private static CmdletParameter CreateEntityParameter( OdcmProperty property, Type powerShellType, bool markAsPowerShellParameter, bool isBaseType, string entityTypeFullName, bool isReadOnly = false, bool allowPipelineInputByName = true, IEnumerable <string> enumValues = null) { var result = new CmdletParameter(property.Name, powerShellType) { Mandatory = property.IsRequired, IsPowerShellParameter = markAsPowerShellParameter && !isReadOnly, ValueFromPipelineByPropertyName = allowPipelineInputByName, DerivedTypeName = markAsPowerShellParameter || isBaseType ? null : entityTypeFullName, IsExpandable = property.IsExpandable(), IsSortable = !markAsPowerShellParameter && !property.IsCollection, Documentation = new CmdletParameterDocumentation() { Descriptions = new string[] { $"The \"{property.Name}\" property, of type \"{property.Type.FullName}\".", $"This property is on the \"{entityTypeFullName}\" type.", property.Description, }, ValidValues = enumValues, } }; return(result); }
protected ConcreteNavigationProperty(OdcmProperty odcmProperty) : base(odcmProperty) { FieldName = NamesService.GetPropertyFieldName(odcmProperty); FieldType = NamesService.GetConcreteTypeName(odcmProperty.Type); Type = new Type(NamesService.GetConcreteInterfaceName(odcmProperty.Type)); PrivateSet = true; }
private void WriteProperty(OdcmClass odcmClass, IEdmProperty property) { var odcmType = ResolveType(property.Type); var odcmProperty = new OdcmProperty(property.Name) { Class = odcmClass, IsNullable = property.Type.IsNullable, IsCollection = property.Type.IsCollection(), ContainsTarget = property is IEdmNavigationProperty && ((IEdmNavigationProperty)property).ContainsTarget, IsLink = property is IEdmNavigationProperty, DefaultValue = property is IEdmStructuralProperty ? ((IEdmStructuralProperty)property).DefaultValueString : null }; odcmProperty.Projection = new OdcmProjection { Type = odcmType, BackLink = odcmProperty }; _propertyCapabilitiesCache.Add(odcmProperty, OdcmCapability.DefaultPropertyCapabilities); AddVocabularyAnnotations(odcmProperty, property); odcmClass.Properties.Add(odcmProperty); }
public Given_an_OdcmClass_Entity_Property_forced_to_pascal_case() { SetConfiguration(new CSharpWriterSettings { ForcePropertyPascalCasing = true }); Init(m => { var originalProperty = Class.Properties.Where(p => !p.IsCollection).RandomElement(); var camelCasedName = Any.Char('a', 'z') + originalProperty.Name; _property = originalProperty.Rename(camelCasedName); originalProperty = Class.NavigationProperties().Where(p => p.IsCollection).RandomElement(); camelCasedName = Any.Char('a', 'z') + originalProperty.Name; _collectionProperty = originalProperty.Rename(camelCasedName); }); _propertyType = Proxy.GetClass(_property.Type.Namespace, _property.Type.Name); _collectionPropertyType = Proxy.GetClass(_collectionProperty.Type.Namespace, _collectionProperty.Type.Name); _collectionPropertyType = typeof(IList <>).MakeGenericType(_collectionPropertyType); }
public static string GetToLowerImport(this OdcmProperty property) { var type = property.Projection.Type; var index = type.Name.LastIndexOf('.'); return(type.Name.Substring(0, index).ToLower() + type.Name.Substring(index)); }
/// <summary> /// This method takes a specific property and determines whether its could be referenced in the navigation property of another type. /// The navigation property must also come from chain where the containTarget=true from the root Service class to prove that we can reference it. /// Ideally we should call this function if GetServiceCollectionNavigationPropertyForPropertyType returns null /// </summary> /// <param name="odcmProperty">The property to check</param> /// <param name="model">The model to use</param> /// <returns></returns> public static bool IsPropertyChainedToContainedServiceNavigationProperty(this OdcmProperty odcmProperty, OdcmModel model) { // keep track of the types we've traversed to avoid circular references var navigatedTypes = new HashSet <string>(); var matchingRootProperty = GetOdcmNamespaces(model) .SelectMany( @namespace => @namespace .Classes .FirstOrDefault(odcmClass => odcmClass.Kind == OdcmClassKind.Service) // find the root service class ?.Properties ?.Where(serviceProperty => serviceProperty.GetType() == typeof(OdcmSingleton)) // find the singleton properties ?.Where(singleton => singleton. Type.AsOdcmClass() ?.Properties ?.Where(property => property.ContainsTarget) // find singleton type properties that are self contained ?.Any(property => property.IsPropertyTypeChainedContainedNavigationProperty( // keep following the containsTarget=True to find if we can use a reference odcmProperty, navigatedTypes, property.IsCollection ? $"{singleton.Name}/{property.Name}/{{id}}" : $"{singleton.Name}/{property.Name}") ) ?? false ) ?? Array.Empty <OdcmProperty>() ).FirstOrDefault(); return(matchingRootProperty != null); }
/// <summary> /// Generates the OData route string with ID and typecast placeholders. /// It will have neither a leading slash nor trailing slash. /// </summary> /// <param name="includeEntityIdAndTypeCast">Whether or not to include the entity ID and typecast placeholders if required</param> /// <returns>The OData route.</returns> public string ToODataRouteString(bool includeEntityIdAndTypeCast = true) { IList <string> segments = new List <string>(); OdcmProperty lastSegment = this.Segments.LastOrDefault(); foreach (OdcmProperty property in this.Segments) { // Add this node to the route segments.Add(property.Name); // Add the ID and typecast after the final segment only if the caller wants to include them if (property != lastSegment || includeEntityIdAndTypeCast) { // If this segment requires an ID, add it to the route if (this._idParameters.TryGetValue(property, out string idParameterName)) { segments.Add($"{{{idParameterName}}}"); } // If this segment requires a typecast, add it to the route if (this._typeCastParameters.TryGetValue(property, out string typeCastParameterName)) { segments.Add($"{{{typeCastParameterName}}}"); } } } return(string.Join("/", segments)); }
public static OdcmProperty Rename(this OdcmProperty originalProperty, string newName) { var index = originalProperty.Class.Properties.IndexOf(originalProperty); originalProperty.Class.Properties[index] = new OdcmProperty(newName) { Class = originalProperty.Class, ReadOnly = originalProperty.ReadOnly, Projection = originalProperty.Type.DefaultProjection, ContainsTarget = originalProperty.ContainsTarget, IsCollection = originalProperty.IsCollection, IsLink = originalProperty.IsLink, IsNullable = originalProperty.IsNullable, IsRequired = originalProperty.IsRequired }; if (originalProperty.Class is OdcmEntityClass && ((OdcmEntityClass)originalProperty.Class).Key.Contains(originalProperty)) { var keyIndex = ((OdcmEntityClass)originalProperty.Class).Key.IndexOf(originalProperty); ((OdcmEntityClass)originalProperty.Class).Key[keyIndex] = originalProperty.Class.Properties[index]; } return(originalProperty.Class.Properties[index]); }
/// <summary> /// Sanitizes a property name for the following conditions: /// 1) a property has the same name as a C# keyword. Prefix @ to the property name to make it valid. /// 2) a property has the same name as the class. First we'll try to change the property name to the /// return type name. If the return type name is the same as the class name, then we'll append /// "Property" to the property name. /// </summary> /// <param name="property">The string that called this extension.</param> /// <param name="odcmProperty">An OdcmProperty. Use the property that you want to sanitize.</param> /// <param name="prefix">The prefix to use on this property.</param> /// <returns></returns> public static string GetSanitizedPropertyName(this string property, OdcmProperty odcmProperty, string prefix = null) { if (GetReservedNames().Contains(property)) { var reservedPrefix = string.IsNullOrEmpty(prefix) ? DefaultReservedPrefix : prefix; logger.Info("Property \"{0}\" is a reserved word in .NET. Converting to \"{1}{0}\"", property.ToUpperFirstChar(), reservedPrefix); return(string.Concat(reservedPrefix, property.ToUpperFirstChar())); } // Check whether the propertyObject is null (means they called the extension from a string). // Check whether the property name is the same as the class name. // Only constructor members may be named the same as the class name. if (odcmProperty != null && property == odcmProperty.Class.Name.ToUpperFirstChar()) { // Check whether the property type is the same as the class name. if (odcmProperty.Projection.Type.Name.ToUpperFirstChar() == odcmProperty.Class.Name.ToUpperFirstChar()) { // Name the property: {metadataName} + "Property" logger.Info("Property type \"{0}\" has the same name as the class. Converting to \"{0}Property\"", property); return(string.Concat(property, "Property")); } // Name the property by its type. Sanitize it in case the type is a reserved name. return(odcmProperty.Projection.Type.Name.ToUpperFirstChar().GetSanitizedPropertyName()); } return(property); }
/// <summary> /// Expands a node into child nodes. /// </summary> /// <param name="node">The node to expand</param> /// <param name="model">The ODCM model</param> /// <returns>The child nodes if the node can be expanded, otherwise an empty list.</returns> private static IEnumerable <OdcmNode> CreateChildNodes(this OdcmNode node, OdcmModel model) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (model == null) { throw new ArgumentNullException(nameof(model)); } // Identify the kind of ODCM element this node represents and expand it if we need to OdcmProperty obj = node.OdcmProperty; IEnumerable <OdcmProperty> childObjects = obj.Type.GetChildObjects(model); // Don't allow loops in the list of ODCM nodes ICollection <string> parents = new HashSet <string>(); OdcmNode currentNode = node; while (currentNode != null) { parents.Add(currentNode.OdcmProperty.CanonicalName()); currentNode = currentNode.Parent; } return(childObjects // Filter out the children we've already seen so we can avoid loops .Where(child => !parents.Contains(child.CanonicalName())) // Add the child nodes to the current node .Select(child => node.CreateChildNode(child))); }
protected FetcherNavigationProperty(OdcmProperty odcmProperty) : base(odcmProperty) { FieldName = NamesService.GetFetcherFieldName(odcmProperty); InstanceType = NamesService.GetFetcherTypeName(odcmProperty.Type); PrivateSet = true; Type = new Type(NamesService.GetFetcherInterfaceName(odcmProperty.Type)); }
/// <summary> /// This method takes in a property and looks through to see if the given testProperty could be contained in it through its contained navigation properties or /// its nested contained navigation properties. /// </summary> /// <param name="odcmRootProperty">The property to start the search from</param> /// <param name="testProperty">The property to find in the from the root type</param> /// <param name="navigatedTypes">The types already navigated to prevent circular references</param> /// <param name="route">The route followed to get here</param> /// <returns></returns> private static bool IsPropertyTypeChainedContainedNavigationProperty(this OdcmProperty odcmRootProperty, OdcmProperty testProperty, HashSet <string> navigatedTypes, string route) { // check if the property already matches the type. if (odcmRootProperty.Type.FullName.Equals(testProperty.Type.FullName, StringComparison.OrdinalIgnoreCase)) { logger.Info("Property \"{0}\" matches self contained navigation property \"{1}\" of type \"{2}\"", testProperty.Name, odcmRootProperty.Name, odcmRootProperty.Type.FullName); logger.Info("Possible route from service class is: {0}{1}{1}", route, Environment.NewLine); return(true); } // check if the base class is referenced instead. if (odcmRootProperty.AsOdcmClass()?.IsAncestorOfType(testProperty.AsOdcmClass() ?? null) ?? false) { logger.Info("Property \"{0}\" of type \"{1}\" matches self contained navigation property \"{2}\" of Base type \"{3}\"", testProperty.Name, testProperty.Type.FullName, odcmRootProperty.Name, odcmRootProperty.Type.FullName); logger.Info("Possible route from service class is: {0}{1}{1}", route, Environment.NewLine); return(true); } // its not this type so lets add it to the exclusion list navigatedTypes.Add(odcmRootProperty.Type.FullName); // The current type does not match. So, we get the list of contained nav properties from the given type and recursively subject it to the same test var matchingProperty = odcmRootProperty.Type.AsOdcmClass()? .Properties .Where(prop => prop.ContainsTarget) // the nave properties with containsTarget .Where(prop => !navigatedTypes.Contains(prop.Type.FullName)) // prevent any cycle business .FirstOrDefault(prop => prop.IsPropertyTypeChainedContainedNavigationProperty(testProperty, navigatedTypes, prop.IsCollection ? $"{route}/{prop.Name}/{{id}}" : $"{route}/{prop.Name}") ); return(matchingProperty != null); }
protected ConcreteNavigationAccessorProperty(OdcmProperty odcmProperty) : base(odcmProperty) { FieldName = NamesService.GetPropertyFieldName(odcmProperty); InstanceType = NamesService.GetFetcherTypeName(odcmProperty.Type); FieldType = NamesService.GetConcreteTypeName(odcmProperty.Type); Type = new Type(NamesService.GetConcreteTypeName(odcmProperty.Type)); }
private static string ToEdmx(this OdcmProperty odcmProperty) { var tagName = "Property"; var typeAttributeName = "Type"; var edmType = odcmProperty.Type.FullName; if (odcmProperty.Class.Kind == OdcmClassKind.Service) { if (odcmProperty.IsCollection) { tagName = "EntitySet"; typeAttributeName = "EntityType"; } else { tagName = "Singleton"; } } else if (odcmProperty.Class.Kind == OdcmClassKind.Entity) { if (odcmProperty.Type is OdcmClass && ((OdcmClass)odcmProperty.Type).Kind == OdcmClassKind.Entity) { tagName = "NavigationProperty"; if (odcmProperty.IsCollection) { edmType = String.Format("Collection({0})", edmType); } } } return(String.Format("<{0} Name=\"{1}\" {2}=\"{3}\" />", tagName, odcmProperty.Name, typeAttributeName, edmType)); }
public ObsoletedNavigationProperty(OdcmProperty odcmProperty) : base(odcmProperty) { Type = odcmProperty.IsCollection ? new Type(new Identifier("global::System.Collections.Generic", "IList"), new Type(NamesService.GetConcreteTypeName(odcmProperty.Type))) : new Type(NamesService.GetConcreteTypeName(odcmProperty.Type)); }
public static FetcherNavigationProperty ForConcrete(OdcmProperty odcmProperty) { return(new FetcherNavigationProperty(odcmProperty) { DefiningInterface = NamesService.GetFetcherInterfaceName(odcmProperty.Class) }); }
public new static ConcreteNavigationProperty ForConcrete(OdcmProperty odcmProperty) { return(new ConcreteNavigationCollectionProperty(odcmProperty) { DefiningInterface = NamesService.GetConcreteInterfaceName(odcmProperty.Class), }); }
/// <summary> /// Adds a property line inside an entity or complex type object /// </summary> /// <param name="prop">property</param> private void AddProperties(OdcmProperty prop) { if (prop.LongDescription != null || prop.Description != null) { List <string> multiLineDescriptions = SplitString(prop.GetSanitizedLongDescription()); if (multiLineDescriptions.Count() == 1) { sb.AppendLine($"{NamespaceIndent}{TabSpace}// {multiLineDescriptions.First()}"); } else { sb.AppendLine($"{NamespaceIndent}{TabSpace}/**"); foreach (var descriptionLine in multiLineDescriptions) { sb.AppendLine($"{NamespaceIndent}{TabSpace} * {descriptionLine}"); } sb.AppendLine($"{NamespaceIndent}{TabSpace} */"); } } var typeName = GetFullyQualifiedTypeScriptTypeName(prop.GetTypeString(), prop.Projection.Type.Namespace.GetNamespaceName()); if (prop.IsNullable) { typeName = $"NullableOption<{typeName}>"; } sb.AppendLine($"{NamespaceIndent}{TabSpace}{prop.Name}?: {typeName};"); }
private ConcreteNavigationCollectionProperty(OdcmProperty odcmProperty) : base(odcmProperty) { FieldName = NamesService.GetConcreteFieldName(odcmProperty); OdcmType = odcmProperty.Type; PrivateSet = true; Type = new Type(new Identifier("global::System.Collections.Generic", "IList"), new Type(NamesService.GetConcreteInterfaceName(odcmProperty.Type))); }
public static string GetSanitizedLongDescription(this OdcmProperty property) { if (property.LongDescription != null) { return(property.LongDescription.Replace("<", "<").Replace(">", ">").Replace("&", "&")); } return(null); }
private ConcreteNavigationCollectionAccessorProperty(OdcmProperty odcmProperty) : base(odcmProperty) { CollectionType = new Type(NamesService.GetCollectionTypeName((OdcmClass)odcmProperty.Type)); FieldName = NamesService.GetConcreteFieldName(odcmProperty); InstanceType = NamesService.GetConcreteTypeName(odcmProperty.Type); Type = new Type(new Identifier("global::System.Collections.Generic", "IList"), new Type(NamesService.GetConcreteTypeName(odcmProperty.Type))); }
private ConcreteNavigationCollectionProperty(OdcmProperty odcmProperty) : base(odcmProperty) { FieldName = NamesService.GetConcreteFieldName(odcmProperty); OdcmType = odcmProperty.Type; PrivateSet = true; Type = new Type(NamesService.GetExtensionTypeName("IPagedCollection"), new Type(NamesService.GetConcreteInterfaceName(odcmProperty.Type))); }
public static Parameter FromProperty(OdcmProperty arg) { return(new Parameter { Name = arg.Name.ToLowerCamelCase(), Type = new Type(NamesService.GetConcreteTypeName(arg.Type)) }); }
public static Field ForNavigationProperty(OdcmProperty property) { return(new Field { Name = NamesService.GetPropertyFieldName(property), Type = new Type(NamesService.GetConcreteTypeName(property.Type)) }); }
protected FetcherNavigationCollectionProperty(OdcmProperty odcmProperty) : base(odcmProperty) { CollectionType = new Type(NamesService.GetCollectionTypeName((OdcmClass)odcmProperty.Type)); FieldName = NamesService.GetFetcherCollectionFieldName(odcmProperty); InstanceType = NamesService.GetFetcherTypeName(odcmProperty.Type); Type = new Type(NamesService.GetCollectionInterfaceName((OdcmClass)odcmProperty.Type)); }
public static string SanitizePropertyName(this OdcmProperty property) { if (ReservedNames.Contains(property.Name.ToLower())) { return(property.Class.Name.ToLowerFirstChar() + property.Name.ToUpperFirstChar()); } return(property.Name); }
public static Field ForFetcherNavigationCollectionProperty(OdcmProperty property) { return(new Field { Name = NamesService.GetFetcherCollectionFieldName(property), Type = new Type(NamesService.GetCollectionTypeName((OdcmClass)property.Type)) }); }
public static string SanitizePropertyName(this OdcmProperty property) { if (ReservedNames.Contains(property.Name.ToLower())) { return(ReservedPrefix + property.Name); } return(property.Name); }
public static Field ForNavigationConcreteProperty(OdcmProperty property) { return(new Field { Name = NamesService.GetConcreteFieldName(property), Type = new Type(NamesService.GetExtensionTypeName("EntityCollectionImpl"), new Type(NamesService.GetConcreteTypeName((OdcmClass)property.Type))) }); }
public ObsoletedProperty(OdcmProperty odcmProperty) : base(odcmProperty) { Type = odcmProperty.IsCollection ? new Type(new Identifier("global::System.Collections.Generic", "IList"), TypeService.GetPropertyType(odcmProperty)) : TypeService.GetPropertyType(odcmProperty); UpdatedName = Name; Name = NamesService.GetModelPropertyName(odcmProperty); }