Fixes #1149 Document EntityRepository to help contributors understand how to use it to add new entities

This commit is contained in:
sureshms 2021-11-28 12:02:52 -08:00
parent 00038449e8
commit 93a644dfcd
22 changed files with 64 additions and 40 deletions

View File

@ -69,7 +69,7 @@ public class BotsRepository extends EntityRepository<Bots>{
} }
@Override @Override
public void addRelationships(Bots entity) throws IOException { } public void storeRelationships(Bots entity) throws IOException { }
public static class BotsEntityInterface implements EntityInterface<Bots> { public static class BotsEntityInterface implements EntityInterface<Bots> {
private final Bots entity; private final Bots entity;

View File

@ -96,7 +96,7 @@ public class ChartRepository extends EntityRepository<Chart> {
} }
@Override @Override
public void addRelationships(Chart chart) throws IOException { public void storeRelationships(Chart chart) throws IOException {
EntityReference service = chart.getService(); EntityReference service = chart.getService();
dao.relationshipDAO().insert(service.getId().toString(), chart.getId().toString(), service.getType(), dao.relationshipDAO().insert(service.getId().toString(), chart.getId().toString(), service.getType(),
Entity.CHART, Relationship.CONTAINS.ordinal()); Entity.CHART, Relationship.CONTAINS.ordinal());

View File

@ -156,7 +156,7 @@ public class DashboardRepository extends EntityRepository<Dashboard> {
} }
@Override @Override
public void addRelationships(Dashboard dashboard) throws IOException { public void storeRelationships(Dashboard dashboard) throws IOException {
setService(dashboard, dashboard.getService()); setService(dashboard, dashboard.getService());
// Add relationship from dashboard to chart // Add relationship from dashboard to chart

View File

@ -101,7 +101,7 @@ public class DashboardServiceRepository extends EntityRepository<DashboardServic
} }
@Override @Override
public void addRelationships(DashboardService entity) throws IOException { public void storeRelationships(DashboardService entity) throws IOException {
} }
@Override @Override

View File

@ -101,7 +101,7 @@ public class DatabaseRepository extends EntityRepository<Database> {
} }
@Override @Override
public void addRelationships(Database database) throws IOException { public void storeRelationships(Database database) throws IOException {
dao.relationshipDAO().insert(database.getService().getId().toString(), database.getId().toString(), dao.relationshipDAO().insert(database.getService().getId().toString(), database.getId().toString(),
database.getService().getType(), Entity.DATABASE, Relationship.CONTAINS.ordinal()); database.getService().getType(), Entity.DATABASE, Relationship.CONTAINS.ordinal());
EntityUtil.setOwner(dao.relationshipDAO(), database.getId(), Entity.DATABASE, database.getOwner()); EntityUtil.setOwner(dao.relationshipDAO(), database.getId(), Entity.DATABASE, database.getOwner());

View File

@ -91,7 +91,7 @@ public class DatabaseServiceRepository extends EntityRepository<DatabaseService>
} }
@Override @Override
public void addRelationships(DatabaseService entity) throws IOException { public void storeRelationships(DatabaseService entity) throws IOException {
} }
@Override @Override

View File

@ -171,7 +171,7 @@ public class DbtModelRepository extends EntityRepository<DbtModel> {
} }
@Override @Override
public void addRelationships(DbtModel dbtModel) throws IOException { public void storeRelationships(DbtModel dbtModel) throws IOException {
// Add relationship from database to model // Add relationship from database to model
String databaseId = dbtModel.getDatabase().getId().toString(); String databaseId = dbtModel.getDatabase().getId().toString();
dao.relationshipDAO().insert(databaseId, dbtModel.getId().toString(), Entity.DATABASE, Entity.DBTMODEL, dao.relationshipDAO().insert(databaseId, dbtModel.getId().toString(), Entity.DATABASE, Entity.DBTMODEL,

View File

@ -24,6 +24,7 @@ import org.openmetadata.catalog.entity.teams.User;
import org.openmetadata.catalog.exception.CatalogExceptionMessage; import org.openmetadata.catalog.exception.CatalogExceptionMessage;
import org.openmetadata.catalog.exception.EntityNotFoundException; import org.openmetadata.catalog.exception.EntityNotFoundException;
import org.openmetadata.catalog.jdbi3.CollectionDAO.EntityVersionPair; import org.openmetadata.catalog.jdbi3.CollectionDAO.EntityVersionPair;
import org.openmetadata.catalog.jdbi3.TableRepository.TableUpdater;
import org.openmetadata.catalog.type.ChangeDescription; import org.openmetadata.catalog.type.ChangeDescription;
import org.openmetadata.catalog.type.ChangeEvent; import org.openmetadata.catalog.type.ChangeEvent;
import org.openmetadata.catalog.type.EntityHistory; import org.openmetadata.catalog.type.EntityHistory;
@ -61,28 +62,39 @@ import java.util.UUID;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
/** /**
* This class is used by Entity Resources to perform READ and WRITE operations to the backend database to Create, * This is the base class used by Entity Resources to perform READ and WRITE operations to the backend database to
* Retrieve, Update, and Delete entities. * Create, * Retrieve, Update, and Delete entities.
* *
* An entity has two types of fields - `attributes` and `relationships`. The `attributes` are the core properties of * An entity has two types of fields - `attributes` and `relationships`.
* the entity, example - entity id, name, fullyQualifiedName, columns for a table, etc. The `relationships` are * <ul>
* an associated between two entities, example - table belongs to a database, table has a tag, user owns a table, etc. * <li>The `attributes` are the core properties of the entity, example - entity id, name, fullyQualifiedName, columns
* All relationships are captured using {@code EntityReference}. * for a table, etc.</li>
* <li>The `relationships` are an associated between two entities, example - table belongs to a database,
* table has a tag, user owns a table, etc. All relationships are captured using {@code EntityReference}. </li>
* </ul>
* *
* Entities are stored as JSON documents in the database. Each entity is stored in a separate table and is accessed * Entities are stored as JSON documents in the database. Each entity is stored in a separate table and is accessed
* through a <i>Data Access Object</i> or <i>DAO</i> that corresponds to each of the entity. All DAO objects for an * through a <i>Data Access Object</i> or <i>DAO</i> that corresponds to each of the entity. For example,
* entity are available in {@code daoCollection}. * <i>table_entity</i> is the database table used to store JSON docs corresponding to <i>table</i> entity and
* {@link org.openmetadata.catalog.jdbi3.CollectionDAO.TableDAO} is used as the DAO object to access the table_entity
* table. All DAO objects for an entity are available in {@code daoCollection}.
* *
* <br><br>
* Relationships between entity is stored in a separate table that captures the edge - fromEntity, toEntity, and * Relationships between entity is stored in a separate table that captures the edge - fromEntity, toEntity, and
* the relationship name. * the relationship name <i>entity_relationship</i> table and are supported by
* {@link org.openmetadata.catalog.jdbi3.CollectionDAO.EntityRelationshipDAO} DAO object.
* *
* JSON document of an entity stores only required attributes of an entity. Some attributes such as <i>href</i> * JSON document of an entity stores only <i>required</i> attributes of an entity. Some attributes such as
* are not stored and are created on the fly. * <i>href</i> are not stored and are created on the fly.
*
* <br><br>
* *
* Json document of an entity does not store relationships. As an example, JSON document for <i>table</i> entity * Json document of an entity does not store relationships. As an example, JSON document for <i>table</i> entity
* does not store the relationship <i>database</i> which is of type <i>EntityReference</i>. This is always retrieved * does not store the relationship <i>database</i> which is of type <i>EntityReference</i>. This is always retrieved
* from the the relationship edges when required to ensure, the data stored is consistent and information in * from the the relationship table when required to ensure, the data stored is efficiently and consistently, and
* responses is not stale. * relationship information does not become stale.
* </p>
*
*/ */
public abstract class EntityRepository<T> { public abstract class EntityRepository<T> {
public static final Logger LOG = LoggerFactory.getLogger(EntityRepository.class); public static final Logger LOG = LoggerFactory.getLogger(EntityRepository.class);
@ -150,6 +162,8 @@ public abstract class EntityRepository<T> {
* entity and does not include attributes such as <i>href</i>. The relationship fields of an entity is never stored * entity and does not include attributes such as <i>href</i>. The relationship fields of an entity is never stored
* in the JSON document. It is always reconstructed based on relationship edges from the backend database. * in the JSON document. It is always reconstructed based on relationship edges from the backend database.
* *
* <br><br>
*
* As an example, when <i>table</i> entity is stored, the attributes such as <i>href</i> and the relationships such * As an example, when <i>table</i> entity is stored, the attributes such as <i>href</i> and the relationships such
* as <i>owner</i>, <i>database</i>, and <i>tags</i> are set to null. These attributes are restored back after the * as <i>owner</i>, <i>database</i>, and <i>tags</i> are set to null. These attributes are restored back after the
* JSON document is stored to be sent as response. * JSON document is stored to be sent as response.
@ -162,14 +176,14 @@ public abstract class EntityRepository<T> {
* This method is called to store all the relationships of an entity. It is expected that all relationships are * This method is called to store all the relationships of an entity. It is expected that all relationships are
* already validated and completely setup before this method is called and no validation of relationships is required. * already validated and completely setup before this method is called and no validation of relationships is required.
* *
* @see TableRepository#addRelationships(Table) for an example implementation * @see TableRepository#storeRelationships(Table) for an example implementation
*/ */
public abstract void addRelationships(T entity) throws IOException; public abstract void storeRelationships(T entity) throws IOException;
/** /**
* PATCH operations can't overwrite certain fields, such as entity ID, fullyQualifiedNames etc. Instead of throwing * PATCH operations can't overwrite certain fields, such as entity ID, fullyQualifiedNames etc. Instead of throwing
* an error, we take lenient approach of ignoring the user error and restore those attributes based on what is * an error, we take lenient approach of ignoring the user error and restore those attributes based on what is
* already stored as original entity. * already stored in the original entity.
*/ */
public abstract void restorePatchAttributes(T original, T updated) throws IOException, ParseException; public abstract void restorePatchAttributes(T original, T updated) throws IOException, ParseException;
@ -376,7 +390,7 @@ public abstract class EntityRepository<T> {
private T createNewEntity(T entity) throws IOException { private T createNewEntity(T entity) throws IOException {
storeEntity(entity, false); storeEntity(entity, false);
addRelationships(entity); storeRelationships(entity);
return entity; return entity;
} }
@ -393,8 +407,15 @@ public abstract class EntityRepository<T> {
} }
/** /**
* Class that performs PUT and PATCH update operation. Override {@code entitySpecificUpdate()} to add * Class that performs PUT and PATCH update operation. It takes an <i>updated</i> entity and <i>original</i> entity.
* additional entity specific fields to be updated. * Performs comparison between then and updates the stored entity and also updates all the relationships. This class
* also tracks the changes between original and updated to version the entity and produce change events.
*
* <br><br>
*
* Common entity attributes such as description, displayName, owner, tags are handled by this class.
* Override {@code entitySpecificUpdate()} to add additional entity specific fields to be updated.
* @see TableUpdater#entitySpecificUpdate() for example.
*/ */
public class EntityUpdater { public class EntityUpdater {
protected final EntityInterface<T> original; protected final EntityInterface<T> original;
@ -409,6 +430,9 @@ public abstract class EntityRepository<T> {
this.patchOperation = patchOperation; this.patchOperation = patchOperation;
} }
/**
* Compare original and updated entities and perform updates. Update the entity version and track changes.
*/
public final void update() throws IOException, ParseException { public final void update() throws IOException, ParseException {
updated.setId(original.getId()); updated.setId(original.getId());
updateDescription(); updateDescription();

View File

@ -129,7 +129,7 @@ public class IngestionRepository extends EntityRepository<Ingestion> {
} }
@Override @Override
public void addRelationships(Ingestion ingestion) throws IOException { public void storeRelationships(Ingestion ingestion) throws IOException {
EntityReference service = ingestion.getService(); EntityReference service = ingestion.getService();
dao.relationshipDAO().insert(service.getId().toString(), ingestion.getId().toString(), service.getType(), dao.relationshipDAO().insert(service.getId().toString(), ingestion.getId().toString(), service.getType(),
Entity.INGESTION, Relationship.CONTAINS.ordinal()); Entity.INGESTION, Relationship.CONTAINS.ordinal());

View File

@ -177,7 +177,7 @@ public class LocationRepository extends EntityRepository<Location> {
} }
@Override @Override
public void addRelationships(Location location) throws IOException { public void storeRelationships(Location location) throws IOException {
// Add location owner relationship // Add location owner relationship
EntityUtil.setOwner(dao.relationshipDAO(), location.getId(), Entity.LOCATION, location.getOwner()); EntityUtil.setOwner(dao.relationshipDAO(), location.getId(), Entity.LOCATION, location.getOwner());
dao.relationshipDAO().insert(location.getService().getId().toString(), location.getId().toString(), dao.relationshipDAO().insert(location.getService().getId().toString(), location.getId().toString(),

View File

@ -89,7 +89,7 @@ public class MessagingServiceRepository extends EntityRepository<MessagingServic
} }
@Override @Override
public void addRelationships(MessagingService entity) throws IOException { } public void storeRelationships(MessagingService entity) throws IOException { }
@Override @Override
public EntityUpdater getUpdater(MessagingService original, MessagingService updated, boolean patchOperation) throws IOException { public EntityUpdater getUpdater(MessagingService original, MessagingService updated, boolean patchOperation) throws IOException {

View File

@ -96,7 +96,7 @@ public class MetricsRepository extends EntityRepository<Metrics> {
} }
@Override @Override
public void addRelationships(Metrics metrics) throws IOException { public void storeRelationships(Metrics metrics) throws IOException {
dao.relationshipDAO().insert(metrics.getService().getId().toString(), metrics.getId().toString(), dao.relationshipDAO().insert(metrics.getService().getId().toString(), metrics.getId().toString(),
metrics.getService().getType(), Entity.METRICS, Relationship.CONTAINS.ordinal()); metrics.getService().getType(), Entity.METRICS, Relationship.CONTAINS.ordinal());
setOwner(metrics, metrics.getOwner()); setOwner(metrics, metrics.getOwner());

View File

@ -160,7 +160,7 @@ public class MlModelRepository extends EntityRepository<MlModel> {
} }
@Override @Override
public void addRelationships(MlModel mlModel) throws IOException { public void storeRelationships(MlModel mlModel) throws IOException {
EntityUtil.setOwner(dao.relationshipDAO(), mlModel.getId(), Entity.MLMODEL, mlModel.getOwner()); EntityUtil.setOwner(dao.relationshipDAO(), mlModel.getId(), Entity.MLMODEL, mlModel.getOwner());

View File

@ -143,7 +143,7 @@ public class PipelineRepository extends EntityRepository<Pipeline> {
} }
@Override @Override
public void addRelationships(Pipeline pipeline) throws IOException { public void storeRelationships(Pipeline pipeline) throws IOException {
EntityReference service = pipeline.getService(); EntityReference service = pipeline.getService();
dao.relationshipDAO().insert(service.getId().toString(), pipeline.getId().toString(), service.getType(), dao.relationshipDAO().insert(service.getId().toString(), pipeline.getId().toString(), service.getType(),
Entity.PIPELINE, Relationship.CONTAINS.ordinal()); Entity.PIPELINE, Relationship.CONTAINS.ordinal());

View File

@ -89,7 +89,7 @@ public class PipelineServiceRepository extends EntityRepository<PipelineService>
} }
@Override @Override
public void addRelationships(PipelineService entity) throws IOException { public void storeRelationships(PipelineService entity) throws IOException {
} }

View File

@ -122,7 +122,7 @@ public class PolicyRepository extends EntityRepository<Policy> {
} }
@Override @Override
public void addRelationships(Policy policy) throws IOException { public void storeRelationships(Policy policy) throws IOException {
// Add policy owner relationship // Add policy owner relationship
setOwner(policy, policy.getOwner()); setOwner(policy, policy.getOwner());
} }

View File

@ -76,7 +76,7 @@ public class ReportRepository extends EntityRepository<Report> {
} }
@Override @Override
public void addRelationships(Report entity) throws IOException { public void storeRelationships(Report entity) throws IOException {
// TODO // TODO
} }

View File

@ -84,7 +84,7 @@ public class StorageServiceRepository extends EntityRepository<StorageService> {
} }
@Override @Override
public void addRelationships(StorageService entity) throws IOException { public void storeRelationships(StorageService entity) throws IOException {
} }
public static class StorageServiceEntityInterface implements EntityInterface<StorageService> { public static class StorageServiceEntityInterface implements EntityInterface<StorageService> {

View File

@ -304,7 +304,7 @@ public class TableRepository extends EntityRepository<Table> {
} }
@Override @Override
public void addRelationships(Table table) throws IOException { public void storeRelationships(Table table) throws IOException {
// Add relationship from database to table // Add relationship from database to table
String databaseId = table.getDatabase().getId().toString(); String databaseId = table.getDatabase().getId().toString();
dao.relationshipDAO().insert(databaseId, table.getId().toString(), Entity.DATABASE, Entity.TABLE, dao.relationshipDAO().insert(databaseId, table.getId().toString(), Entity.DATABASE, Entity.TABLE,

View File

@ -130,7 +130,7 @@ public class TeamRepository extends EntityRepository<Team> {
} }
@Override @Override
public void addRelationships(Team team) throws IOException { public void storeRelationships(Team team) throws IOException {
for (EntityReference user : Optional.ofNullable(team.getUsers()).orElse(Collections.emptyList())) { for (EntityReference user : Optional.ofNullable(team.getUsers()).orElse(Collections.emptyList())) {
dao.relationshipDAO().insert(team.getId().toString(), user.getId().toString(), "team", "user", dao.relationshipDAO().insert(team.getId().toString(), user.getId().toString(), "team", "user",
Relationship.CONTAINS.ordinal()); Relationship.CONTAINS.ordinal());

View File

@ -101,7 +101,7 @@ public class TopicRepository extends EntityRepository<Topic> {
} }
@Override @Override
public void addRelationships(Topic topic) throws IOException { public void storeRelationships(Topic topic) throws IOException {
setService(topic, topic.getService()); setService(topic, topic.getService());
setOwner(topic, topic.getOwner()); setOwner(topic, topic.getOwner());
applyTags(topic); applyTags(topic);

View File

@ -90,7 +90,7 @@ public class UserRepository extends EntityRepository<User> {
} }
@Override @Override
public void addRelationships(User user) throws IOException { public void storeRelationships(User user) throws IOException {
assignTeams(user, user.getTeams()); assignTeams(user, user.getTeams());
} }