Skip to content

Commit

Permalink
fix IsLocalDateTime and use it in FilterJsonConverter
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Feb 16, 2023
1 parent eab66f3 commit 68914f6
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 3 deletions.
3 changes: 3 additions & 0 deletions Signum.Engine/Basics/QueryLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ static QueryLogic()
{
QueryToken.StaticEntityExtensions = parent => Expressions.GetExtensionsTokens(parent);
QueryToken.DynamicEntityExtensions = parent => Expressions.GetExtensionsWithParameterTokens(parent);
QueryToken.IsLocalDateTime = qt =>
qt is NetPropertyToken npt && npt.MemberInfo.Name == nameof(DateTimeOffset.DateTime) && npt.MemberInfo.DeclaringType == typeof(DateTimeOffset) ||
qt is EntityPropertyToken ept && Schema.Current.Field(ept.PropertyRoute) is FieldValue fv && fv.DateTimeKind == DateTimeKind.Local;
ExtensionToken.BuildExtension = (parentType, key, parentExpression) => Expressions.BuildExtension(parentType, key, parentExpression);
QueryToken.ImplementedByAllSubTokens = GetImplementedByAllSubTokens;
QueryToken.IsSystemVersioned = IsSystemVersioned;
Expand Down
5 changes: 3 additions & 2 deletions Signum.Engine/Json/FilterJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ public override Filter ToFilter(QueryDescription qd, bool canAggregate, JsonSeri
var val = value is JsonElement jtok ?
jtok.ToObject(expectedValueType, jsonSerializerOptions) :
value;


if (val is DateTime dt)
if (val is DateTime dt && !QueryToken.IsLocalDateTime(parsedToken))
val = dt.FromUserInterface();
else if (val is ObservableCollection<DateTime?> col)
else if (val is ObservableCollection<DateTime?> col && !QueryToken.IsLocalDateTime(parsedToken))
val = col.Select(dt => dt?.FromUserInterface()).ToObservableCollection();

return new FilterCondition(parsedToken, operation, val);
Expand Down
2 changes: 1 addition & 1 deletion Signum.Entities/DynamicQuery/Tokens/QueryToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public static IEnumerable<QueryToken> OnDynamicEntityExtension(QueryToken parent
return DynamicEntityExtensions(parent);
}

static Func<QueryToken, bool> IsLocalDateTime = qt => qt is NetPropertyToken npt && npt.MemberInfo.Name == nameof(DateTimeOffset.DateTime) && npt.MemberInfo.DeclaringType == typeof(DateTimeOffset);
public static Func<QueryToken, bool> IsLocalDateTime;

public static List<QueryToken> DateTimeProperties(QueryToken parent, DateTimePrecision precision)
{
Expand Down

2 comments on commit 68914f6

@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.

Time Machine 2.0

Since the last three months there have been a series of changes, mainly done by @JafarMirzaie, that can be group together in the "Time Machine 2.0" theme.

The main focus of this change is to make the Time Machine more approachable for the end user.

1. Clien Side Diffs

This change improves performance of the Diff algorithm and, more important, moves the computation from the server to the client browser.

Already mentioned here.

2. New Time Machine UI

There have been many changes in the Time Machine UI:

  • A more prominent Quick Link
    image
  • Modal UI
  • Radio buttons (instead of check boxes) are used for selection.
  • When clicked, the selected radio button is considered the comparison target (in blue) and the one below the comparison origin (in gray).
  • You can change the comparison target / origin independently clicking the radio buttons with Ctrl pressed.
  • At any point, only two tabs will be shown below:
    • UI Differences: Shows the selected version (blue) rendered with some special decorators (TimeMachineIcons) to highlight differences with the previous version.
    • Data Differences: Shows the Git-like diff of the Dump strings of the two versions.

image

UI Differences

The new TimeMachineIcons is a small circle in the upper left corner/left side and indicates changes of the value by taking one of the following colors:

  • Gray means no changes.
  • Green means the value has been set (from null), or the row has been created.
  • Yellow means the previous value has changed, or the row has been moved.
  • Red means the value has been removed (to null) or the row has been removed.

The icon is now supported by all the controls: ValueLine, EntityLine, EntityCombo, EntityDetail, EntityStrip, EntityTable, EntityTabRepeater, EntityRepeater, EntityCheckboxList, EnumCheckboxList,... Thanks @JafarMirzaie!

Internally it works by adding a new field previousVersion to TypeContext, so for a typical user interface using all the previously mentioned controls should work without any code changes!!.

Search Control

Also SearchControl, SearchValue and SearchValueLine are compatible with the time machine.

The TimeMachine writes the value SystemValidFrom of the selected version and the previous version into two new fields of the EntityFrame (part of the TypeContext) called currentDate and previousDate.

Thanks to this information SearchValue / SearchValueLine can executed the query at the begining of the selected interval (AS OF). Also it can show a Yellow TimeMachineIcon if there have been any differences between the two versions (BETWEEN).

On the other side, the SearchControl shows only the changes between this two versions using (BETWEEN) and some new icons to express if this version has been created (green +) or removed (red -) in this interval. Obsolete versions have also opacity 0.5.

image

Note: If you want to enjoy TimeMachine functionality in your embedded SearchControl / SearchValue remember to set the optional ctx attribute. For SearchValueLine is mandatory anyway.

UCT/Local columns.

Finally I made some internal changes in the Schema class and LINQ provider to support changing UTC / Local mode not only globally, but for particular columns.

You can define it like this:

    [DbType(DateTimeKind = DateTimeKind.Utc)]
    public DateTime CreationDate { get; private set; } = Clock.Now;

    [DbType(DateTimeKind = DateTimeKind.Local)]
    public DateTime OrderDate { get; set; }

This will correctly set the Kind property of the DateTime when retrieved from the database (SQL has not kind property) and will validate the Kind property when saving or even when comparing in LINQ queries.

This is necessary because SystemValidFrom and SystemValidTo are always UTC. Before this change it was hacked together using DateTimeOffset but this produced other problems.

This change was challenging because it required adding some additional information to any expression tree, including the ones created by Microsoft.

Thanks to some magic in ExpressionMetadataStore using ConditionalWeakTable and ThreadStatic was possible.

Finally

Go use the time machine if you are not doing it yet, it is easy!:

https://github.com/signumsoftware/southwind/blob/182c3c08655a8cdf35fd55b85b1e9ce732f8c3e4/Southwind.Logic/Starter.cs#L350
https://github.com/signumsoftware/southwind/blob/182c3c08655a8cdf35fd55b85b1e9ce732f8c3e4/Southwind.React/App/MainAdmin.tsx#L80

And remember to synchronize!

@JafarMirzaie
Copy link
Contributor

@JafarMirzaie JafarMirzaie commented on 68914f6 Feb 19, 2023 via email

Choose a reason for hiding this comment

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

Please sign in to comment.