Пример #1
0
 /// <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)
 {
 }
Пример #2
0
 /// <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);
        }
Пример #4
0
 /// <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)
 {
 }
Пример #5
0
 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);
 }
Пример #7
0
 public override IEnumerable <string> BeforeUpdateRelationship(HashSet <string> ids, IRelationshipsDictionary <Person> entitiesByRelationship, ResourcePipeline pipeline)
 {
     BeforeImplicitUpdateRelationship(entitiesByRelationship, pipeline);
     return(ids);
 }
Пример #8
0
 /// <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;
                }
            }
        }
Пример #14
0
 /// <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);
 }
Пример #15
0
 public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary <Person> entitiesByRelationship, ResourcePipeline pipeline)
 {
     entitiesByRelationship.GetByRelationship <Passport>().ToList().ForEach(kvp => DisallowLocked(kvp.Value));
 }
Пример #16
0
 /// <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);
 }
Пример #17
0
 /// <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);
 }
Пример #18
0
 /// <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)
 {
 }
Пример #19
0
 /// <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)
 {
 }
Пример #20
0
        //[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));
        }
Пример #21
0
 /// <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);
        }