Skip to content

Commit

Permalink
add EntityTypeToken
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Aug 18, 2022
1 parent adfd004 commit 2ec0dd7
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 16 deletions.
58 changes: 46 additions & 12 deletions Signum.Engine/Linq/ExpressionVisitor/QueryBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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;
Expand Down
93 changes: 93 additions & 0 deletions Signum.Entities/DynamicQuery/Tokens/EntityTypeToken.cs
Original file line number Diff line number Diff line change
@@ -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<QueryToken> 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());
}
}

8 changes: 5 additions & 3 deletions Signum.Entities/DynamicQuery/Tokens/QueryToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ protected List<QueryToken> 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();

Expand All @@ -211,7 +211,7 @@ protected List<QueryToken> 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())
Expand Down Expand Up @@ -696,5 +696,7 @@ public enum QueryTokenMessage
RowId,

CellOperation,
ContainerOfCellOperations
ContainerOfCellOperations,
[Description("Entity Type")]
EntityType
}
1 change: 1 addition & 0 deletions Signum.React/Scripts/Signum.Entities.DynamicQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>("RefreshMode");
Expand Down
87 changes: 86 additions & 1 deletion Signum.Test/LinqProvider/GetTypeAndNewTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Signum.Entities.Basics;
using Signum.Utilities.DataStructures;
using System.IO;
using System.Text;
Expand Down Expand Up @@ -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<ArtistEntity>()
select f.GetType().ToTypeEntity())
.ToList();

Assert.NotEmpty(list);
}

[Fact]
public void WhereToTypeEntity()
{
var list = (from f in Database.Query<ArtistEntity>()
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<BandEntity>()
select f.LastAward!.GetType().ToTypeEntity())
.ToList();

Assert.NotEmpty(list);
}

[Fact]
public void WhereToTypeEntityIB()
{
var list = (from f in Database.Query<BandEntity>()
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<BandEntity>()
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<NoteWithDateEntity>()
select f.Target.GetType().ToTypeEntity())
.ToList();

Assert.NotEmpty(list);
}

[Fact]
public void WhereToTypeEntityIBA()
{
var list = (from f in Database.Query<NoteWithDateEntity>()
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<NoteWithDateEntity>()
group f by f.Target.GetType().ToTypeEntity() into g
select new { g.Key, Count = g.Count() })
.ToList();

Assert.NotEmpty(list);
}
}

2 comments on commit 2ec0dd7

@olmobrutall
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presenting EntityTypeToken

The QueryToken family (aka the DropdownList sequence that you use to create filters or columns in the SearchControl, Chart, UserQuery, WordTemplate, EmailTemplate, etc..) has a new member: EntityTypeToken.

image

This token, shown as [Entity Type] in english, is avalable in any ImplementedBy and ImplementedByAll reference and points to the TypeEntity associated to the System.Type of the value stored in this reference.

Since is a TypeEntity you can drill-down an access fields like ClassName o Namespace.

image

If [Entity Type] is not in the available list of options of an ImplementedBy and ImplementedByAll, check your AuthRules! the user has to read access to the TypeEntity type.

@mehdy-karimpour
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! 👍

Please sign in to comment.