Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion docs/mdsource/query-usage.source.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,31 @@ All where statements require a `path`. This is a full path to a, possible nested

#### Supported Types

[String](https://docs.microsoft.com/en-us/dotnet/api/system.string), [Guid](https://docs.microsoft.com/en-us/dotnet/api/system.guid), [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double), [Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean), [Float](https://docs.microsoft.com/en-us/dotnet/api/system.float), [Byte](https://docs.microsoft.com/en-us/dotnet/api/system.byte), [DateTime](https://docs.microsoft.com/en-us/dotnet/api/system.datetime), [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset), [Decimal](https://docs.microsoft.com/en-us/dotnet/api/system.decimal), [Int16](https://docs.microsoft.com/en-us/dotnet/api/system.int16), [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32), [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64), [UInt16](https://docs.microsoft.com/en-us/dotnet/api/system.uint16), [UInt32](https://docs.microsoft.com/en-us/dotnet/api/system.uint32), [UInt64](https://docs.microsoft.com/en-us/dotnet/api/system.uint64), and [Enum](https://docs.microsoft.com/en-us/dotnet/api/system.enum).
[String](https://docs.microsoft.com/en-us/dotnet/api/system.string), [Guid](https://docs.microsoft.com/en-us/dotnet/api/system.guid), [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double), [Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean), [Float](https://docs.microsoft.com/en-us/dotnet/api/system.float), [Byte](https://docs.microsoft.com/en-us/dotnet/api/system.byte), [DateTime](https://docs.microsoft.com/en-us/dotnet/api/system.datetime), [DateOnly](https://docs.microsoft.com/en-us/dotnet/api/system.dateonly), [TimeOnly](https://docs.microsoft.com/en-us/dotnet/api/system.timeonly), [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset), [Decimal](https://docs.microsoft.com/en-us/dotnet/api/system.decimal), [Int16](https://docs.microsoft.com/en-us/dotnet/api/system.int16), [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32), [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64), [UInt16](https://docs.microsoft.com/en-us/dotnet/api/system.uint16), [UInt32](https://docs.microsoft.com/en-us/dotnet/api/system.uint32), [UInt64](https://docs.microsoft.com/en-us/dotnet/api/system.uint64), and [Enum](https://docs.microsoft.com/en-us/dotnet/api/system.enum).


##### TimeOnly query

```
{
timeEntities (where: {path: 'Property', comparison: equal, value: '10:11 AM'})
{
id
}
}
```


##### DateOnly query

```
{
dateEntities (where: {path: 'Property', comparison: equal, value: '2020-10-1'})
{
id
}
}
```


#### Supported Comparisons
Expand Down
26 changes: 25 additions & 1 deletion docs/query-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,31 @@ All where statements require a `path`. This is a full path to a, possible nested

#### Supported Types

[String](https://docs.microsoft.com/en-us/dotnet/api/system.string), [Guid](https://docs.microsoft.com/en-us/dotnet/api/system.guid), [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double), [Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean), [Float](https://docs.microsoft.com/en-us/dotnet/api/system.float), [Byte](https://docs.microsoft.com/en-us/dotnet/api/system.byte), [DateTime](https://docs.microsoft.com/en-us/dotnet/api/system.datetime), [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset), [Decimal](https://docs.microsoft.com/en-us/dotnet/api/system.decimal), [Int16](https://docs.microsoft.com/en-us/dotnet/api/system.int16), [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32), [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64), [UInt16](https://docs.microsoft.com/en-us/dotnet/api/system.uint16), [UInt32](https://docs.microsoft.com/en-us/dotnet/api/system.uint32), [UInt64](https://docs.microsoft.com/en-us/dotnet/api/system.uint64), and [Enum](https://docs.microsoft.com/en-us/dotnet/api/system.enum).
[String](https://docs.microsoft.com/en-us/dotnet/api/system.string), [Guid](https://docs.microsoft.com/en-us/dotnet/api/system.guid), [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double), [Boolean](https://docs.microsoft.com/en-us/dotnet/api/system.boolean), [Float](https://docs.microsoft.com/en-us/dotnet/api/system.float), [Byte](https://docs.microsoft.com/en-us/dotnet/api/system.byte), [DateTime](https://docs.microsoft.com/en-us/dotnet/api/system.datetime), [DateOnly](https://docs.microsoft.com/en-us/dotnet/api/system.dateonly), [TimeOnly](https://docs.microsoft.com/en-us/dotnet/api/system.timeonly), [DateTimeOffset](https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset), [Decimal](https://docs.microsoft.com/en-us/dotnet/api/system.decimal), [Int16](https://docs.microsoft.com/en-us/dotnet/api/system.int16), [Int32](https://docs.microsoft.com/en-us/dotnet/api/system.int32), [Int64](https://docs.microsoft.com/en-us/dotnet/api/system.int64), [UInt16](https://docs.microsoft.com/en-us/dotnet/api/system.uint16), [UInt32](https://docs.microsoft.com/en-us/dotnet/api/system.uint32), [UInt64](https://docs.microsoft.com/en-us/dotnet/api/system.uint64), and [Enum](https://docs.microsoft.com/en-us/dotnet/api/system.enum).


##### TimeOnly query

```
{
timeEntities (where: {path: 'Property', comparison: equal, value: '10:11 AM'})
{
id
}
}
```


##### DateOnly query

```
{
dateEntities (where: {path: 'Property', comparison: equal, value: '2020-10-1'})
{
id
}
}
```


#### Supported Comparisons
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<PropertyGroup>
<NoWarn>CS1591;NU5104;CS1573</NoWarn>
<Version>21.2.0</Version>
<Version>21.3.0</Version>
<AssemblyVersion>1.0.0</AssemblyVersion>
<PackageTags>EntityFrameworkCore, EntityFramework, GraphQL</PackageTags>
<ImplicitUsings>true</ImplicitUsings>
Expand Down
13 changes: 10 additions & 3 deletions src/GraphQL.EntityFramework/Where/ExpressionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,14 @@ static Expression ProcessList(string path, Comparison comparison, string?[]? val
.MakeGenericType(listItemType)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Single(m => m.Name == "BuildPredicate" && m.GetParameters().Length == 5)
.Invoke(new(), new object[] { listPath, comparison, values!, false, stringComparison! })!;
.Invoke(new(), new object[]
{
listPath,
comparison,
values!,
false,
stringComparison!
})!;

// Generate a method info for the Any Enumerable Static Method
var anyInfo = typeof(Enumerable)
Expand All @@ -142,7 +149,7 @@ static Expression GetExpression(string path, Comparison comparison, string?[]? v
{
case Comparison.NotIn:
WhereValidator.ValidateString(comparison, stringComparison);
expressionBody = NegateExpression(MakeStringListInComparison(values!, property, stringComparison)); // Ensure expression is negated
expressionBody = NegateExpression(MakeStringListInComparison(values!, property, stringComparison)); // Ensure expression is negated
break;
case Comparison.In:
WhereValidator.ValidateString(comparison, stringComparison);
Expand All @@ -162,7 +169,7 @@ static Expression GetExpression(string path, Comparison comparison, string?[]? v
{
case Comparison.NotIn:
WhereValidator.ValidateObject(property.PropertyType, comparison, stringComparison);
expressionBody = NegateExpression(MakeObjectListInComparision(values!, property)); // Ensure expression is negated
expressionBody = NegateExpression(MakeObjectListInComparision(values!, property));
break;
case Comparison.In:
WhereValidator.ValidateObject(property.PropertyType, comparison, stringComparison);
Expand Down
28 changes: 28 additions & 0 deletions src/GraphQL.EntityFramework/Where/TypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,24 @@ static IList ConvertStringsToListInternal(IEnumerable<string> values, Type type)
return values.Select(_ => (DateTime?)DateTime.Parse(_)).ToList();
}

if (type == typeof(Time))
{
return values.Select(Time.Parse).ToList();
}
if (type == typeof(Time?))
{
return values.Select(_ => (Time?)Time.Parse(_)).ToList();
}

if (type == typeof(Date))
{
return values.Select(_ => Date.ParseExact(_, "yyyy-MM-dd")).ToList();
}
if (type == typeof(Date?))
{
return values.Select(_ => (Date?)Date.ParseExact(_, "yyyy-MM-dd")).ToList();
}

if (type == typeof(DateTimeOffset))
{
return values.Select(DateTimeOffset.Parse).ToList();
Expand Down Expand Up @@ -151,6 +169,16 @@ static IList ConvertStringsToListInternal(IEnumerable<string> values, Type type)
return ValueConverter.ConvertTo<DateTime>(value);
}

if (type == typeof(Date))
{
return ValueConverter.ConvertTo<Date>(value);
}

if (type == typeof(Time))
{
return ValueConverter.ConvertTo<Time>(value);
}

if (type == typeof(DateTimeOffset))
{
return ValueConverter.ConvertTo<DateTimeOffset>(value);
Expand Down
8 changes: 8 additions & 0 deletions src/Tests/Converters/DateConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class DateConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<Date, DateTime>
{
public DateConverter() : base(
d => d.ToDateTime(Time.MinValue),
d => Date.FromDateTime(d))
{
}
}
12 changes: 12 additions & 0 deletions src/Tests/Converters/NullableDateConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
public class NullableDateConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<Date?, DateTime?>
{
public NullableDateConverter() : base(
d => d == null
? null
: new DateTime?(d.Value.ToDateTime(Time.MinValue)),
d => d == null
? null
: new Date?(Date.FromDateTime(d.Value)))
{
}
}
8 changes: 8 additions & 0 deletions src/Tests/Converters/NullableTimeConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class NullableTimeConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<Time?, TimeSpan?>
{
public NullableTimeConverter() : base(
t => t == null ? null : new TimeSpan?(t.Value.ToTimeSpan()),
t => t == null ? null : new Time?(Time.FromTimeSpan(t.Value)))
{
}
}
8 changes: 8 additions & 0 deletions src/Tests/Converters/TimeConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
public class TimeConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<Time, TimeSpan>
{
public TimeConverter() : base(
t => t.ToTimeSpan(),
t => Time.FromTimeSpan(t))
{
}
}
5 changes: 5 additions & 0 deletions src/Tests/IntegrationTests/Graphs/DateEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class DateEntity
{
public Guid Id { get; set; } = Guid.NewGuid();
public Date? Property { get; set; }
}
7 changes: 7 additions & 0 deletions src/Tests/IntegrationTests/Graphs/DateEntityGraphType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public class DateEntityGraphType :
EfObjectGraphType<IntegrationDbContext, DateEntity>
{
public DateEntityGraphType(IEfGraphQLService<IntegrationDbContext> graphQlService) :
base(graphQlService) =>
AutoMap();
}
5 changes: 5 additions & 0 deletions src/Tests/IntegrationTests/Graphs/TimeEntity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class TimeEntity
{
public Guid Id { get; set; } = Guid.NewGuid();
public Time? Property { get; set; }
}
7 changes: 7 additions & 0 deletions src/Tests/IntegrationTests/Graphs/TimeEntityGraphType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public class TimeEntityGraphType :
EfObjectGraphType<IntegrationDbContext, TimeEntity>
{
public TimeEntityGraphType(IEfGraphQLService<IntegrationDbContext> graphQlService) :
base(graphQlService) =>
AutoMap();
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ type CustomType {
property: Long!
}

type DateEntity {
id: ID!
property: DateOnly
}

scalar DateOnly

type Derived implements Interface {
childrenFromInterface(after: String, first: Int, before: String, last: Int, where: [WhereExpression!], orderBy: [OrderBy!], ids: [ID!]): DerivedChildConnection!
childrenFromBase(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [DerivedChild!]!
Expand Down Expand Up @@ -266,6 +273,8 @@ type Query {
misNamed(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [WithMisNamedQueryParent!]!
parentEntities(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [Parent!]!
childEntities(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [Child!]!
dateEntities(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [DateEntity!]!
timeEntities(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [TimeEntity!]!
parentEntitiesConnection(after: String, first: Int, before: String, last: Int, where: [WhereExpression!], orderBy: [OrderBy!], ids: [ID!]): ParentConnection!
childEntitiesConnection(after: String, first: Int, before: String, last: Int, where: [WhereExpression!], orderBy: [OrderBy!], ids: [ID!]): ChildConnection!
parentEntitiesFiltered(id: ID, ids: [ID!], where: [WhereExpression!], orderBy: [OrderBy!], skip: Int, take: Int): [FilterParent!]!
Expand Down Expand Up @@ -298,6 +307,13 @@ enum StringComparison {
ORDINAL_IGNORE_CASE
}

type TimeEntity {
id: ID!
property: TimeOnly
}

scalar TimeOnly

input WhereExpression {
path: String
comparison: Comparison
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
target:
{
"data": {
"dateEntities": [
{
"id": "Guid_1"
}
]
}
},
sql: [
{
HasTransaction: false,
Text:
SELECT [d].[Id], [d].[Property]
FROM [DateEntities] AS [d]
WHERE [d].[Property] = '2020-10-01'
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
target:
{
"data": {
"timeEntities": [
{
"id": "Guid_1"
}
]
}
},
sql: [
{
HasTransaction: false,
Text:
SELECT [t].[Id], [t].[Property]
FROM [TimeEntities] AS [t]
WHERE [t].[Property] = '10:11:00'
}
]
}
44 changes: 44 additions & 0 deletions src/Tests/IntegrationTests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,50 @@ public async Task Where_multiple()
await RunQuery(database, query, null, null, false, new object[] { entity1, entity2, entity3 });
}

[Fact]
public async Task Where_date()
{
var query = """
{
dateEntities (where: {path: 'Property', comparison: equal, value: '2020-10-1'})
{
id
}
}
""";

var entity1 = new DateEntity();
var entity2 = new DateEntity
{
Property = new Date(2020, 10, 1)
};

await using var database = await sqlInstance.Build();
await RunQuery(database, query, null, null, false, new object[] { entity1, entity2 });
}

[Fact]
public async Task Where_time()
{
var query = """
{
timeEntities (where: {path: 'Property', comparison: equal, value: '10:11 AM'})
{
id
}
}
""";

var entity1 = new TimeEntity();
var entity2 = new TimeEntity
{
Property = new Time(10, 11)
};

await using var database = await sqlInstance.Build();
await RunQuery(database, query, null, null, false, new object[] { entity1, entity2 });
}

[Fact]
public async Task Where_with_nullable_properties1()
{
Expand Down
21 changes: 21 additions & 0 deletions src/Tests/IntegrationTests/MyDataContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
DbContext
{
public DbSet<ParentEntity> ParentEntities { get; set; } = null!;
public DbSet<DateEntity> DateEntities { get; set; } = null!;
public DbSet<TimeEntity> TimeEntities { get; set; } = null!;
public DbSet<FilterParentEntity> FilterParentEntities { get; set; } = null!;
public DbSet<FilterChildEntity> FilterChildEntities { get; set; } = null!;
public DbSet<ChildEntity> ChildEntities { get; set; } = null!;
Expand Down Expand Up @@ -70,4 +72,23 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
x => x.HasOne(xs => xs.ManyToManyLeftEntity).WithMany(),
x => x.HasOne(xs => xs.ManyToManyRightEntity).WithMany());
}
protected override void ConfigureConventions(ModelConfigurationBuilder builder)
{
builder.Properties<Date>()
.HaveConversion<DateConverter>()
.HaveColumnType("date");

builder.Properties<Date?>()
.HaveConversion<NullableDateConverter>()
.HaveColumnType("date");

builder.Properties<Time>()
.HaveConversion<TimeConverter>()
.HaveColumnType("time");

builder.Properties<Time?>()
.HaveConversion<NullableTimeConverter>()
.HaveColumnType("time");
}

}
Loading