From 2ec0dd7c53067c34e01e4570968ae9e14263a65e Mon Sep 17 00:00:00 2001 From: Olmo del Corral Cano Date: Thu, 18 Aug 2022 15:33:19 +0200 Subject: [PATCH] add EntityTypeToken --- .../Linq/ExpressionVisitor/QueryBinder.cs | 58 +++++++++--- .../DynamicQuery/Tokens/EntityTypeToken.cs | 93 +++++++++++++++++++ .../DynamicQuery/Tokens/QueryToken.cs | 8 +- .../Scripts/Signum.Entities.DynamicQuery.ts | 1 + Signum.Test/LinqProvider/GetTypeAndNewTest.cs | 87 ++++++++++++++++- 5 files changed, 231 insertions(+), 16 deletions(-) create mode 100644 Signum.Entities/DynamicQuery/Tokens/EntityTypeToken.cs diff --git a/Signum.Engine/Linq/ExpressionVisitor/QueryBinder.cs b/Signum.Engine/Linq/ExpressionVisitor/QueryBinder.cs index 0c622a487b..a361eee71b 100644 --- a/Signum.Engine/Linq/ExpressionVisitor/QueryBinder.cs +++ b/Signum.Engine/Linq/ExpressionVisitor/QueryBinder.cs @@ -1666,6 +1666,38 @@ public Expression BindMethodCall(MethodCallExpression m) return tablePeriod; } + if(m.Method.DeclaringType == typeof(TypeEntityExtensions) && m.Method.Name == nameof(TypeEntityExtensions.ToTypeEntity)) + { + var arg = m.Arguments[0]; + + + if (arg is TypeEntityExpression type) + { + var id = Condition(Expression.NotEqual(type.ExternalId, NullId(type.ExternalId.ValueType)), + ifTrue: Expression.Constant(TypeLogic.TypeToId.GetOrThrow(type.TypeValue).Object), + ifFalse: Expression.Constant(null, PrimaryKey.Type(typeof(TypeEntity)).Nullify())); + + return new EntityExpression(typeof(TypeEntity), new PrimaryKeyExpression(id), null, null, null, null, null, false); + } + + if (arg is TypeImplementedByExpression typeIB) + { + var id = typeIB.TypeImplementations.Aggregate( + (Expression)Expression.Constant(null, PrimaryKey.Type(typeof(TypeEntity)).Nullify()), + (acum, kvp) => Condition(Expression.NotEqual(kvp.Value, NullId(kvp.Value.Value.Type)), + ifTrue: Expression.Constant(TypeLogic.TypeToId.GetOrThrow(kvp.Key).Object), + ifFalse: acum)); + + return new EntityExpression(typeof(TypeEntity), new PrimaryKeyExpression(id), null, null, null, null, null, false); + } + + if (arg is TypeImplementedByAllExpression typeIBA) + { + return new EntityExpression(typeof(TypeEntity), typeIBA.TypeColumn, null, null, null, null, null, false); + } + + } + Expression PartialEval(Expression ee) { if (m.Method.IsExtensionMethod()) @@ -1678,20 +1710,22 @@ Expression PartialEval(Expression ee) } } - if (source is TypeEntityExpression type) { - return Condition(Expression.NotEqual(type.ExternalId, NullId(type.ExternalId.ValueType)), - ifTrue: PartialEval(Expression.Constant(type.TypeValue)), - ifFalse: Expression.Constant(null, m.Type)); - } + if (source is TypeEntityExpression type) + { + return Condition(Expression.NotEqual(type.ExternalId, NullId(type.ExternalId.ValueType)), + ifTrue: PartialEval(Expression.Constant(type.TypeValue)), + ifFalse: Expression.Constant(null, m.Type)); + } - if(source is TypeImplementedByExpression typeIB) - { - return typeIB.TypeImplementations.Aggregate( - (Expression)Expression.Constant(null, m.Type), - (acum, kvp) => Condition(Expression.NotEqual(kvp.Value, NullId(kvp.Value.Value.Type)), - ifTrue: PartialEval(Expression.Constant(kvp.Key)), - ifFalse: acum)); + if (source is TypeImplementedByExpression typeIB) + { + return typeIB.TypeImplementations.Aggregate( + (Expression)Expression.Constant(null, m.Type), + (acum, kvp) => Condition(Expression.NotEqual(kvp.Value, NullId(kvp.Value.Value.Type)), + ifTrue: PartialEval(Expression.Constant(kvp.Key)), + ifFalse: acum)); + } } return m; diff --git a/Signum.Entities/DynamicQuery/Tokens/EntityTypeToken.cs b/Signum.Entities/DynamicQuery/Tokens/EntityTypeToken.cs new file mode 100644 index 0000000000..1379948828 --- /dev/null +++ b/Signum.Entities/DynamicQuery/Tokens/EntityTypeToken.cs @@ -0,0 +1,93 @@ +using Signum.Entities.Basics; +using Signum.Utilities.Reflection; + +namespace Signum.Entities.DynamicQuery; + + +public class EntityTypeToken : QueryToken +{ + QueryToken parent; + public override QueryToken? Parent => parent; + + internal EntityTypeToken(QueryToken parent) + { + this.parent = parent ?? throw new ArgumentNullException(nameof(parent)); + + this.Priority = 10; + } + + public override Type Type + { + get { return typeof(TypeEntity).BuildLite(); } + } + + public override string ToString() + { + return "[" + QueryTokenMessage.EntityType.NiceToString() + "]"; + } + + public override string Key + { + get { return "[EntityType]"; } + } + + static MethodInfo miTypeEntity = ReflectionTools.GetMethodInfo(() => TypeEntityExtensions.ToTypeEntity(null!)); + + protected override Expression BuildExpressionInternal(BuildExpressionContext context) + { + Expression baseExpression = parent.BuildExpression(context); + + Expression entityType = Expression.Property(baseExpression, "EntityType"); + + Expression typeEntity = Expression.Call(miTypeEntity, entityType); + + return typeEntity.BuildLite(); + } + + protected override List SubTokensOverride(SubTokensOptions options) + { + return SubTokensBase(typeof(TypeEntity), options, GetImplementations()); + } + + public override string? Format + { + get { return null; } + } + + public override string? Unit + { + get { return null; } + } + + public override Implementations? GetImplementations() + { + return Implementations.By(typeof(TypeEntity)); + } + + public override string? IsAllowed() + { + var parentAllowed = this.parent.IsAllowed(); + var routeAllowed = GetPropertyRoute()!.IsAllowed(); + + if (parentAllowed.HasText() && routeAllowed.HasText()) + QueryTokenMessage.And.NiceToString().Combine(parentAllowed, routeAllowed); + + return parentAllowed ?? routeAllowed; + } + + public override PropertyRoute? GetPropertyRoute() + { + return PropertyRoute.Root(typeof(TypeEntity)); + } + + public override string NiceName() + { + return QueryTokenMessage._0Of1.NiceToString().FormatWith(QueryTokenMessage.EntityType.NiceToString(), parent.ToString()); + } + + public override QueryToken Clone() + { + return new EntityTypeToken(parent.Clone()); + } +} + diff --git a/Signum.Entities/DynamicQuery/Tokens/QueryToken.cs b/Signum.Entities/DynamicQuery/Tokens/QueryToken.cs index 6a1048666a..90e25bd883 100644 --- a/Signum.Entities/DynamicQuery/Tokens/QueryToken.cs +++ b/Signum.Entities/DynamicQuery/Tokens/QueryToken.cs @@ -196,7 +196,7 @@ protected List SubTokensBase(Type type, SubTokensOptions options, Im if (cleanType.IsIEntity()) { if (implementations!.Value.IsByAll) - return ImplementedByAllSubTokens(this, type, options); // new[] { EntityPropertyToken.IdProperty(this) }; + return ImplementedByAllSubTokens(this, type, options).PreAnd(new EntityTypeToken(this)).ToList().AndHasValue(this); // new[] { EntityPropertyToken.IdProperty(this) }; var onlyType = implementations.Value.Types.Only(); @@ -211,7 +211,7 @@ protected List SubTokensBase(Type type, SubTokensOptions options, Im .NotNull() .Concat(EntityProperties(onlyType)).ToList().AndHasValue(this); - return implementations.Value.Types.Select(t => (QueryToken)new AsTypeToken(this, t)).ToList().AndHasValue(this); + return implementations.Value.Types.Select(t => (QueryToken)new AsTypeToken(this, t)).PreAnd(new EntityTypeToken(this)).ToList().AndHasValue(this); } if (type.IsEmbeddedEntity() || type.IsModelEntity()) @@ -696,5 +696,7 @@ public enum QueryTokenMessage RowId, CellOperation, - ContainerOfCellOperations + ContainerOfCellOperations, + [Description("Entity Type")] + EntityType } diff --git a/Signum.React/Scripts/Signum.Entities.DynamicQuery.ts b/Signum.React/Scripts/Signum.Entities.DynamicQuery.ts index 97e476564a..c27fe284f3 100644 --- a/Signum.React/Scripts/Signum.Entities.DynamicQuery.ts +++ b/Signum.React/Scripts/Signum.Entities.DynamicQuery.ts @@ -133,6 +133,7 @@ export module QueryTokenMessage { export const RowId = new MessageKey("QueryTokenMessage", "RowId"); export const CellOperation = new MessageKey("QueryTokenMessage", "CellOperation"); export const ContainerOfCellOperations = new MessageKey("QueryTokenMessage", "ContainerOfCellOperations"); + export const EntityType = new MessageKey("QueryTokenMessage", "EntityType"); } export const RefreshMode = new EnumType("RefreshMode"); diff --git a/Signum.Test/LinqProvider/GetTypeAndNewTest.cs b/Signum.Test/LinqProvider/GetTypeAndNewTest.cs index 5ec8a2092e..fb013c8d4b 100644 --- a/Signum.Test/LinqProvider/GetTypeAndNewTest.cs +++ b/Signum.Test/LinqProvider/GetTypeAndNewTest.cs @@ -1,3 +1,4 @@ +using Signum.Entities.Basics; using Signum.Utilities.DataStructures; using System.IO; using System.Text; @@ -101,7 +102,91 @@ public void TestIsNew() select new { f.Name }).ToList(); Assert.NotEmpty(list); - } + } + + [Fact] + public void SelectToTypeEntity() + { + var list = (from f in Database.Query() + select f.GetType().ToTypeEntity()) + .ToList(); + Assert.NotEmpty(list); + } + + [Fact] + public void WhereToTypeEntity() + { + var list = (from f in Database.Query() + where f.GetType().ToTypeEntity().Is(typeof(ArtistEntity).ToTypeEntity()) + select f) + .ToList(); + + + Assert.NotEmpty(list); + } + + [Fact] + public void SelectToTypeEntityIB() + { + var list = (from f in Database.Query() + select f.LastAward!.GetType().ToTypeEntity()) + .ToList(); + + Assert.NotEmpty(list); + } + + [Fact] + public void WhereToTypeEntityIB() + { + var list = (from f in Database.Query() + where f.LastAward!.GetType().ToTypeEntity().Is(typeof(GrammyAwardEntity).ToTypeEntity()) + select f) + .ToList(); + Assert.NotEmpty(list); + } + + [Fact] + public void WhereToTypeEntityIBGroupBy() + { + var list = (from f in Database.Query() + group f by f.LastAward!.GetType().ToTypeEntity() into g + select new { g.Key, Count = g.Count() }) + .ToList(); + + Assert.NotEmpty(list); + } + + [Fact] + public void SelectToTypeEntityIBA() + { + var list = (from f in Database.Query() + select f.Target.GetType().ToTypeEntity()) + .ToList(); + + Assert.NotEmpty(list); + } + + [Fact] + public void WhereToTypeEntityIBA() + { + var list = (from f in Database.Query() + where f.Target.GetType().ToTypeEntity().Is(typeof(ArtistEntity).ToTypeEntity()) + select f) + .ToList(); + + Assert.NotEmpty(list); + } + + [Fact] + public void WhereToTypeEntityIBAGroupBy() + { + var list = (from f in Database.Query() + group f by f.Target.GetType().ToTypeEntity() into g + select new { g.Key, Count = g.Count() }) + .ToList(); + + Assert.NotEmpty(list); + } }