/// <summary> /// Gets the generated arguments /// </summary> /// <returns>The list of arguments</returns> public static IEnumerable <ApiField> GetArguments() { if (FilterType.Fields.Count > 2) { yield return (FilterType.CreateField( "filter", EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); } if (SortType.Values.Any()) { const EnFieldFlags SortFlags = EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument | EnFieldFlags.IsArray; yield return(ApiField.Object("sort", SortType.TypeName, SortFlags)); } if (NodeMetaData.KeyProperty != null) { var keyMetadata = TypeMetadata.GenerateTypeMetadata( NodeMetaData.KeyProperty.PropertyType, NodeMetaData.KeyProperty.GetCustomAttribute <PublishToApiAttribute>()); if (keyMetadata.ScalarType != EnScalarType.None) { yield return (ApiField.Scalar( "id", keyMetadata.ScalarType, EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); } } yield return (ApiField.Scalar( "limit", EnScalarType.Integer, EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); yield return (ApiField.Scalar( "offset", EnScalarType.Integer, EnFieldFlags.CanBeUsedInInput | EnFieldFlags.Queryable | EnFieldFlags.IsTypeArgument)); }
/// <summary> /// Performs final type initialization /// </summary> private static void InitializeType() { if (isInitialized) { return; } lock (LockObject) { if (isInitialized) { return; } isInitialized = true; var nodeType = ObjectResolver <T> .GeneratedType; var realFields = ObjectResolver <T> .DeclaredFields; var sortableFields = nodeType.Fields.Where(f => f.Flags.HasFlag(EnFieldFlags.IsSortable)); foreach (var sortableField in sortableFields) { SortingConditions[$"{sortableField.Name}_asc"] = new SortingCondition(realFields[sortableField.Name].Name, SortingCondition.EnDirection.Asc); SortingConditions[$"{sortableField.Name}_desc"] = new SortingCondition(realFields[sortableField.Name].Name, SortingCondition.EnDirection.Desc); } SortType.Values.AddRange(SortingConditions.Keys); FilterChecks["OR"] = prop => { var subFilters = prop.Value as JArray; if (subFilters == null) { return(Expression.Constant(true)); } Expression or = Expression.Constant(false); or = subFilters.Children() .OfType <JObject>() .Aggregate(or, (current, subFilter) => Expression.Or(current, CreateFilterPart(subFilter))); return(or); }; FilterType.Fields.Add( FilterType.CreateField( "OR", description: "Combine filter conditions with logic \"OR\"", flags: EnFieldFlags.Queryable | EnFieldFlags.CanBeUsedInInput)); FilterChecks["AND"] = prop => { var subFilters = prop.Value as JArray; if (subFilters == null) { return(Expression.Constant(true)); } Expression and = Expression.Constant(true); and = subFilters.Children() .OfType <JObject>() .Aggregate( and, (current, subFilter) => Expression.And(current, CreateFilterPart(subFilter))); return(and); }; FilterType.Fields.Add( FilterType.CreateField( "AND", description: "Combine filter conditions with logic \"AND\"", flags: EnFieldFlags.Queryable | EnFieldFlags.CanBeUsedInInput)); var filterableFields = nodeType.Fields.Where(f => f.Flags.HasFlag(EnFieldFlags.IsFilterable)); var stringContains = typeof(string).GetMethod("Contains"); var stringStartsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); var stringEndsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); var stringToLower = typeof(string).GetMethod("ToLower", new Type[0]); foreach (var filterableField in filterableFields) { var property = realFields[filterableField.Name] as PropertyInfo; if (property == null) { continue; } var propertyExpression = Expression.Property(FilterSourceParameter, property); Func <JProperty, Expression> createConstant = prop => Expression.Constant(prop.Value.ToObject(property.PropertyType), property.PropertyType); AddFilterExpression( filterableField.Name, prop => Expression.Equal(propertyExpression, createConstant(prop)), filterableField, "{0} exactly equals to the parameter"); AddFilterExpression( $"{filterableField.Name}_not", prop => Expression.NotEqual(propertyExpression, createConstant(prop)), filterableField, "{0} not equals to the parameter"); switch (filterableField.ScalarType) { case EnScalarType.Float: case EnScalarType.Decimal: case EnScalarType.Integer: case EnScalarType.DateTime: AddFilterExpression( $"{filterableField.Name}_lt", prop => Expression.LessThan(propertyExpression, createConstant(prop)), filterableField, "{0} is less then the parameter"); AddFilterExpression( $"{filterableField.Name}_lte", prop => Expression.LessThanOrEqual(propertyExpression, createConstant(prop)), filterableField, "{0} is less then or equal to the parameter"); AddFilterExpression( $"{filterableField.Name}_gt", prop => Expression.GreaterThan(propertyExpression, createConstant(prop)), filterableField, "{0} is greater then the parameter"); AddFilterExpression( $"{filterableField.Name}_gte", prop => Expression.GreaterThanOrEqual(propertyExpression, createConstant(prop)), filterableField, "{0} is greater then or equal to the parameter"); break; case EnScalarType.String: var propertyToLower = Expression.Call(propertyExpression, stringToLower); AddFilterExpression( $"{filterableField.Name}_in", prop => Expression.Call(createConstant(prop), stringContains, propertyExpression), filterableField, "{0} is a substring of the parameter"); AddFilterExpression( $"{filterableField.Name}_not_in", prop => Expression.Not( Expression.Call(createConstant(prop), stringContains, propertyExpression)), filterableField, "{0} is not a substring of the parameter"); AddFilterExpression( $"{filterableField.Name}_contains", prop => Expression.Call(propertyExpression, stringContains, createConstant(prop)), filterableField, "{0} contains the parameter as substring"); AddFilterExpression( $"{filterableField.Name}_not_contains", prop => Expression.Not( Expression.Call(propertyExpression, stringContains, createConstant(prop))), filterableField, "{0} doesn't contain the parameter as substring"); AddFilterExpression( $"{filterableField.Name}_starts_with", prop => Expression.Call(propertyExpression, stringStartsWith, createConstant(prop)), filterableField, "{0} starts with the parameter value"); AddFilterExpression( $"{filterableField.Name}_not_starts_with", prop => Expression.Not( Expression.Call(propertyExpression, stringStartsWith, createConstant(prop))), filterableField, "{0} doesn't start with the parameter value"); AddFilterExpression( $"{filterableField.Name}_ends_with", prop => Expression.Call(propertyExpression, stringEndsWith, createConstant(prop)), filterableField, "{0} ends with the parameter value"); AddFilterExpression( $"{filterableField.Name}_not_ends_with", prop => Expression.Not( Expression.Call(propertyExpression, stringEndsWith, createConstant(prop))), filterableField, "{0} doesn't end with the parameter value"); AddFilterExpression( $"{filterableField.Name}_l", prop => Expression.Equal(propertyToLower, createConstant(prop)), filterableField, "{0} lowercased equals the parameter"); AddFilterExpression( $"{filterableField.Name}_l_not", prop => Expression.NotEqual(propertyToLower, createConstant(prop)), filterableField, "{0} lowercased doesn't equal the parameter"); AddFilterExpression( $"{filterableField.Name}_l_in", prop => Expression.Call(createConstant(prop), stringContains, propertyToLower), filterableField, "{0} lowercased is a substring of the parameter"); AddFilterExpression( $"{filterableField.Name}_l_not_in", prop => Expression.Not( Expression.Call(createConstant(prop), stringContains, propertyToLower)), filterableField, "{0} lowercased is not a substring of the parameter"); AddFilterExpression( $"{filterableField.Name}_l_contains", prop => Expression.Call(propertyToLower, stringContains, createConstant(prop)), filterableField, "{0} lowercased contains the parameter as substring"); AddFilterExpression( $"{filterableField.Name}_l_not_contains", prop => Expression.Not( Expression.Call(propertyToLower, stringContains, createConstant(prop))), filterableField, "{0} lowercased doesn't contain the parameter as substring"); AddFilterExpression( $"{filterableField.Name}_l_starts_with", prop => Expression.Call(propertyToLower, stringStartsWith, createConstant(prop)), filterableField, "{0} lowercased starts with the parameter value"); AddFilterExpression( $"{filterableField.Name}_l_not_starts_with", prop => Expression.Not( Expression.Call(propertyToLower, stringStartsWith, createConstant(prop))), filterableField, "{0} lowercased doesn't start with the parameter value"); AddFilterExpression( $"{filterableField.Name}_l_ends_with", prop => Expression.Call(propertyToLower, stringEndsWith, createConstant(prop)), filterableField, "{0} lowercased ends with the parameter value"); AddFilterExpression( $"{filterableField.Name}_l_not_ends_with", prop => Expression.Not( Expression.Call(propertyToLower, stringEndsWith, createConstant(prop))), filterableField, "{0} lowercased doesn't end with the parameter value"); break; } } } }