Skip to content

Commit

Permalink
add support for Signum.Utilities.Date
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Feb 9, 2020
1 parent ed42d8a commit 5602eff
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 36 deletions.
3 changes: 3 additions & 0 deletions Signum.Entities/DynamicQuery/QueryUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public static FilterType GetFilterType(Type type)
if (uType == typeof(Guid))
return FilterType.Guid;

if (uType == typeof(Date))
return FilterType.DateTime;

if (uType.IsEnum)
return FilterType.Enum;

Expand Down
22 changes: 19 additions & 3 deletions Signum.Entities/DynamicQuery/Tokens/DateTimeSpecialTokens.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ internal DatePartStartToken(QueryToken parent, QueryTokenMessage name)
this.parent = parent ?? throw new ArgumentNullException(nameof(parent));
}

private static MethodInfo GetMethodInfo(QueryTokenMessage name)
private static MethodInfo GetMethodInfoDateTime(QueryTokenMessage name)
{
return
name == QueryTokenMessage.MonthStart ? miMonthStart :
Expand All @@ -33,6 +33,15 @@ private static MethodInfo GetMethodInfo(QueryTokenMessage name)
throw new InvalidOperationException("Unexpected name");
}

private static MethodInfo GetMethodInfoDate(QueryTokenMessage name)
{
return
name == QueryTokenMessage.MonthStart ? miDMonthStart :
name == QueryTokenMessage.QuarterStart ? miDQuarterStart :
name == QueryTokenMessage.WeekStart ? miDWeekStart :
throw new InvalidOperationException("Unexpected name");
}

public override string ToString()
{
return this.Name.NiceToString();
Expand Down Expand Up @@ -65,7 +74,7 @@ public override string? Unit

public override Type Type
{
get { return typeof(DateTime?); }
get { return Parent!.Type.Nullify(); }
}

public override string Key
Expand All @@ -85,10 +94,17 @@ protected override List<QueryToken> SubTokensOverride(SubTokensOptions options)
public static MethodInfo miMinuteStart = ReflectionTools.GetMethodInfo(() => DateTimeExtensions.MinuteStart(DateTime.MinValue));
public static MethodInfo miSecondStart = ReflectionTools.GetMethodInfo(() => DateTimeExtensions.SecondStart(DateTime.MinValue));

public static MethodInfo miDMonthStart = ReflectionTools.GetMethodInfo(() => DateTimeExtensions.MonthStart(Date.MinValue));
public static MethodInfo miDQuarterStart = ReflectionTools.GetMethodInfo(() => DateTimeExtensions.QuarterStart(Date.MinValue));
public static MethodInfo miDWeekStart = ReflectionTools.GetMethodInfo(() => DateTimeExtensions.WeekStart(Date.MinValue));

protected override Expression BuildExpressionInternal(BuildExpressionContext context)
{
var exp = parent.BuildExpression(context);
var mi = GetMethodInfo(this.Name);
var mi = parent.Type.UnNullify() == typeof(Date) ?
GetMethodInfoDate(this.Name) :
GetMethodInfoDateTime(this.Name);

return Expression.Call(mi, exp.UnNullify()).Nullify();
}

Expand Down
33 changes: 31 additions & 2 deletions Signum.Entities/DynamicQuery/Tokens/QueryToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ public virtual bool IsGroupable

if (route != null && route.PropertyRouteType == PropertyRouteType.FieldOrProperty)
{
if (route.Type == typeof(Date))
return true;

var pp = Validator.TryGetPropertyValidator(route);
if (pp != null)
{
DateTimePrecisionValidatorAttribute? datetimePrecision = pp.Validators.OfType<DateTimePrecisionValidatorAttribute>().SingleOrDefaultEx();

if (datetimePrecision != null && datetimePrecision.Precision == DateTimePrecision.Days)
return true;

}
}

Expand Down Expand Up @@ -158,6 +160,9 @@ protected List<QueryToken> SubTokensBase(Type type, SubTokensOptions options, Im
if (ut == typeof(DateTime))
return DateTimeProperties(this, DateTimePrecision.Milliseconds).AndHasValue(this);

if (ut == typeof(Date))
return DateProperties(this).AndHasValue(this);

if (ut == typeof(float) || ut == typeof(double) || ut == typeof(decimal))
return StepTokens(this, 4).AndHasValue(this);

Expand Down Expand Up @@ -247,6 +252,26 @@ public static List<QueryToken> DateTimeProperties(QueryToken parent, DateTimePre
}.NotNull().ToList();
}

public static List<QueryToken> DateProperties(QueryToken parent)
{
string utc = TimeZoneManager.Mode == TimeZoneMode.Utc ? "Utc - " : "";

return new List<QueryToken?>
{
new NetPropertyToken(parent, ReflectionTools.GetPropertyInfo((Date dt)=>dt.Year), () => utc + QueryTokenMessage.Year.NiceToString()),
new NetPropertyToken(parent, ReflectionTools.GetMethodInfo((Date dt ) => dt.Quarter()), ()=> utc + QueryTokenMessage.Quarter.NiceToString()),
new DatePartStartToken(parent, QueryTokenMessage.QuarterStart),
new NetPropertyToken(parent, ReflectionTools.GetPropertyInfo((Date dt)=>dt.Month),() => utc + QueryTokenMessage.Month.NiceToString()),
new DatePartStartToken(parent, QueryTokenMessage.MonthStart),
new NetPropertyToken(parent, ReflectionTools.GetMethodInfo((Date dt ) => dt.WeekNumber()), ()=> utc + QueryTokenMessage.WeekNumber.NiceToString()),
new DatePartStartToken(parent, QueryTokenMessage.WeekStart),
new NetPropertyToken(parent, ReflectionTools.GetPropertyInfo((Date dt)=>dt.Day), () => utc + QueryTokenMessage.Day.NiceToString()),
new NetPropertyToken(parent, ReflectionTools.GetPropertyInfo((Date dt)=>dt.DayOfYear), () => utc + QueryTokenMessage.DayOfYear.NiceToString()),
new NetPropertyToken(parent, ReflectionTools.GetPropertyInfo((Date dt)=>dt.DayOfWeek), () => utc + QueryTokenMessage.DayOfWeek.NiceToString()),

}.NotNull().ToList();
}

public static List<QueryToken> StepTokens(QueryToken parent, int decimals)
{
return new List<QueryToken?>
Expand Down Expand Up @@ -390,7 +415,11 @@ static string GetNiceTypeName(Type type, Implementations? implementations)
case FilterType.Integer: return QueryTokenMessage.Number.NiceToString();
case FilterType.Decimal: return QueryTokenMessage.DecimalNumber.NiceToString();
case FilterType.String: return QueryTokenMessage.Text.NiceToString();
case FilterType.DateTime: return QueryTokenMessage.DateTime.NiceToString();
case FilterType.DateTime:
if (type.UnNullify() == typeof(Date))
return QueryTokenMessage.Date.NiceToString();

return QueryTokenMessage.DateTime.NiceToString();
case FilterType.Boolean: return QueryTokenMessage.Check.NiceToString();
case FilterType.Guid: return QueryTokenMessage.GlobalUniqueIdentifier.NiceToString();
case FilterType.Enum: return type.UnNullify().NiceName();
Expand Down
3 changes: 3 additions & 0 deletions Signum.Entities/Reflection/Reflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@ public static bool QueryableProperty(Type type, PropertyInfo pi)
if (type.IsEnum)
return null;

if (type == typeof(Date))
return "d";

switch (Type.GetTypeCode(type))
{
case TypeCode.DateTime:
Expand Down
22 changes: 0 additions & 22 deletions Signum.Entities/ValidationAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -668,28 +668,6 @@ public enum ComparisonType
LessThanOrEqualTo,
}

public class DaysPrecisionValidatorAttribute : DateTimePrecisionValidatorAttribute
{
public DaysPrecisionValidatorAttribute()
: base(DateTimePrecision.Days)
{ }
}

public class SecondsPrecisionValidatorAttribute : DateTimePrecisionValidatorAttribute
{
public SecondsPrecisionValidatorAttribute()
: base(DateTimePrecision.Seconds)
{ }
}

public class MinutesPrecisionValidatorAttribute : DateTimePrecisionValidatorAttribute
{
public MinutesPrecisionValidatorAttribute()
: base(DateTimePrecision.Minutes)
{ }

}

public class DateTimePrecisionValidatorAttribute : ValidatorAttribute
{
public DateTimePrecision Precision { get; private set; }
Expand Down
1 change: 1 addition & 0 deletions Signum.React/Facades/SignumServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static MvcNewtonsoftJsonOptions AddSignumJsonConverters(this MvcNewtonsof
s.Converters.Add(new StringEnumConverter());
s.Converters.Add(new ResultTableConverter());
s.Converters.Add(new TimeSpanConverter());
s.Converters.Add(new DateConverter());
});

return jsonOptions;
Expand Down
26 changes: 26 additions & 0 deletions Signum.React/JsonConverters/DateConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Newtonsoft.Json;
using Signum.Utilities;
using System;
using System.Globalization;

namespace Signum.React.Json
{
public class DateConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Date).IsAssignableFrom(objectType.UnNullify());
}

public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
writer.WriteValue(((DateTime?)(Date?)value)?.ToString("o"));
}

public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
var date = reader.Value as DateTime?;
return (Date?)date;
}
}
}
2 changes: 1 addition & 1 deletion Signum.React/Scripts/Lines/ValueLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class ValueLineController extends LineBaseController<ValueLineProps>{
if (t.name == "boolean")
return "Checkbox";

if (t.name == "datetime" || t.name == "DateTimeOffset")
if (t.name == "datetime" || t.name == "DateTimeOffset" || t.name == "Date")
return "DateTime";

if (t.name == "string" || t.name == "Guid")
Expand Down
4 changes: 3 additions & 1 deletion Signum.TSGenerator/EntityDeclarationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,9 @@ private static string TypeScriptNameInternal(TypeReference type, TypeDefinition
if (type.FullName == typeof(String).FullName)
return "string";

if (type.FullName == typeof(DateTime).FullName)
if (type.FullName == typeof(DateTime).FullName ||
type.FullName == "Signum.Utilities.Date"
)
return "string";

if (type.FullName == typeof(DateTimeOffset).FullName)
Expand Down
2 changes: 1 addition & 1 deletion Signum.TSGenerator/Signum.TSGenerator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<LangVersion>latest</LangVersion>
<Platforms>x64;AnyCPU</Platforms>
<Version>2.2.5</Version>
<Version>2.3.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion Signum.TSGenerator/Signum.TSGenerator.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>Signum.TSGenerator</id>
<version>2.2.5</version>
<version>2.3.0</version>
<title>TypeScript generator for Signum Framework applications</title>
<authors>Olmo del Corral</authors>
<license type="expression">MIT</license>
Expand Down
12 changes: 7 additions & 5 deletions Signum.Utilities/Extensions/DateTimeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,13 @@ public static int WeekNumber(this DateTime dateTime)
return cc.Calendar.GetWeekOfYear(dateTime, cc.DateTimeFormat.CalendarWeekRule, cc.DateTimeFormat.FirstDayOfWeek);
}

public static int WeekNumber(this Date date)
{
var cc = CultureInfo.CurrentCulture;

return cc.Calendar.GetWeekOfYear(date, cc.DateTimeFormat.CalendarWeekRule, cc.DateTimeFormat.FirstDayOfWeek);
}

/// <summary>
/// Returns the unix time (also known as POSIX time or epoch time) for the give date time.
/// </summary>
Expand All @@ -502,11 +509,6 @@ public static long ToUnixTimeMilliseconds(this DateTime dateTime)
{
return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds();
}

public static Date ToDate(this DateTime dt)
{
return new Date(dt);
}
}

[DescriptionOptions(DescriptionOptions.Members)]
Expand Down

3 comments on commit 5602eff

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

New Date type in Signum.Utilities.

Both PostgreSQL and Microsoft SQL Server have a type for DateTime without Time for a long time, but it's not implemented in .Net, so was never usable from Signum Framework.

The new Date type is very intuitive and is based in the implementation from https://github.com/supersonicclay/csharp-date/blob/master/CSharpDate/Date.cs.

  • It contains all the properties that makes sense (Year, Month, Day, DayOfWeek, DayOfYear, etc..)
  • It also has all the extension methods (MonthStart, WeekStart, QuarterStart).
  • It's fully integrated into the ORM and the LINQ provider.
  • It's fully supported in the Dynamic queries.
  • It's serialized to JSON using the full ISO 8601 standard (yyyy-MM-dd 00:00:00) you you just need to do moment().format() like always.
  • It's already supported by the ValueLine.

When to use it?

If you have a date time that needs no time part (often using DateTimePrecisionValidator(DateTimePrecision.Days)) it's a good idea to use Date type. Less space in the database and less space where bugs can hide, specially for applications with multiple time zones where the conversions from / to UTC make no sense for properties like DateOfBirth.

Check how Southwind was updated: signumsoftware/southwind@31a5f7f

Enjoy!

@MehdyKarimpour
Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome! Actually we need this.

@rezanos
Copy link
Contributor

@rezanos rezanos commented on 5602eff Feb 9, 2020

Choose a reason for hiding this comment

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

Cool! Great feature!

Please sign in to comment.