Skip to content

Commit

Permalink
add StringSnippetToken
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Apr 12, 2023
1 parent 45456fd commit e8c2011
Show file tree
Hide file tree
Showing 12 changed files with 407 additions and 180 deletions.
9 changes: 9 additions & 0 deletions Signum.Engine/Basics/QueryLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ static QueryLogic()
EntityPropertyToken.DateTimeKindFunc = ept =>
Schema.Current.Settings.FieldAttribute<DbTypeAttribute>(ept.PropertyRoute)?.DateTimeKind ?? DateTimeKind.Unspecified;
EntityPropertyToken.HasFullTextIndexFunc = ept => Schema.Current.HasFullTextIndex(ept.PropertyRoute);
EntityPropertyToken.HasSnippetFunc = ept =>
{
if (ept.Type != typeof(string))
return false;

var field = Schema.Current.TryField(ept.PropertyRoute);

return field is FieldValue fv && (fv.Size == null || fv.Size > 200);
};

ExtensionToken.BuildExtension = (parentType, key, parentExpression) => Expressions.BuildExtension(parentType, key, parentExpression);
QueryToken.ImplementedByAllSubTokens = GetImplementedByAllSubTokens;
Expand Down
35 changes: 21 additions & 14 deletions Signum.Engine/DynamicQuery/DQueryable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Signum.Utilities;
using System.Runtime.ConstrainedExecution;
using Signum.Entities.DynamicQuery.Tokens;
using System.Runtime.CompilerServices;

namespace Signum.Engine.DynamicQuery;

Expand Down Expand Up @@ -74,15 +75,15 @@ public static class DQueryable
{
#region ToDQueryable

public static DQueryable<T> ToDQueryable<T>(this IQueryable<T> query, QueryDescription description)
public static DQueryable<T> ToDQueryable<T>(this IQueryable<T> query, QueryDescription description, List<Filter>? filters = null)
{
ParameterExpression pe = Expression.Parameter(typeof(T));

var dic = description.Columns.ToDictionary(
cd => (QueryToken)new ColumnToken(cd, description.QueryName),
cd => new ExpressionBox(Expression.PropertyOrField(pe, cd.Name).BuildLiteNullifyUnwrapPrimaryKey(cd.PropertyRoutes!)));

return new DQueryable<T>(query, new BuildExpressionContext(typeof(T), pe, dic));
return new DQueryable<T>(query, new BuildExpressionContext(typeof(T), pe, dic, filters));
}


Expand Down Expand Up @@ -166,7 +167,8 @@ static LambdaExpression SelectTupleConstructor(BuildExpressionContext context, H
{
Token = t,
Expr = TupleReflection.TupleChainProperty(pe, i)
}).ToDictionary(t => t.Token!, t => new ExpressionBox(t.Expr)));
}).ToDictionary(t => t.Token!, t => new ExpressionBox(t.Expr)),
context.Filters);

return Expression.Lambda(ctor, context.Parameter);
}
Expand Down Expand Up @@ -233,7 +235,7 @@ static LambdaExpression SubQueryConstructor(BuildExpressionContext context, Node
mlistElementRoute: eptML != null ? cet.GetPropertyRoute() : null
)
}
});
}, context.Filters);

var subQueryExp = SubQueryConstructor(subQueryCtx, child, out var newSubContext);

Expand Down Expand Up @@ -266,7 +268,7 @@ static LambdaExpression SubQueryConstructor(BuildExpressionContext context, Node
replacements.Add(collectionElementToken, new ExpressionBox(exp, subQueryContext: subContext[i]));
}

newContext = new BuildExpressionContext(ctor.Type, pe, replacements);
newContext = new BuildExpressionContext(ctor.Type, pe, replacements, context.Filters);

return Expression.Lambda(ctor, context.Parameter);
}
Expand Down Expand Up @@ -298,15 +300,15 @@ public static DEnumerable<T> ToDEnumerable<T>(this DQueryable<T> query)
return new DEnumerable<T>(Untyped.ToList(query.Query, query.Context.ElementType), query.Context);
}

public static DEnumerable<T> ToDEnumerable<T>(this IEnumerable<T> query, QueryDescription description)
public static DEnumerable<T> ToDEnumerable<T>(this IEnumerable<T> query, QueryDescription description, List<Filter>? filters = null)
{
ParameterExpression pe = Expression.Parameter(typeof(T));

var dic = description.Columns.ToDictionary(
cd => (QueryToken)new ColumnToken(cd, description.QueryName),
cd => new ExpressionBox(Expression.PropertyOrField(pe, cd.Name).BuildLiteNullifyUnwrapPrimaryKey(cd.PropertyRoutes!)));

return new DEnumerable<T>(query, new BuildExpressionContext(typeof(T), pe, dic));
return new DEnumerable<T>(query, new BuildExpressionContext(typeof(T), pe, dic, filters));
}

public static DEnumerableCount<T> WithCount<T>(this DEnumerable<T> result, int? totalElements)
Expand Down Expand Up @@ -381,7 +383,7 @@ public static DQueryable<T> JoinWith<T>(this DQueryable<T> query, FilterFullText

newReplacements.AddRange(fft.Tokens, keySelector: t => new FullTextRankToken(t), valueSelector: t => new ExpressionBox(rank, mlistElementRoute: null));

var newContext = new BuildExpressionContext(ctor.Type, parameter, newReplacements);
var newContext = new BuildExpressionContext(ctor.Type, parameter, newReplacements, query.Context.Filters);

return new DQueryable<T>(join, newContext);
}
Expand Down Expand Up @@ -471,7 +473,7 @@ private static void SelectManyConstructor(BuildExpressionContext context, Collec
mlistElementRoute: eptML != null ? cet.GetPropertyRoute() : null
));

newContext = new BuildExpressionContext(ctor.Type, parameter, newReplacements);
newContext = new BuildExpressionContext(ctor.Type, parameter, newReplacements, context.Filters);
}

public static DEnumerableCount<T> SelectManySubQueries<T>(this DEnumerableCount<T> collection)
Expand Down Expand Up @@ -558,7 +560,7 @@ static void SelectManySubQueriesConstructor(BuildExpressionContext context, Coll
subQueryContext: kvp.Value.SubQueryContext)
)));

newContext = new BuildExpressionContext(ctor.Type, parameter, newReplacements);
newContext = new BuildExpressionContext(ctor.Type, parameter, newReplacements, context.Filters);
}


Expand All @@ -577,7 +579,11 @@ public static DQueryable<T> Where<T>(this DQueryable<T> query, List<Filter> filt
if (predicate == null)
return query;

return new DQueryable<T>(Untyped.Where(query.Query, predicate), query.Context);
var context = query.Context;

var newContext = new BuildExpressionContext(context.ElementType, context.Parameter, context.Replacements, context.Filters.EmptyIfNull().Concat(filters).ToList());

return new DQueryable<T>(Untyped.Where(query.Query, predicate), newContext);
}

public static DQueryable<T> Where<T>(this DQueryable<T> query, Expression<Func<object, bool>> filter)
Expand Down Expand Up @@ -958,7 +964,7 @@ static LambdaExpression ResultSelectSelectorAndContext(BuildExpressionContext co
{
if (isQueryable)
{
var tempContext = new BuildExpressionContext(keyTupleType, pk, rootKeyTokens.Select((kqt, i) => KeyValuePair.Create(kqt, new ExpressionBox(TupleReflection.TupleChainProperty(pk, i)))).ToDictionary());
var tempContext = new BuildExpressionContext(keyTupleType, pk, rootKeyTokens.Select((kqt, i) => KeyValuePair.Create(kqt, new ExpressionBox(TupleReflection.TupleChainProperty(pk, i)))).ToDictionary(), context.Filters);
resultExpressions.AddRange(redundantKeyTokens.Select(t => KeyValuePair.Create(t, t.BuildExpression(tempContext, searchToArray: true))));
}
else
Expand All @@ -985,7 +991,8 @@ static LambdaExpression ResultSelectSelectorAndContext(BuildExpressionContext co

ParameterExpression pg = Expression.Parameter(resultConstructor.Type, "gr");
newContext = new BuildExpressionContext(resultConstructor.Type, pg,
resultExpressions.Keys.Select((t, i) => KeyValuePair.Create(t, new ExpressionBox(TupleReflection.TupleChainProperty(pg, i)))).ToDictionary());
resultExpressions.Keys.Select((t, i) => KeyValuePair.Create(t, new ExpressionBox(TupleReflection.TupleChainProperty(pg, i)))).ToDictionary(),
context.Filters);

return Expression.Lambda(resultConstructor, pk, pe);
}
Expand Down Expand Up @@ -1174,7 +1181,7 @@ public static DEnumerable<T> ReplaceColumns<T>(this DEnumerable<T> query, params
ctor.Type, pe,
tokens
.Select((t, i) => new { Token = t, Expr = TupleReflection.TupleChainProperty(pe, i) })
.ToDictionary(t => t.Token!, t => new ExpressionBox(t.Expr)));
.ToDictionary(t => t.Token!, t => new ExpressionBox(t.Expr)), query.Context.Filters);

var selector = Expression.Lambda(ctor, query.Context.Parameter);

Expand Down
72 changes: 64 additions & 8 deletions Signum.Entities/DynamicQuery/Filter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ public abstract class Filter

public abstract IEnumerable<QueryToken> GetTokens();

public abstract Filter ToFullText();
public abstract Filter? ToFullText();

public abstract bool IsAggregate();

public abstract IEnumerable<string> GetKeywords();

protected Expression GetExpressionWithAnyAll(BuildExpressionContext ctx, CollectionAnyAllToken anyAll)
{
var ept = MListElementPropertyToken.AsMListEntityProperty(anyAll.Parent!);
Expand Down Expand Up @@ -73,6 +75,7 @@ public static void SetIsTable(List<Filter> filters, IEnumerable<QueryToken> allT
fg.SetIsTable(fullTextOrders, false);
}
}

}

public class FilterGroup : Filter
Expand Down Expand Up @@ -116,7 +119,7 @@ public override Expression GetExpression(BuildExpressionContext ctx)
return GetExpressionWithAnyAll(ctx, anyAll);
}

public override Filter ToFullText()
public override Filter? ToFullText()
{
if (this.GroupOperation == FilterGroupOperation.Or)
{
Expand All @@ -133,11 +136,15 @@ public override Filter ToFullText()
Operation = a.Operation.ToFullTextFilterOperation(),
a.Value,
})
.Where(a => a.Key.Value is string s && s.Length > 0)
.Select(gr => new FilterFullText(gr.Key.Operation, gr.Select(a => a.Token).ToList(), (string)gr.Key.Value!))
.ToList();

filters.RemoveAll(aa => fullTextFilter.Contains(aa));

if (filters.Count == 0 && groups.Count == 0)
return null;

if (filters.Count == 0 && groups.Count == 1)
return groups.SingleEx();

Expand All @@ -147,7 +154,15 @@ public override Filter ToFullText()
}
else
{
return new FilterGroup(FilterGroupOperation.And, this.Token, this.Filters.Select(a => a.ToFullText()).ToList());
var filters = this.Filters.Select(a => a.ToFullText()).NotNull().ToList();

if (filters.Count == 0)
return null;

if (filters.Count == 1)
return filters.SingleEx();

return new FilterGroup(FilterGroupOperation.And, this.Token, filters);
}
}

Expand Down Expand Up @@ -178,6 +193,8 @@ internal void SetIsTable(IEnumerable<QueryToken> fullTextOrders, bool isOuter)
fg.SetIsTable(fullTextOrders, isOuter);
}
}

public override IEnumerable<string> GetKeywords() => Enumerable.Empty<string>();
}


Expand All @@ -204,10 +221,14 @@ public override IEnumerable<QueryToken> GetTokens()
yield return Token;
}

public override Filter ToFullText()
public override Filter? ToFullText()
{
if (Operation.IsFullTextFilterOperation())
return new FilterFullText(Operation.ToFullTextFilterOperation(), new List<QueryToken> { Token }, (string?)Value!);
{
if (Value is string s && s.Length > 0)
return new FilterFullText(Operation.ToFullTextFilterOperation(), new List<QueryToken> { Token }, s);
return null;
}

return this;
}
Expand Down Expand Up @@ -323,6 +344,34 @@ public override string ToString()
{
return "{0} {1} {2}".FormatWith(Token.FullKey(), Operation, Value);
}

public override IEnumerable<string> GetKeywords()
{
switch (this.Operation)
{
case FilterOperation.EqualTo:
case FilterOperation.Contains:
case FilterOperation.StartsWith:
case FilterOperation.EndsWith:
{
if(this.Value is string s)
return new[] { s };

break;
}
case FilterOperation.Like:
{
if (this.Value is string s)
return s.SplitNoEmpty("%");

break;
}
case FilterOperation.IsIn:
return ((IEnumerable)this.Value!).OfType<string>();
}

return Enumerable.Empty<string>();
}
}


Expand Down Expand Up @@ -373,9 +422,6 @@ public FilterFullText(FullTextFilterOperation operation, List<QueryToken> tokens
if (tokens.IsNullOrEmpty())
throw new ArgumentNullException(nameof(tokens));

if (value.IsNullOrEmpty())
throw new ArgumentNullException(nameof(tokens));

Tokens = tokens;
Operation = operation;
SearchCondition = value;
Expand Down Expand Up @@ -438,6 +484,16 @@ public static List<FilterFullText> TableFilters(List<Filter> filters)
{
return filters.SelectMany(a => a.GetAllFilters()).OfType<FilterFullText>().Where(a => a.IsTable).ToList();
}

public override IEnumerable<string> GetKeywords()
{
if (this.Operation == FullTextFilterOperation.FreeText)
return this.SearchCondition.Split(" ");

return this.SearchCondition.Split(new string[] { "AND", "OR", "NOT", "NEAR", "(", ")", "*" }, StringSplitOptions.RemoveEmptyEntries)
.Select(a => a.Trim(' ').Trim('\'', '"'))
.Where(a => a.Length > 0);
}
}

public static class FullTextFilterOperationExtensions
Expand Down
10 changes: 10 additions & 0 deletions Signum.Entities/DynamicQuery/Order.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

using Signum.Entities.DynamicQuery.Tokens;

namespace Signum.Entities.DynamicQuery;

public class Order: IEquatable<Order>
Expand All @@ -23,6 +25,14 @@ public override string ToString()

internal Order ToFullText()
{
if(this.Token is StringSnippetToken s)
{
if (s.Parent is EntityPropertyToken ep && ep.HasFullTextIndex)
return new Order(new FullTextRankToken(ep), this.OrderType == OrderType.Ascending ? OrderType.Descending : OrderType.Ascending);

return new Order(s.Parent!, this.OrderType);
}

return this;
}
}
Expand Down
2 changes: 0 additions & 2 deletions Signum.Entities/DynamicQuery/QueryUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ public static FilterType GetFilterType(Type type)
}
}

static Func<PropertyRoute, bool> HasFullTextSearch = null!;

public static IList<FilterOperation> GetFilterOperations(QueryToken token)
{
var filtertype = GetFilterType(token.Type);
Expand Down
8 changes: 4 additions & 4 deletions Signum.Entities/DynamicQuery/Requests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public override QueryRequest CombineFullTextFilters()
QueryUrl = this.QueryUrl,
Columns = this.Columns,
GroupResults = this.GroupResults,
Filters = this.Filters.Select(f => f.ToFullText()).ToList(),
Filters = this.Filters.Select(f => f.ToFullText()).NotNull().ToList(),
Orders = this.Orders.Select(o => o.ToFullText()).ToList(),
Pagination = this.Pagination,
SystemTime = this.SystemTime,
Expand Down Expand Up @@ -209,7 +209,7 @@ public override QueryValueRequest CombineFullTextFilters()
{
QueryName = this.QueryName,
QueryUrl = this.QueryUrl,
Filters = this.Filters.Select(f => f.ToFullText()).ToList(),
Filters = this.Filters.Select(f => f.ToFullText()).NotNull().ToList(),
SystemTime = this.SystemTime,
ValueToken = this.ValueToken,
MultipleValues = this.MultipleValues
Expand Down Expand Up @@ -241,7 +241,7 @@ public override UniqueEntityRequest CombineFullTextFilters()
{
QueryName = this.QueryName,
QueryUrl = this.QueryUrl,
Filters = this.Filters.Select(f => f.ToFullText()).ToList(),
Filters = this.Filters.Select(f => f.ToFullText()).NotNull().ToList(),
Orders = this.Orders.Select(f => f.ToFullText()).ToList(),
UniqueType = this.UniqueType,
};
Expand Down Expand Up @@ -274,7 +274,7 @@ public override QueryEntitiesRequest CombineFullTextFilters()
{
QueryName = this.QueryName,
QueryUrl = this.QueryUrl,
Filters = this.Filters.Select(f => f.ToFullText()).ToList(),
Filters = this.Filters.Select(f => f.ToFullText()).NotNull().ToList(),
Orders = this.Orders.Select(f => f.ToFullText()).ToList(),
Count = Count
};
Expand Down
Loading

0 comments on commit e8c2011

Please sign in to comment.