/// <summary> /// Retrieves fluent configuration wrapper for form field /// </summary> /// <typeparam name="TData">Field type</typeparam> /// <param name="field">Field expression</param> /// <returns>Formwatch field configuration builder</returns> public FormWatchFieldBuilder <TData> Field <TData>(Expression <Func <TFormViewModel, TData> > field) { var prop = LambdaHelpers.ParsePropertyLambda(field); AssureFieldConfiguration <TData>(prop); return((FormWatchFieldBuilder <TData>)_fieldsConfig[prop.Name]); }
private Func <object, string> GetConverterForType(Type propertyType) { if (propertyType.IsEnum) { return(o => ((Enum)o).GetDisplayName()); } if (typeof(string).IsAssignableFrom(propertyType)) { return(o => (string)o); //Prevent futher conversion } var enumerableArg = LambdaHelpers.GetEnumerableType(propertyType); if (enumerableArg != null) { return(LambdaHelpers.GetEnumerableConvertor(GetConverterForType(enumerableArg))); } if (typeof(IEnumerable).IsAssignableFrom(propertyType)) { return(LambdaHelpers.GetEnumerableConvertor(item => item.ToString())); } return (DisplayFunctions.Where( displayFunction => displayFunction.Key.IsAssignableFrom(propertyType)) .Select(kv => kv.Value) .FirstOrDefault() ?? (arg => arg?.ToString())); }
/// <summary> /// Filters specified target table field with form field treated as ValueFilter. /// Warning! ValueFilter should be configured for column /// </summary> /// <param name="expr">Property expression</param> /// <param name="af">Filter</param> public static void FilterValueExpr <TCol, TForm>(this FormWatchAutofilterConfiguration <TCol, TForm> af, LambdaExpression expr) { af.Update(new FormWatchFilteringsMappings() { FilterType = 0, FieldKeys = new[] { LambdaHelpers.ParsePropertyLambda(expr).Name } }); }
/// <summary> /// Filters specified target table field with form field treated as Range Filter. /// In this case field is list or array (e.g. mapped to multiple select) /// Warning! SelectFilter with multiple options should be configured for column /// </summary> /// <param name="field">Fields that will be merged into multiple filter values</param> public static void FilterMultiple <TCol, TForm>(this FormWatchAutofilterConfiguration <TCol, TForm> af, Expression <Func <TForm, IEnumerable <TCol> > > field) { af.Update(new FormWatchFilteringsMappings() { FilterType = 2, FieldKeys = new [] { LambdaHelpers.ParsePropertyLambda(field).Name } }); }
/// <summary> /// Filters specified target table field with form field treated as Range Filter. /// Warning! SelectFilter with multiple options should be configured for column /// </summary> /// <param name="fields">Fields that will be merged into multiple filter values</param> public static void FilterMultiple <TCol, TForm>(this FormWatchAutofilterConfiguration <TCol, TForm> af, params Expression <Func <TForm, TCol> >[] fields) { af.Update(new FormWatchFilteringsMappings() { FilterType = 2, FieldKeys = fields.Select(c => LambdaHelpers.ParsePropertyLambda(c).Name).ToArray() }); }
/// <summary> /// Filters specified target table field with form field treated as Range Filter. /// Warning! RangeFilter should be configured for column /// </summary> /// <param name="expr">Property expression</param> /// <param name="af">Filter</param> public static void FilterRangeExpr <TCol, TForm>(this FormWatchAutofilterConfiguration <TCol, TForm> af, LambdaExpression from, LambdaExpression to) { af.Update(new FormWatchFilteringsMappings() { FilterType = 1, FieldKeys = new[] { LambdaHelpers.ParsePropertyLambda(from).Name, LambdaHelpers.ParsePropertyLambda(to).Name, } }); }
/// <summary> /// Filters specified target table field with form field treated as Range Filter. /// Warning! RangeFilter should be configured for column /// </summary> /// <param name="from">Field containig from value</param> /// <param name="to">Field containing to value</param> public static void FilterRange <TCol, TForm>(this FormWatchAutofilterConfiguration <TCol, TForm> af, Expression <Func <TForm, IEnumerable <TCol?> > > values) where TCol : struct { af.Update(new FormWatchFilteringsMappings() { FilterType = 1, FieldKeys = new[] { LambdaHelpers.ParsePropertyLambda(values).Name } }); }
private TableColumn GetTableColumn([NotNull] PropertyInfo propertyInfo) { return(new TableColumn { Getter = LambdaHelpers.CompileGetter(propertyInfo, TargetType), Name = propertyInfo.GetDisplayName(), Converter = GetConverterForType(propertyInfo.PropertyType), }); }
/// <summary> /// Adds client total calculator function to totals /// Calculator function type: (data:IClientDataResults)=>any /// data: data prepared on client side. Consists of 4 collections: Source, Filtered, Ordered, Displaying all of type any[] containing corresponding JSONed TTableData /// </summary> /// <param name="column">Table column to provide total with</param> /// <param name="function">Client calculator function</param> /// <returns></returns> public TotalCalculatorBuilder <TSourceData, TTableData> AddClientCalculator <TTableColumn>( Expression <Func <TTableData, TTableColumn> > column, string function ) { var name = LambdaHelpers.ParsePropertyLambda(column).Name; _clientCalculators.Add(name, function); return(this); }
private IQueryable <string> SelectCheckboxes(PowerTablesData data) { var column = data.Request.Query.AdditionalData["SelectionColumn"]; var columnProp = data.Configuration.SourceType.GetProperty(column); var selection = LambdaHelpers.MemberExpression(columnProp); var q = ReflectionCache.CallSelect(data.Ordered, selection, data.Configuration.SourceType, columnProp.PropertyType); return(q.Cast <object>().Select(c => c.ToString())); }
/// <summary> /// Adds only template for total cell /// </summary> /// <param name="column">Table column to provide total with</param> /// <param name="templateBuilder">Template builder like for usual column, but here is only self reference ('{@}') available </param> /// <returns></returns> public TotalCalculatorBuilder <TSourceData, TTableData> AddTemplate <TTableColumn>( Expression <Func <TTableData, TTableColumn> > column, Action <CellTemplateBuilder> templateBuilder ) { var name = LambdaHelpers.ParsePropertyLambda(column).Name; CellTemplateBuilder ctb = new CellTemplateBuilder(null); templateBuilder(ctb); _valueFunctions.Add(name, ctb.Build()); return(this); }
/// <summary> /// Exclude specified column /// </summary> /// <typeparam name="TTableColumn"></typeparam> /// <param name="column">Column</param> /// <returns>Fluent</returns> public ColumnListBuilder <TSourceData, TTableData> Except <TTableColumn>( Expression <Func <TTableData, TTableColumn> > column) { var info = LambdaHelpers.ParsePropertyLambda(column); if (!_colNames.Contains(info.Name)) { return(this); } _colNames.Remove(info.Name); return(this); }
/// <summary> /// Adds total calculator to table /// </summary> /// <param name="column">Table column to provide total with</param> /// <param name="calculator">Total calculator consuming ready-to-send table data and producing some value</param> /// <param name="valueFunction">Function that will be used to format total in the table. /// Function type is (v:any) => string /// v: value that you have calculated previously /// </param> /// <returns></returns> public TotalCalculatorBuilder <TSourceData, TTableData> AddTotal <TTableColumn, TTotalType>( Expression <Func <TTableData, TTableColumn> > column, Func <PowerTablesData <TSourceData, TTableData>, TTotalType> calculator, string valueFunction = null ) { var name = LambdaHelpers.ParsePropertyLambda(column).Name; _calculators.Add(name, calculator); _valueFunctions.Add(name, valueFunction); return(this); }
protected override IQueryable <TSourceData> DefaultFilter(IQueryable <TSourceData> source, IEnumerable <TVal> key) { var anyNulls = key.Any(c => c == null); var expr = ReflectionCache.CallContainsMethod(key.ToArray(), _sourceExpression); if (anyNulls) { var nullcmp = LambdaHelpers.ConstantBinaryLambdaExpression(ExpressionType.Equal, _sourceExpression, null); expr = LambdaHelpers.BinaryLambdaExpression(ExpressionType.Or, expr, nullcmp); } return(ReflectionCache.CallWhere(source, expr)); }
/// <summary> /// Retrieves column configurator /// </summary> /// <typeparam name="TColType">Column type</typeparam> /// <param name="column">Column</param> /// <returns>Corresponding column configurator</returns> public ColumnUsage <TSourceData, TTableData, TColType> Column <TColType>(Expression <Func <TTableData, TColType> > column) { var targetProperty = LambdaHelpers.ParsePropertyLambda(column); targetProperty = _tableColumnsDictionary[targetProperty.Name]; if (_configurators.ContainsKey(targetProperty)) { return((ColumnUsage <TSourceData, TTableData, TColType>)_configurators[targetProperty]); } ColumnUsage <TSourceData, TTableData, TColType> usage = new ColumnUsage <TSourceData, TTableData, TColType>(this, column, GetColumnConfiguration(targetProperty)); _configurators[targetProperty] = usage; return(usage); }
/// <summary> /// Adds client total calculator that produces count of rows /// </summary> /// <param name="conf">Configuration</param> /// <param name="column">Table column to provide total with</param> /// <param name="clientDataSet">Client data set to perform calculations on</param> /// <param name="template">Tempalte for total cell</param> /// <returns></returns> public static TotalCalculatorBuilder <TSourceData, TTableData> AddClientCount <TSourceData, TTableData, TTableColumn>( this TotalCalculatorBuilder <TSourceData, TTableData> conf, Expression <Func <TTableData, TTableColumn> > column, ClientDataSet clientDataSet, Action <CellTemplateBuilder> template = null ) where TTableData : new() { var name = LambdaHelpers.ParsePropertyLambda(column).Name; var function = string.Format("function(v){{ return v.{0}.length; }}", clientDataSet); conf.ClientCalculators.Add(name, function); if (template != null) { conf.AddTemplate(column, template); } return(conf); }
/// <summary> /// Adds client total calculator that produces maximum of supplied row values /// </summary> /// <param name="conf">Configuration</param> /// <param name="column">Table column to provide total with</param> /// <param name="expression">`{@}`-syntax expression minimum of which will be found</param> /// <param name="clientDataSet">Client data set to perform calculations on</param> /// <param name="template">Tempalte for total cell</param> /// <returns></returns> public static TotalCalculatorBuilder <TSourceData, TTableData> AddClientMax <TSourceData, TTableData, TTableColumn>( this TotalCalculatorBuilder <TSourceData, TTableData> conf, Expression <Func <TTableData, TTableColumn> > column, string expression, ClientDataSet clientDataSet, Action <CellTemplateBuilder> template = null ) where TTableData : new() { var name = LambdaHelpers.ParsePropertyLambda(column).Name; var function = CreateExtremumFunction(expression, true, clientDataSet); conf.ClientCalculators.Add(name, function); if (template != null) { conf.AddTemplate(column, template); } return(conf); }
protected override IQueryable <TSourceData> DefaultFilter(IQueryable <TSourceData> source, RangeTuple <TVal> key) { if (_sourceExpression == null) { throw new Exception("Trying to call FilterDelegate with null source expression"); } if (TreatEqualDateAsWholeDay) { if (typeof(TVal) == typeof(DateTime) || typeof(TVal) == typeof(DateTime?)) { if (key.HasFrom && key.HasTo) { var from = (DateTime)(object)key.From; var to = (DateTime)(object)key.To; if (from.Date == to.Date) { key.From = (TVal)(object)new DateTime(from.Year, from.Month, from.Day, 00, 00, 00); key.To = (TVal)(object)new DateTime(from.Year, from.Month, from.Day, 23, 59, 59); } } } } if (key.HasTo && key.HasFrom) { var between = LambdaHelpers.BetweenLambdaExpression(_sourceExpression, key.From.ExtractValueFromNullable(), key.To.ExtractValueFromNullable(), _inclusive); return(ReflectionCache.CallWhere(source, between)); } if (key.HasTo) { ExpressionType lt = _inclusive ? ExpressionType.LessThanOrEqual : ExpressionType.LessThan; var less = LambdaHelpers.ConstantBinaryLambdaExpression(lt, _sourceExpression, key.To.ExtractValueFromNullable()); return(ReflectionCache.CallWhere(source, less)); } if (key.HasFrom) { ExpressionType gt = _inclusive ? ExpressionType.GreaterThanOrEqual : ExpressionType.GreaterThan; var greater = LambdaHelpers.ConstantBinaryLambdaExpression(gt, _sourceExpression, key.From.ExtractValueFromNullable()); return(ReflectionCache.CallWhere(source, greater)); } return(source); }
/// <summary> /// Gets the Linq.Expression that will represent the AdvancedPaging query /// </summary> /// <param name="model">The AdvancedPageModel</param> /// <param name="genericType">The ParameterExpression that represents the Entity</param> /// <returns>The Expression for the AdvancedPage</returns> public Expression GetAdvancedSearchRestrictions(AdvancedPageModel model, ParameterExpression genericType) { Expression restrictions = null; if (model.AdvancedSearch == null) { return(restrictions); } foreach (var adv in model.AdvancedSearch) { var valueA = (object)(adv.IntValue.HasValue ? adv.IntValue.Value : adv.Value); var key = typeof(TEntity).GetPropertyExpressionFromSubProperty(adv.PropertyName, genericType); //if (key.Type == typeof(int)) //{ // key = ((MemberExpression)key).ConvertToType(TypeCode.String); //}; var propertyType = typeof(TEntity).FollowPropertyPath(adv.PropertyName).PropertyType; var value = valueA != null?Expression.Constant(LambdaHelpers.ChangeType(valueA, propertyType)) : null; Expression addedExpression = null; switch (adv.TypeOfSearch) { case AdvancedSearchType.IsNull: addedExpression = LambdaHelpers.NullableEqual(key, Expression.Constant(null)); break; case AdvancedSearchType.IsNotNull: addedExpression = LambdaHelpers.NullableNotEqual(key, Expression.Constant(null)); break; case AdvancedSearchType.In: addedExpression = LambdaHelpers.InExpression <TEntity>(genericType, adv.PropertyName, adv.ListValue); break; case AdvancedSearchType.Equal: addedExpression = LambdaHelpers.NullableEqual(key, value); break; case AdvancedSearchType.NotEqual: addedExpression = LambdaHelpers.NullableNotEqual(key, value); break; case AdvancedSearchType.LessThan: addedExpression = LambdaHelpers.NullableLessThan(key, value); break; case AdvancedSearchType.LessThanEqual: addedExpression = LambdaHelpers.NullableLessThanOrEqualTo(key, value); break; case AdvancedSearchType.GreaterThan: addedExpression = LambdaHelpers.NullableGreaterThan(key, value); break; case AdvancedSearchType.GreaterThanEqual: addedExpression = LambdaHelpers.NullableGreaterThanOrEqualTo(key, value); break; case AdvancedSearchType.Between: var lowerBound = Expression.GreaterThanOrEqual(key, Expression.Constant(Convert.ChangeType(adv.Value, propertyType))); var upperBound = Expression.LessThanOrEqual(key, Expression.Constant(Convert.ChangeType(adv.Value2, propertyType))); addedExpression = Expression.AndAlso(lowerBound, upperBound); break; case AdvancedSearchType.Like: default: var method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var someValue = Expression.Constant(valueA, typeof(string)); addedExpression = Expression.Call(key, method, someValue); break; } //add the new expression to the list restrictions = restrictions == null ? addedExpression : Expression.AndAlso(restrictions, addedExpression); } return(restrictions); }
/// <summary> /// Creates an Linq.Expression for the Searchable properties /// </summary> /// <param name="searchCriteria">The search string</param> /// <param name="genericType">The ParameterExpression that represents the Entity</param> /// <returns>Expression</returns> public Expression GetSearchRestrictions(object searchCriteria, ParameterExpression genericType) { Expression restrictions = null; if (searchCriteria != null) { foreach (var sc in typeof(TEntity).GetProperties()) { if (sc.IsDefined(typeof(SearchAbleAttribute), true)) { var searchAtts = (SearchAbleAttribute[])sc.GetCustomAttributes(typeof(SearchAbleAttribute), true); //walk each searchable attribute on the property foreach (var att in searchAtts) { var propertyName = string.IsNullOrEmpty(att.AliasName) ? sc.Name : att.AliasName; var propertyType = typeof(TEntity).FollowPropertyPath(propertyName).PropertyType; //check for special cases where a string cannot be converted to the type specifically if (FieldCanBeSearch(propertyType, searchCriteria)) { var key = typeof(TEntity).GetPropertyExpressionFromSubProperty(propertyName, genericType); var value = Expression.Constant(LambdaHelpers.ChangeType(searchCriteria, propertyType)); Expression addedExpression = null; switch (att.SearchType) { case SearchAbleType.Equal: addedExpression = LambdaHelpers.NullableEqual(key, value); break; case SearchAbleType.NotEqual: addedExpression = LambdaHelpers.NullableNotEqual(key, value); break; case SearchAbleType.GreaterThan: addedExpression = LambdaHelpers.NullableGreaterThan(key, value); break; case SearchAbleType.GreaterThanEqual: addedExpression = LambdaHelpers.NullableGreaterThanOrEqualTo(key, value); break; case SearchAbleType.LessThan: addedExpression = LambdaHelpers.NullableLessThan(key, value); break; case SearchAbleType.LessThanEqual: addedExpression = LambdaHelpers.NullableLessThanOrEqualTo(key, value); break; case SearchAbleType.Contains: var method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var someValue = Expression.Constant(searchCriteria, typeof(string)); addedExpression = Expression.Call(key, method, someValue); break; case SearchAbleType.StartsWith: var methodsw = typeof(string).GetMethod("StartsWith", new[] { typeof(string) }); var swValue = Expression.Constant(searchCriteria, typeof(string)); addedExpression = Expression.Call(key, methodsw, swValue); break; case SearchAbleType.EndsWith: var methodew = typeof(string).GetMethod("EndsWith", new[] { typeof(string) }); var ewValue = Expression.Constant(searchCriteria, typeof(string)); addedExpression = Expression.Call(key, methodew, ewValue); break; } //add the new expression to the list of restrictions restrictions = restrictions == null ? addedExpression : Expression.OrElse(restrictions, addedExpression); } } } } } return(restrictions); }
internal ColumnUsage(Configurator <TSourceData, TTableData> configurator, Expression <Func <TTableData, TTableColumn> > tableColumnExpression, ColumnConfiguration columnConfiguration) { _columnProperty = LambdaHelpers.ParsePropertyLambda(tableColumnExpression); _configurator = configurator; _columnConfiguration = columnConfiguration; }
protected override IQueryable <TSourceData> DefaultFilter(IQueryable <TSourceData> source, TFilteringKey key) { LambdaExpression lambda = LambdaHelpers.ConstantBinaryLambdaExpression(ExpressionType.Equal, _sourceExpression, key.ExtractValueFromNullable()); return(ReflectionCache.CallWhere(source, lambda)); }
/// <summary> /// Places select checkboxes within every row /// </summary> /// <typeparam name="TSourceData"></typeparam> /// <typeparam name="TTableData"></typeparam> /// <typeparam name="TTableColumn"></typeparam> /// <param name="conf">Table configuration</param> /// <param name="column">Column that will be used as ID provider for select checkbox</param> /// <param name="selectAllBehavior">Behavior for "Select All" button</param> /// <param name="ui">UI configuration</param> /// <returns></returns> public static Configurator <TSourceData, TTableData> Checkboxify <TSourceData, TTableData, TTableColumn>( this Configurator <TSourceData, TTableData> conf, Expression <Func <TTableData, TTableColumn> > column, SelectAllBehavior selectAllBehavior = SelectAllBehavior.OnlyIfAllDataVisible, Action <PluginConfigurationWrapper <CheckboxifyClientConfig> > ui = null ) where TTableData : new() { var targetProp = LambdaHelpers.ParsePropertyLambda(column); var colName = targetProp.Name; CheckboxifyClientConfig ccc = new CheckboxifyClientConfig { SelectionColumnName = colName }; switch (selectAllBehavior) { case SelectAllBehavior.Disabled: ccc.EnableSelectAll = false; break; case SelectAllBehavior.CurrentPage: //ccc.ResetOnReload = true; ccc.EnableSelectAll = true; break; case SelectAllBehavior.OnlyIfAllDataVisible: ccc.EnableSelectAll = true; ccc.SelectAllOnlyIfAllData = true; break; case SelectAllBehavior.AllLocal: ccc.EnableSelectAll = true; ccc.SelectAllSelectsClientUndisplayedData = true; break; case SelectAllBehavior.InvolveServer: try { var p = typeof(TSourceData).GetProperty(colName); if (p.PropertyType != targetProp.PropertyType) { throw new Exception(); } } catch (Exception ex) { throw new Exception( String.Format( "In case of using SelectAllBehavior.InvolveServer, please assure that property {0} exists on both {1} and {2} types and represents same data", colName, typeof(TSourceData).FullName, typeof(TTableData).FullName)); } ccc.EnableSelectAll = true; ccc.SelectAllSelectsServerUndisplayedData = true; conf.RegisterCommandHandler <CheckboxifyCommandHandler>("checkboxify_all"); break; } conf.TableConfiguration.ReplacePluginConfig(PluginId, ccc); conf.TableConfiguration.UpdatePluginConfig(PluginId, ui); return(conf); }