private Lazy <IRelationMetadata> CreateRecursor(RelationMetadata metadata) { if (metadata.HasFlag(RelationMetadataFlags.Item)) { IRelationMetadata recursiveParent = this.GetRecursiveParent(metadata); if (recursiveParent != null) { string recursivePath = metadata.Notation.Path(recursiveParent.Identity.Name, metadata.Parent.Identity.Name); string otherPath = metadata.Notation.Combine(metadata.Identity.Name, recursivePath); MetadataIdentity otherId = metadata.Identity.Push(recursivePath); return(new Lazy <IRelationMetadata>(() => this.GetMetadata(metadata.Schema, otherId))); } } else if (metadata.Owner.Recursor != null) { IRelationContract contract = this.GetContract(metadata); if (contract != null && metadata.Owner.Type.Equals(contract.ItemType)) { return(new Lazy <IRelationMetadata>(() => metadata.Owner)); } } return(null); }
private void ValidateContract(RelationMetadata metadata, IRelationListContract contract) { if (contract.ItemType == null) { this.ThrowContractException(metadata, "Item type cannot be null."); } else if (string.IsNullOrWhiteSpace(contract.ItemName)) { this.ThrowContractException(metadata, "Item name cannot be empty."); } else { Type enumerableType = typeof(IEnumerable <>).MakeGenericType(contract.ItemType); if (!enumerableType.IsAssignableFrom(metadata.Type)) { this.ThrowContractException(metadata, $"List of type '{metadata.Type.GetSanitizedName()}' cannot be converted to '{enumerableType.GetSanitizedName()}'."); } } if (contract.ReadIndex != null && !contract.ReadIndex.HasSignature(contract.ItemType, typeof(int))) { this.ThrowContractException(metadata, $"ReadIndex method must have signature '{contract.ItemType.GetSanitizedName()} (int)'."); } if (contract.WriteIndex != null && !contract.WriteIndex.HasSignature(typeof(void), typeof(int), contract.ItemType)) { this.ThrowContractException(metadata, $"WriteIndex method must have signature 'void (int, {contract.ItemType.GetSanitizedName()})'."); } }
private RelationMetadata CreateItem(RelationMetadata parent) { if (parent.Owner.HasFlag(RelationMetadataFlags.Recursive)) { MemberInfo parentMember = parent.Owner.Parent?.Member; MemberInfo thisMember = parent.Member; if (parentMember != null && parentMember.Equals(thisMember)) { return(null); } } IRelationContract contract = this.GetContract(parent); if (contract == null) { return(null); } MetadataIdentity itemId = parent.Identity.Push(contract.ItemName ?? "Item"); RelationMetadata metadata = new RelationMetadata(parent.Schema, itemId) { Parent = parent, Type = contract.ItemType, Flags = RelationMetadataFlags.Item, ReadIndex = contract.ReadIndex, WriteIndex = contract.WriteIndex, Depth = parent.Depth + 1, }; metadata.Owner = metadata; metadata.Item = this.CreateItem(metadata); metadata.Properties = this.CreateLazy(() => this.CreateProperties(metadata)); metadata.Annotations = this.CreateAnnotations(metadata).ToList(); if (contract.ReadIndex != null) { metadata.Flags |= RelationMetadataFlags.Readable; } if (contract.WriteIndex != null) { metadata.Flags |= RelationMetadataFlags.Writable; } if (metadata.Item != null) { metadata.Flags |= RelationMetadataFlags.List; } return(metadata); }
private IRelationListContract GetListContract(RelationMetadata metadata) { IEnumerable <IRelationContractResolver> allResolvers = new[] { this.DefaultResolver }.Concat(this); IRelationListContract contract = allResolvers.Reverse().NotNull(cr => cr.GetListContract(metadata)).FirstOrDefault(); if (contract != null) { this.ValidateContract(metadata, contract); } return(contract); }
private RelationMetadata CreateProperty(RelationMetadata parent, MemberInfo memberInfo) { MetadataIdentity propertyId = parent.Identity.Push(memberInfo.Name); RelationMetadata metadata = new RelationMetadata(parent.Schema, propertyId) { Type = this.GetMemberType(memberInfo), Parent = parent, Member = memberInfo, Owner = parent.Owner, Flags = RelationMetadataFlags.Property, Depth = parent.Depth, }; metadata.Item = this.CreateItem(metadata); metadata.Properties = this.CreateLazy(() => this.CreateProperties(metadata)); metadata.Annotations = this.CreateAnnotations(metadata).ToList(); if (metadata.Item != null) { metadata.Flags |= RelationMetadataFlags.List; } if (memberInfo is PropertyInfo pi) { if (pi.CanRead) { metadata.Flags |= RelationMetadataFlags.Readable; } if (pi.CanWrite) { metadata.Flags |= RelationMetadataFlags.Writable; } } else if (memberInfo is FieldInfo) { metadata.Flags |= RelationMetadataFlags.Readable | RelationMetadataFlags.Writable; } parent.Schema.AddMetadata <IRelationMetadata>(metadata); if (metadata.Item != null) { parent.Schema.AddMetadata <IRelationMetadata>(metadata.Item); } this.AddRecursors(metadata); return(metadata); }
private IEnumerable <RelationMetadata> CreateProperties(RelationMetadata parent) { IEnumerable <MemberInfo> members = parent.Type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (MemberInfo member in members.Where(m => this.IsFieldOrNonIndexedProperty(m))) { RelationMetadata property = this.CreateProperty(parent, member); if (property != null) { yield return(property); } } }
private RelationMetadata CreateItem(IMetadataBuilderContext context, RelationMetadata parent) { IRelationListContract contract = this.GetListContract(parent); if (contract == null) { return(null); } MetadataIdentity itemId = parent.Identity.Child(contract.ItemName ?? "Item"); RelationMetadata metadata = new RelationMetadata(itemId) { Parent = parent, Type = contract.ItemType, Flags = RelationMetadataFlags.Item | RelationMetadataFlags.Property, ReadIndex = contract.ReadIndex, WriteIndex = contract.WriteIndex, }; metadata.MemberOf = metadata; metadata.Item = this.CreateItem(context, metadata); metadata.Properties = this.CreateLazy(() => this.CreateProperties(context, metadata)); metadata.Annotations = this.CreateAnnotations(metadata).ToList(); if (this.IsMetadataRecursive(metadata)) { metadata.Flags |= RelationMetadataFlags.Recursive; } if (contract.ReadIndex != null) { metadata.Flags |= RelationMetadataFlags.Readable; } if (contract.WriteIndex != null) { metadata.Flags |= RelationMetadataFlags.Writable; } if (metadata.Item != null) { metadata.Flags |= RelationMetadataFlags.List; } context.AddMetadata <IRelationMetadata>(metadata); return(metadata); }
private RelationMetadata CreateProperty(IMetadataBuilderContext context, RelationMetadata parent, MemberInfo memberInfo) { MetadataIdentity attributeId = parent.Identity.Child(memberInfo.Name); RelationMetadata metadata = new RelationMetadata(attributeId) { Type = this.GetMemberType(memberInfo), Parent = parent, Member = memberInfo, MemberOf = parent.MemberOf, Flags = RelationMetadataFlags.Property, }; metadata.Item = this.CreateItem(context, metadata); metadata.Properties = this.CreateLazy(() => this.CreateProperties(context, metadata)); metadata.Annotations = this.CreateAnnotations(metadata).ToList(); if (metadata.Item != null) { metadata.Flags |= RelationMetadataFlags.List; } if (this.IsMetadataRecursive(metadata)) { metadata.Flags |= RelationMetadataFlags.Recursive; } if (memberInfo is PropertyInfo pi) { if (pi.CanRead) { metadata.Flags |= RelationMetadataFlags.Readable; } if (pi.CanWrite) { metadata.Flags |= RelationMetadataFlags.Writable; } } else if (memberInfo is FieldInfo) { metadata.Flags |= RelationMetadataFlags.Readable | RelationMetadataFlags.Writable; } context.AddMetadata <IRelationMetadata>(metadata); return(metadata); }
private IRelationMetadata GetRecursiveParent(RelationMetadata metadata) { IRelationMetadata current = metadata.Parent; IRelationMetadata stop = current.Owner.Parent ?? current.Owner; while (current != stop) { if (current.Type == metadata.Type) { return(current); } current = current.Parent; } return(null); }
private void AddRecursors(RelationMetadata metadata) { metadata.Recursor = this.CreateRecursor(metadata); if (metadata.Recursor != null) { metadata.Flags |= RelationMetadataFlags.Recursive | RelationMetadataFlags.List; } if (metadata.Item != null) { metadata.Item.Recursor = this.CreateRecursor(metadata.Item); if (metadata.Item.Recursor != null) { metadata.Item.Flags |= RelationMetadataFlags.Recursive; } } }
public void Initialize(IMetadataBuilderContext context) { RelationMetadata model = new RelationMetadata(context.Identity) { Flags = RelationMetadataFlags.Model | RelationMetadataFlags.Readable, Type = context.Schema.Model, }; model.MemberOf = model; model.Properties = this.CreateLazy(() => this.CreateProperties(context, model)); model.Annotations = this.CreateAnnotations(model).ToList(); model.Item = this.CreateItem(context, model); if (model.Item != null) { model.Flags |= RelationMetadataFlags.List; } context.AddMetadata <IRelationMetadata>(model); }
internal void Initialize(Schema schema, Type modelType) { MetadataIdentity identity = new MetadataIdentity(schema); RelationMetadata metadata = new RelationMetadata(schema, identity) { Flags = RelationMetadataFlags.Model | RelationMetadataFlags.Readable, Type = modelType, }; metadata.Owner = metadata; metadata.Properties = this.CreateLazy(() => this.CreateProperties(metadata)); metadata.Depth = 0; metadata.Annotations = this.CreateAnnotations(metadata).ToList(); metadata.Item = this.CreateItem(metadata); if (metadata.Item != null) { metadata.Flags |= RelationMetadataFlags.List; } schema.AddMetadata <IRelationMetadata>(metadata); }
private IEnumerable <RelationMetadata> CreateProperties(IMetadataBuilderContext context, RelationMetadata parent) { IEnumerable <MemberInfo> members = parent.Type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (MemberInfo member in members.Where(m => this.IsFieldOrNonIndexedProperty(m))) { yield return(this.CreateProperty(context, parent, member)); } }
private IEnumerable <Attribute> CreateAnnotations(RelationMetadata metadata) { IEnumerable <IRelationContractResolver> allResolvers = new[] { this.DefaultResolver }.Concat(this); return(allResolvers.NotNull().SelectMany(cr => cr.GetAnnotationContract(metadata) ?? Array.Empty <Attribute>()).NotNull()); }
private void ThrowContractException(RelationMetadata metadata, string message) { throw new MetadataBuilderException($"Invalid contract for metadata '{metadata.Identity}'. {message}"); }