/// <summary> /// Performs the add or update. /// </summary> /// <param name="entity">The entity.</param> /// <param name="transaction"></param> public void PerformAddOrUpdate(AbstractEntity entity, ExamineTransaction transaction) { Mandate.ParameterNotNull(entity, "entity"); //use the mappers to map this entity (whatever it might be) to an IndexCategoryOperation var indexOperation = _frameworkContext.TypeMappers.MapToIntent <NestedHiveIndexOperation>(entity); if (TypeFinder.IsTypeAssignableFrom <TypedEntity>(entity.GetType())) { //since we're updating the schema when its an entity, need to ensure associations are removed RemoveSchemaAssociations(((TypedEntity)entity).EntitySchema, ExamineManager, transaction); } if (TypeFinder.IsTypeAssignableFrom <EntitySchema>(entity.GetType())) { //need to ensure schema associations are removed RemoveSchemaAssociations((EntitySchema)entity, ExamineManager, transaction); } transaction.EnqueueIndexOperation(indexOperation); //we need to recursively add all operations and sub operations to the queue foreach (var operation in indexOperation.SubIndexOperations.SelectRecursive(x => x.SubIndexOperations)) { transaction.EnqueueIndexOperation(operation); } }
/// <summary> /// Adds a revision /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="revision"></param> /// <param name="transaction"></param> public void PerformAddRevision <TEntity>(Revision <TEntity> revision, ExamineTransaction transaction) where TEntity : class, IVersionableEntity { Mandate.ParameterNotNull(revision, "revision"); var e = _frameworkContext.TypeMappers.MapToIntent <NestedHiveIndexOperation>(revision); transaction.EnqueueIndexOperation(e); //we need to recursively add all operations and sub operations to the queue foreach (var r in e.SubIndexOperations.SelectRecursive(x => x.SubIndexOperations)) { transaction.EnqueueIndexOperation(r); } }
/// <summary> /// Method to add delete queue items for each schema association since we're not tracking /// revisions with schemas, we need to first remove the associations like groups/attribute defs and then re-add them /// with the up-to-date info. /// </summary> /// <param name="schema"></param> /// <param name="manager"></param> /// <param name="transaction"></param> internal static void RemoveSchemaAssociations(EntitySchema schema, ExamineManager manager, ExamineTransaction transaction) { //find all associations previously added to the transaction queue transaction.RemoveSchemaAssociations(schema); //if there's no id already assigned to the schema, then we can't look it up if (schema.Id.IsNullValueOrEmpty()) { return; } //lookup all associated: AttributeGroup, AttributeDefinition that already exist in the index var toRemove = manager.Search( manager.CreateSearchCriteria() .Must().EntityType <AttributeGroup>() .Must().HiveId(schema.Id, FixedIndexedFields.SchemaId).Compile()) .Concat(manager.Search(manager.CreateSearchCriteria() .Must().EntityType <AttributeDefinition>() .Must().HiveId(schema.Id, FixedIndexedFields.SchemaId).Compile())); foreach (var r in toRemove) { //need to copy to closure var r1 = r; transaction.EnqueueIndexOperation(new LinearHiveIndexOperation { Id = new Lazy <string>(() => r1.Id), OperationType = IndexOperationType.Delete }); } }
/// <summary> /// Adds the relation. /// </summary> /// <param name="item">The item.</param> /// <param name="transaction"></param> public void PerformAddRelation(IReadonlyRelation <IRelatableEntity, IRelatableEntity> item, ExamineTransaction transaction) { Mandate.ParameterNotNull(item, "item"); var r = _frameworkContext.TypeMappers.MapToIntent <NestedHiveIndexOperation>(item); transaction.EnqueueIndexOperation(r); }
/// <summary> /// Removes the relation. /// </summary> /// <param name="item">The item.</param> /// <param name="transaction"></param> public void PerformRemoveRelation(IRelationById item, ExamineTransaction transaction) { Mandate.ParameterNotNull(item, "item"); var delete = new LinearHiveIndexOperation() { OperationType = IndexOperationType.Delete, Id = new Lazy <string>(item.GetCompositeId) }; transaction.EnqueueIndexOperation(delete); }
/// <summary> /// Performs the delete. /// </summary> /// <param name="id">The id.</param> /// <param name="transaction"></param> /// <remarks> /// This will lookup all all related entities and remove them from the index /// </remarks> public void PerformDelete(string id, ExamineTransaction transaction) { Mandate.ParameterNotNullOrEmpty(id, "id"); //NOTE: The below deletion process relies on having unique GUID ids across the board, // if you want to support int Ids, then we'll need to lookup the item type first // and delete different things based on that, i chose not to do that because // if for some reason the item with the Id that we're deleting isn't there then // any related instances will never be deleted whereas doing the below will delete all // related entities regardless. Action <IEnumerable <SearchResult> > addItemsToDeleteQueue = x => { foreach (var r in x) { var r1 = r; transaction.EnqueueIndexOperation(new LinearHiveIndexOperation { OperationType = IndexOperationType.Delete, Id = new Lazy <string>(() => r1.Id) }); } }; //First, check if there's relations for this id and remove any relations found var relations = ExamineManager.Search( ExamineManager.CreateSearchCriteria() .Should() .Id(id, FixedRelationIndexFields.SourceId) .Should() .Id(id, FixedRelationIndexFields.DestinationId).Compile()); addItemsToDeleteQueue(relations); //next, check if there's any items (TypedEntity, AttributeDefinition, AttributeGroup) assigned to a schema by this id, // this will also delete all revisions of TypedEntity too var entities = ExamineManager.Search( ExamineManager.CreateSearchCriteria() .Should() .Id(id, FixedIndexedFields.SchemaId) .Should() .Id(id, FixedIndexedFields.EntityId) .Compile()); addItemsToDeleteQueue(entities); //now, check if the item being deleted is an attribute type, if it is we need to remove all AttributeDefinitions associated // with it and then all TypedAttribute fields belonging to the TypedEntity that reference these AttributeDefinitions var attributeDefs = ExamineManager.Search( ExamineManager.CreateSearchCriteria() .Must() .Id(id, FixedIndexedFields.AttributeTypeId) .Must() .EntityType <AttributeDefinition>() .Compile()); addItemsToDeleteQueue(attributeDefs); //now that we have the attribute defintions related to the typed attribute being deleted, we need to actually create new revisions // for any entity that had a schemas with these definitions on them. var schemaIds = attributeDefs.Select(x => x.Fields[FixedIndexedFields.SchemaId]).Distinct(); foreach (var schemaId in schemaIds) { var criteria = ExamineManager.CreateSearchCriteria() .Must().EntityType <TypedEntity>() .Must().Id(schemaId, FixedIndexedFields.SchemaId) //need to lookup latest because when we're supporting revisions, we will have more than one version of a TypedEntity .Must().Range(FixedRevisionIndexFields.IsLatest, 1, 1); var latest = FilterLatestTypedEntities( ExamineManager.Search(criteria.Compile())); //now that we have the latest TypedEntity for any Schema that had an AttributeDefinition on it that we are deleting // because we are deleting it's TypedAttribute, we need to make a new revision of //NOTE: If for some reason Revisions are disabled, this wont work foreach (var l in latest) { //now that we have an entity, we'll loop through the attribute defs were removing an ensure it's fields are removed foreach (var d in attributeDefs) { //remove all attributes starting with the prefix and attribute def alias var d1 = d; l.Fields.RemoveAll(x => x.Key.StartsWith(FixedAttributeIndexFields.AttributePrefix + d1.Fields[FixedIndexedFields.Alias])); //conver the fields to be used in an index operation var opFields = l.Fields.ToLazyDictionary(x => new ItemField(x)); //update some manual fields like the dates and revision ids StoreDateTimeOffset(FixedIndexedFields.UtcModified, opFields, DateTimeOffset.UtcNow); var revId = Guid.NewGuid().ToString("N"); opFields.AddOrUpdate(FixedRevisionIndexFields.RevisionId, new Lazy <ItemField>(() => new ItemField(revId)), (key, o) => new Lazy <ItemField>(() => new ItemField(revId))); //need to generate a new id (which is composite) var l1 = l; var op = new LinearHiveIndexOperation { OperationType = IndexOperationType.Add, Id = new Lazy <string>(() => l1.Fields[FixedIndexedFields.EntityId] + "," + revId), Fields = opFields }; //create the new revision without the fields transaction.EnqueueIndexOperation(op); } } } //finally, lookup the item itself and remove it var item = ExamineManager.Search(ExamineManager.CreateSearchCriteria().Must().Id(id).Compile()); addItemsToDeleteQueue(item); }