示例#1
0
        static CodeBlock WriteNode(
            Variable <JsonWriter> jsonWriter,
            TypedExpression <string> baseUri,
            ResourceModel model,
            Expression resource,
            MemberAccess <Func <object, string> > uriGenerator,
            MemberAccess <Func <object, string> > typeGenerator,
            IMetaModelRepository models,
            Variable <HydraJsonFormatterResolver> jsonFormatterResolver,
            NodeProperty[] existingNodeProperties   = null,
            Stack <ResourceModel> recursionDefender = null)
        {
            recursionDefender = recursionDefender ?? new Stack <ResourceModel>();
            var resourceType = model.ResourceType;

            if (recursionDefender.Contains(model))
            {
                throw new InvalidOperationException(
                          $"Detected recursion, already processing {resourceType?.Name}: {string.Join("->", recursionDefender.Select(m => m.ResourceType?.Name).Where(n => n != null))}");
            }

            recursionDefender.Push(model);

            var resourceRegistrationHydraType = HydraTextExtensions.GetHydraTypeName(model);
            var resourceUri = uriGenerator.Invoke(resource);

            List <NodeProperty> nodeProperties =
                new List <NodeProperty>(existingNodeProperties ?? Enumerable.Empty <NodeProperty>());

            nodeProperties.AddRange(GetNodeProperties(
                                        jsonWriter,
                                        baseUri,
                                        model,
                                        resource,
                                        uriGenerator,
                                        typeGenerator,
                                        models,
                                        recursionDefender,
                                        jsonFormatterResolver,
                                        resourceType,
                                        resourceUri,
                                        resourceRegistrationHydraType));


            var  collectionItemTypes = HydraTextExtensions.CollectionItemTypes(resourceType).ToList();
            Type collectionItemType  = null;
            var  isHydraCollection   = collectionItemTypes.Count == 1 &&
                                       models.TryGetResourceModel(collectionItemType = collectionItemTypes.First(), out _);

            IEnumerable <AnyExpression> render()
            {
                if (isHydraCollection)
                {
                    var collectionType = HydraTypes.Collection.MakeGenericType(collectionItemType);
                    var collectionCtor =
                        collectionType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(collectionItemType) });
                    var collection = Expression.Variable(collectionType);

                    yield return(collection);

                    var instantiateCollection = Expression.Assign(collection, Expression.New(collectionCtor, resource));
                    yield return(instantiateCollection);

                    resource = collection;

                    // if we have a generic list of sort, we hydra:Collection instead
                    if (resourceType.IsGenericType) // IEnum<T>, List<T> etc
                    {
                        resourceRegistrationHydraType = "hydra:Collection";
                    }

                    resourceType = collectionType;

                    // Remove existing id and type if already defined
                    nodeProperties.RemoveAll(p => p.Name == "@id" || p.Name == "@type");
                    nodeProperties.AddRange(GetNodeProperties(jsonWriter, baseUri, model, resource, uriGenerator, typeGenerator,
                                                              models,
                                                              recursionDefender,
                                                              jsonFormatterResolver, resourceType, resourceUri, resourceRegistrationHydraType));
                }

                if (nodeProperties.Any())
                {
                    yield return(WriteNodeProperties(jsonWriter, nodeProperties));
                }
            }

            recursionDefender.Pop();
            return(new CodeBlock(render()));
        }
示例#2
0
        static NodeProperty WriteNodeProperty(
            Variable <JsonWriter> jsonWriter,
            TypedExpression <string> baseUri,
            Expression resource,
            MemberAccess <Func <object, string> > uriGenerator,
            MemberAccess <Func <object, string> > typeGenerator,
            IMetaModelRepository models,
            Stack <ResourceModel> recursionDefender,
            PropertyInfo pi,
            Variable <HydraJsonFormatterResolver> jsonFormatterResolver)
        {
            // var propertyValue;
            var propertyValue = Expression.Variable(pi.PropertyType, $"val{pi.DeclaringType.Name}{pi.Name}");

            // propertyValue = resource.Property;
            var propertyValueAssignment = Expression.Assign(propertyValue, Expression.MakeMemberAccess(resource, pi));

            var preamble = new InlineCode(new Expression[] { propertyValue, propertyValueAssignment });

            if (models.TryGetResourceModel(pi.PropertyType, out var propertyResourceModel))
            {
                var jsonPropertyName = HydraTextExtensions.GetJsonPropertyName(pi);
                return(new NodeProperty(jsonPropertyName)
                {
                    Preamble = preamble,
                    Code = new InlineCode(new[]
                    {
                        jsonWriter.WritePropertyName(jsonPropertyName),
                        jsonWriter.WriteBeginObject(),
                        WriteNode(jsonWriter, baseUri, propertyResourceModel, propertyValue,
                                  uriGenerator, typeGenerator, models, jsonFormatterResolver, recursionDefender: recursionDefender),
                        jsonWriter.WriteEndObject()
                    }),
                    Conditional = Expression.NotEqual(propertyValue, Expression.Default(pi.PropertyType))
                });
            }

            var itemTypes = (from i in pi.PropertyType.GetInterfaces()
                             .Concat(pi.PropertyType.IsInterface ? new[] { pi.PropertyType } : Array.Empty <Type>())
                             where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)
                             let itemType = i.GetGenericArguments()[0]
                                            where itemType != typeof(object)
                                            select itemType).ToList();

            // not an iri node itself, but is it a list of nodes?
            var itemResourceRegistrations = (
                from itemType in itemTypes
                let resourceModels = models.ResourceRegistrations.Where(r =>
                                                                        r.ResourceType != null && itemType.IsAssignableFrom(r.ResourceType)).ToList()
                                     where resourceModels.Any()
                                     orderby resourceModels.Count() descending
                                     select
                                     (
                    itemType,
                    (from possible in resourceModels
                     orderby possible.ResourceType.GetInheritanceDistance(itemType)
                     select possible).ToList()
                                     )).ToList <(Type itemType, List <ResourceModel> models)>();

            if (itemResourceRegistrations.Any() == false)
            {
                // not a list of iri or blank nodes
                var propValue = WriteNodePropertyValue(jsonWriter, pi, jsonFormatterResolver, resource);
                propValue.Preamble    = preamble;
                propValue.Conditional = Expression.NotEqual(propertyValue, Expression.Default(pi.PropertyType));
                return(propValue);
            }

            // it's a list of nodes
            return(WriteNodeList(jsonWriter, baseUri, uriGenerator, typeGenerator, models, recursionDefender, pi,
                                 jsonFormatterResolver,
                                 itemResourceRegistrations, propertyValue, preamble));
        }