/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual void AfterUpdateRelationship(IRelationshipsDictionary <TResource> resourcesByRelationship, ResourcePipeline pipeline) { }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual void BeforeRead(ResourcePipeline pipeline, bool isIncluded = false, string stringId = null) { }
/// <inheritdoc /> public IEnumerable <TResource> OnReturn <TResource>(IEnumerable <TResource> resources, ResourcePipeline pipeline) where TResource : class, IIdentifiable { GetHookResult <TResource> result = GetHook(ResourceHook.OnReturn, resources); if (result.Succeeded) { IEnumerable <TResource> updated = result.Container.OnReturn((HashSet <TResource>)result.Node.UniqueResources, pipeline); ValidateHookResponse(updated); result.Node.UpdateUnique(updated); result.Node.Reassign(resources); } TraverseNodesInLayer(_nodeNavigator.CreateNextLayer(result.Node), ResourceHook.OnReturn, (nextContainer, nextNode) => { IEnumerable filteredUniqueSet = CallHook(nextContainer, ResourceHook.OnReturn, ArrayFactory.Create <object>(nextNode.UniqueResources, pipeline)); nextNode.UpdateUnique(filteredUniqueSet); nextNode.Reassign(); }); return(resources); }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual void AfterDelete(HashSet <TResource> resources, ResourcePipeline pipeline, bool succeeded) { }
public override IEnumerable <string> BeforeUpdateRelationship(HashSet <string> ids, IAffectedRelationships <Person> resourcesByRelationship, ResourcePipeline pipeline) { BeforeImplicitUpdateRelationship(resourcesByRelationship, pipeline); return(ids); }
public override IEnumerable <T> BeforeDelete(IResourceHashSet <T> resources, ResourcePipeline pipeline) { return(resources); }
public override IEnumerable <string> BeforeUpdateRelationship(HashSet <string> ids, IRelationshipsDictionary <Person> entitiesByRelationship, ResourcePipeline pipeline) { BeforeImplicitUpdateRelationship(entitiesByRelationship, pipeline); return(ids); }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual IEnumerable <string> BeforeUpdateRelationship(HashSet <string> ids, IRelationshipsDictionary <TResource> resourcesByRelationship, ResourcePipeline pipeline) { return(ids); }
/// <inheritdoc /> public IEnumerable <TResource> BeforeUpdate <TResource>(IEnumerable <TResource> resources, ResourcePipeline pipeline) where TResource : class, IIdentifiable { GetHookResult <TResource> result = GetHook(ResourceHook.BeforeUpdate, resources); if (result.Succeeded) { RelationshipAttribute[] relationships = result.Node.RelationshipsToNextLayer.Select(proxy => proxy.Attribute).ToArray(); IEnumerable dbValues = LoadDbValues(typeof(TResource), (IEnumerable <TResource>)result.Node.UniqueResources, ResourceHook.BeforeUpdate, relationships); var diff = new DiffableResourceHashSet <TResource>(result.Node.UniqueResources, dbValues, result.Node.LeftsToNextLayer(), _targetedFields); IEnumerable <TResource> updated = result.Container.BeforeUpdate(diff, pipeline); result.Node.UpdateUnique(updated); result.Node.Reassign(resources); } FireNestedBeforeUpdateHooks(pipeline, _nodeNavigator.CreateNextLayer(result.Node)); return(resources); }
/// <inheritdoc /> public IEnumerable <TResource> BeforeCreate <TResource>(IEnumerable <TResource> resources, ResourcePipeline pipeline) where TResource : class, IIdentifiable { GetHookResult <TResource> result = GetHook(ResourceHook.BeforeCreate, resources); if (result.Succeeded) { var affected = new ResourceHashSet <TResource>((HashSet <TResource>)result.Node.UniqueResources, result.Node.LeftsToNextLayer()); IEnumerable <TResource> updated = result.Container.BeforeCreate(affected, pipeline); result.Node.UpdateUnique(updated); result.Node.Reassign(resources); } FireNestedBeforeUpdateHooks(pipeline, _nodeNavigator.CreateNextLayer(result.Node)); return(resources); }
/// <summary> /// Fires the AfterUpdateRelationship hook /// </summary> private void FireAfterUpdateRelationship(IResourceHookContainer container, IResourceNode node, ResourcePipeline pipeline) { IDictionary <RelationshipAttribute, IEnumerable> currentResourcesGrouped = node.RelationshipsFromPreviousLayer.GetRightResources(); // the relationships attributes in currentResourcesGrouped will be pointing from a // resource in the previous layer to a resource in the current (nested) layer. // For the nested hook we need to replace these attributes with their inverse. // See the FireNestedBeforeUpdateHooks method for a more detailed example. IRelationshipsDictionary resourcesByRelationship = CreateRelationshipHelper(node.ResourceType, ReplaceKeysWithInverseRelationships(currentResourcesGrouped)); CallHook(container, ResourceHook.AfterUpdateRelationship, ArrayFactory.Create <object>(resourcesByRelationship, pipeline)); }
/// <summary> /// Fires the nested before hooks for resources in the current <paramref name="layer" /> /// </summary> /// <remarks> /// For example: consider the case when the owner of article1 (one-to-one) is being updated from owner_old to owner_new, where owner_new is currently /// already related to article2. Then, the following nested hooks need to be fired in the following order. First the BeforeUpdateRelationship should be /// for owner1, then the BeforeImplicitUpdateRelationship hook should be fired for owner2, and lastly the BeforeImplicitUpdateRelationship for article2. /// </remarks> private void FireNestedBeforeUpdateHooks(ResourcePipeline pipeline, IEnumerable <IResourceNode> layer) { foreach (IResourceNode node in layer) { IResourceHookContainer nestedHookContainer = _containerProvider.GetResourceHookContainer(node.ResourceType, ResourceHook.BeforeUpdateRelationship); IEnumerable uniqueResources = node.UniqueResources; RightType resourceType = node.ResourceType; IDictionary <RelationshipAttribute, IEnumerable> currentResourcesGrouped; IDictionary <RelationshipAttribute, IEnumerable> currentResourcesGroupedInverse; // fire the BeforeUpdateRelationship hook for owner_new if (nestedHookContainer != null) { if (uniqueResources.Cast <IIdentifiable>().Any()) { RelationshipAttribute[] relationships = node.RelationshipsToNextLayer.Select(proxy => proxy.Attribute).ToArray(); IEnumerable dbValues = LoadDbValues(resourceType, uniqueResources, ResourceHook.BeforeUpdateRelationship, relationships); // these are the resources of the current node grouped by // RelationshipAttributes that occurred in the previous layer // so it looks like { HasOneAttribute:owner => owner_new }. // Note that in the BeforeUpdateRelationship hook of Person, // we want want inverse relationship attribute: // we now have the one pointing from article -> person, ] // but we require the the one that points from person -> article currentResourcesGrouped = node.RelationshipsFromPreviousLayer.GetRightResources(); currentResourcesGroupedInverse = ReplaceKeysWithInverseRelationships(currentResourcesGrouped); IRelationshipsDictionary resourcesByRelationship = CreateRelationshipHelper(resourceType, currentResourcesGroupedInverse, dbValues); IEnumerable <string> allowedIds = CallHook(nestedHookContainer, ResourceHook.BeforeUpdateRelationship, ArrayFactory.Create <object>(GetIds(uniqueResources), resourcesByRelationship, pipeline)).Cast <string>(); ISet <IIdentifiable> updated = GetAllowedResources(uniqueResources, allowedIds); node.UpdateUnique(updated); node.Reassign(); } } // Fire the BeforeImplicitUpdateRelationship hook for owner_old. // Note: if the pipeline is Post it means we just created article1, // which means we are sure that it isn't related to any other resources yet. if (pipeline != ResourcePipeline.Post) { // To fire a hook for owner_old, we need to first get a reference to it. // For this, we need to query the database for the HasOneAttribute:owner // relationship of article1, which is referred to as the // left side of the HasOneAttribute:owner relationship. IDictionary <RelationshipAttribute, IEnumerable> leftResources = node.RelationshipsFromPreviousLayer.GetLeftResources(); if (leftResources.Any()) { // owner_old is loaded, which is an "implicitly affected resource" FireForAffectedImplicits(resourceType, leftResources, pipeline, uniqueResources); } } // Fire the BeforeImplicitUpdateRelationship hook for article2 // For this, we need to query the database for the current owner // relationship value of owner_new. currentResourcesGrouped = node.RelationshipsFromPreviousLayer.GetRightResources(); if (currentResourcesGrouped.Any()) { // rightResources is grouped by relationships from previous // layer, ie { HasOneAttribute:owner => owner_new }. But // to load article2 onto owner_new, we need to have the // RelationshipAttribute from owner to article, which is the // inverse of HasOneAttribute:owner currentResourcesGroupedInverse = ReplaceKeysWithInverseRelationships(currentResourcesGrouped); // Note that currently in the JsonApiDotNetCore implementation of hooks, // the root layer is ALWAYS homogenous, so we safely assume // that for every relationship to the previous layer, the // left type is the same. LeftType leftType = currentResourcesGrouped.First().Key.LeftType; FireForAffectedImplicits(leftType, currentResourcesGroupedInverse, pipeline); } } }
/// <summary> /// Recursively goes through the included relationships from JsonApiContext, translates them to the corresponding hook containers and fires the /// BeforeRead hook (if implemented) /// </summary> private void RecursiveBeforeRead(List <RelationshipAttribute> relationshipChain, ResourcePipeline pipeline, List <LeftType> calledContainers) { while (true) { RelationshipAttribute relationship = relationshipChain.First(); if (!calledContainers.Contains(relationship.RightType)) { calledContainers.Add(relationship.RightType); IResourceHookContainer container = _containerProvider.GetResourceHookContainer(relationship.RightType, ResourceHook.BeforeRead); if (container != null) { CallHook(container, ResourceHook.BeforeRead, new object[] { pipeline, true, null }); } } relationshipChain.RemoveAt(0); if (!relationshipChain.Any()) { break; } } }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual IEnumerable <TResource> BeforeUpdate(IDiffableResourceHashSet <TResource> resources, ResourcePipeline pipeline) { return(resources); }
public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary <Person> entitiesByRelationship, ResourcePipeline pipeline) { entitiesByRelationship.GetByRelationship <Passport>().ToList().ForEach(kvp => DisallowLocked(kvp.Value)); }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual IEnumerable <TResource> BeforeDelete(IResourceHashSet <TResource> resources, ResourcePipeline pipeline) { return(resources); }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual IEnumerable <TResource> OnReturn(HashSet <TResource> resources, ResourcePipeline pipeline) { return(resources); }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual void BeforeImplicitUpdateRelationship(IRelationshipsDictionary <TResource> resourcesByRelationship, ResourcePipeline pipeline) { }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual void AfterRead(HashSet <TResource> resources, ResourcePipeline pipeline, bool isIncluded = false) { }
//[LoadDatabaseValues(true)] //public override IEnumerable<Person> BeforeUpdate(IResourceDiff<Person> entityDiff, ResourcePipeline pipeline) //{ // return entityDiff.Entities; //} public override void BeforeImplicitUpdateRelationship(IAffectedRelationships <Person> resourcesByRelationship, ResourcePipeline pipeline) { resourcesByRelationship.GetByRelationship <Passport>().ToList().ForEach(kvp => DisallowLocked(kvp.Value)); }
/// <inheritdoc /> /// <remarks>This method is part of Resource Hooks, which is an experimental feature and subject to change in future versions.</remarks> public virtual void AfterUpdate(HashSet <TResource> resources, ResourcePipeline pipeline) { }
public override void AfterDelete(HashSet <T> resources, ResourcePipeline pipeline, bool succeeded) { }
/// <inheritdoc /> public IEnumerable <TResource> BeforeDelete <TResource>(IEnumerable <TResource> resources, ResourcePipeline pipeline) where TResource : class, IIdentifiable { GetHookResult <TResource> result = GetHook(ResourceHook.BeforeDelete, resources); if (result.Succeeded) { RelationshipAttribute[] relationships = result.Node.RelationshipsToNextLayer.Select(proxy => proxy.Attribute).ToArray(); IEnumerable targetResources = LoadDbValues(typeof(TResource), (IEnumerable <TResource>)result.Node.UniqueResources, ResourceHook.BeforeDelete, relationships) ?? result.Node.UniqueResources; var affected = new ResourceHashSet <TResource>(targetResources, result.Node.LeftsToNextLayer()); IEnumerable <TResource> updated = result.Container.BeforeDelete(affected, pipeline); result.Node.UpdateUnique(updated); result.Node.Reassign(resources); } // If we're deleting an article, we're implicitly affected any owners related to it. // Here we're loading all relations onto the to-be-deleted article // if for that relation the BeforeImplicitUpdateHook is implemented, // and this hook is then executed foreach (KeyValuePair <Type, Dictionary <RelationshipAttribute, IEnumerable> > entry in result.Node.LeftsToNextLayerByRelationships()) { Type rightType = entry.Key; Dictionary <RelationshipAttribute, IEnumerable> implicitTargets = entry.Value; FireForAffectedImplicits(rightType, implicitTargets, pipeline); } return(resources); }