Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed variable rewriter #3611

Merged
merged 3 commits into from
Apr 28, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ public void CoerceVariableValues(
{
throw ThrowHelper.NonNullVariableIsNull(variableDefinition);
}
coercedValues[variableName] = new VariableValueOrLiteral(
variableType, null, NullValueNode.Default);
coercedValues[variableName] =
new VariableValueOrLiteral(variableType, null, NullValueNode.Default);
}
else
{
coercedValues[variableName] = CoerceVariableValue(
variableDefinition, variableType, value);
coercedValues[variableName] =
CoerceVariableValue(variableDefinition, variableType, value);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ private static ObjectValueNode Rewrite(
}
rewrittenItems[i] = rewritten;
}
else if (rewrittenItems is { })
{
rewrittenItems[i] = node.Fields[i];
}
}

if (rewrittenItems is { })
Expand Down Expand Up @@ -138,6 +142,10 @@ private static ListValueNode Rewrite(
}
rewrittenItems[i] = rewritten;
}
else if (rewrittenItems is { })
{
rewrittenItems[i] = node.Items[i];
}
}

if (rewrittenItems is { })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,11 @@ context.LocalContextData[ContextValueNodeKey] is IValueNode node
: context.ArgumentLiteral<IValueNode>(argumentName);

// if no filter is defined we can stop here and yield back control.
if (filter.IsNull() ||
(context.LocalContextData.TryGetValue(
SkipFilteringKey,
out object? skipObject) &&
skipObject is bool skip &&
skip))
var skipFiltering =
context.LocalContextData.TryGetValue(SkipFilteringKey, out object? skip) &&
skip is true;

if (filter.IsNull() || skipFiltering)
{
return;
}
Expand All @@ -72,15 +71,12 @@ skipObject is bool skip &&
executorObj is VisitFilterArgument executor)
{
var inMemory =
context.Result is QueryableExecutable<TEntityType> executable &&
executable.InMemory ||
context.Result is QueryableExecutable<TEntityType> { InMemory: true } ||
context.Result is not IQueryable ||
context.Result is EnumerableQuery;

QueryableFilterContext visitorContext = executor(
filter,
filterInput,
inMemory);
QueryableFilterContext visitorContext =
executor(filter, filterInput, inMemory);

// compile expression tree
if (visitorContext.TryCreateLambda(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,11 @@ async ValueTask ExecuteAsync(
IValueNode sort = context.ArgumentLiteral<IValueNode>(argumentName);

// if no sort is defined we can stop here and yield back control.
if (sort.IsNull() ||
(context.LocalContextData.TryGetValue(
SkipSortingKey,
out object? skipObject) &&
skipObject is bool skip &&
skip))
var skipSorting =
context.LocalContextData.TryGetValue(SkipSortingKey, out object? skip) &&
skip is true;

if (sort.IsNull() || skipSorting)
{
return;
}
Expand All @@ -63,8 +62,7 @@ lt.ElementType is NonNullType nn &&
executorObj is VisitSortArgument executor)
{
var inMemory =
context.Result is QueryableExecutable<TEntityType> executable &&
executable.InMemory ||
context.Result is QueryableExecutable<TEntityType> { InMemory: true } ||
context.Result is not IQueryable ||
context.Result is EnumerableQuery;

Expand Down
64 changes: 64 additions & 0 deletions src/HotChocolate/Data/test/Data.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,70 @@ public async Task CreateSchema_OnDifferentScope()
result.ToJson().MatchSnapshot(new SnapshotNameExtension("Result"));
}

[Fact]
public async Task Execute_And_OnRoot()
{
// arrange
IRequestExecutor executor = await new ServiceCollection()
.AddGraphQL()
.AddFiltering("Foo")
.AddSorting("Foo")
.AddProjections("Foo")
.AddQueryType<DifferentScope>()
.BuildRequestExecutorAsync();

// act
IExecutionResult result = await executor.ExecuteAsync(
@"
query GetBooks($title: String) {
books(where: {
and: [
{ title: { startsWith: $title } },
{ title: { eq: ""BookTitle"" } },
]
}) {
nodes { title }
}
}",
new Dictionary<string, object?> { ["title"] = "BookTitle" });

// assert
executor.Schema.Print().MatchSnapshot(new SnapshotNameExtension("Schema"));
result.ToJson().MatchSnapshot(new SnapshotNameExtension("Result"));
}

[Fact]
public async Task Execute_And_OnRoot_Reverse()
{
// arrange
IRequestExecutor executor = await new ServiceCollection()
.AddGraphQL()
.AddFiltering("Foo")
.AddSorting("Foo")
.AddProjections("Foo")
.AddQueryType<DifferentScope>()
.BuildRequestExecutorAsync();

// act
IExecutionResult result = await executor.ExecuteAsync(
@"
query GetBooks($title: String) {
books(where: {
and: [
{ title: { eq: ""BookTitle"" } },
{ title: { startsWith: $title } },
]
}) {
nodes { title }
}
}",
new Dictionary<string, object?> { ["title"] = "BookTitle" });

// assert
executor.Schema.Print().MatchSnapshot(new SnapshotNameExtension("Schema"));
result.ToJson().MatchSnapshot(new SnapshotNameExtension("Result"));
}

public class FooType : ObjectType
{
protected override void Configure(IObjectTypeDescriptor descriptor)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"data": {
"books": {
"nodes": [
{
"title": "BookTitle"
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"data": {
"books": {
"nodes": [
{
"title": "BookTitle"
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
schema {
query: DifferentScope
}

type Author {
id: Int!
name: String
books: [Book!]!
}

type Book {
id: Int!
authorId: Int!
title: String
author: Author
}

"A connection to a list of items."
type BookConnection {
"Information to aid in pagination."
pageInfo: PageInfo!
"A list of edges."
edges: [BookEdge!]
"A flattened list of the nodes."
nodes: [Book!]
}

"An edge in a connection."
type BookEdge {
"A cursor for use in pagination."
cursor: String!
"The item at the end of the edge."
node: Book!
}

type DifferentScope {
books(first: Int after: String last: Int before: String where: Foo_BookFilterInput order: [Foo_BookSortInput!]): BookConnection
}

"Information about pagination in a connection."
type PageInfo {
"Indicates whether more edges exist following the set defined by the clients arguments."
hasNextPage: Boolean!
"Indicates whether more edges exist prior the set defined by the clients arguments."
hasPreviousPage: Boolean!
"When paginating backwards, the cursor to continue."
startCursor: String
"When paginating forwards, the cursor to continue."
endCursor: String
}

input Foo_AuthorFilterInput {
and: [Foo_AuthorFilterInput!]
or: [Foo_AuthorFilterInput!]
id: Foo_ComparableInt32OperationFilterInput
name: Foo_StringOperationFilterInput
books: Foo_ListFilterInputTypeOfBookFilterInput
}

input Foo_AuthorSortInput {
id: Foo_SortEnumType
name: Foo_SortEnumType
}

input Foo_BookFilterInput {
and: [Foo_BookFilterInput!]
or: [Foo_BookFilterInput!]
id: Foo_ComparableInt32OperationFilterInput
authorId: Foo_ComparableInt32OperationFilterInput
title: Foo_StringOperationFilterInput
author: Foo_AuthorFilterInput
}

input Foo_BookSortInput {
id: Foo_SortEnumType
authorId: Foo_SortEnumType
title: Foo_SortEnumType
author: Foo_AuthorSortInput
}

input Foo_ComparableInt32OperationFilterInput {
eq: Int
neq: Int
in: [Int!]
nin: [Int!]
gt: Int
ngt: Int
gte: Int
ngte: Int
lt: Int
nlt: Int
lte: Int
nlte: Int
}

input Foo_ListFilterInputTypeOfBookFilterInput {
all: Foo_BookFilterInput
none: Foo_BookFilterInput
some: Foo_BookFilterInput
any: Boolean
}

input Foo_StringOperationFilterInput {
and: [Foo_StringOperationFilterInput!]
or: [Foo_StringOperationFilterInput!]
eq: String
neq: String
contains: String
ncontains: String
in: [String]
nin: [String]
startsWith: String
nstartsWith: String
endsWith: String
nendsWith: String
}

enum Foo_SortEnumType {
ASC
DESC
}

"The `@defer` directive may be provided for fragment spreads and inline fragments to inform the executor to delay the execution of the current fragment to indicate deprioritization of the current fragment. A query with `@defer` directive will cause the request to potentially return multiple responses, where non-deferred data is delivered in the initial response and data deferred is delivered in a subsequent response. `@include` and `@skip` take precedence over `@defer`."
directive @defer("If this argument label has a value other than null, it will be passed on to the result of this defer directive. This label is intended to give client applications a way to identify to which fragment a deferred result belongs to." label: String "Deferred when true." if: Boolean) on FRAGMENT_SPREAD | INLINE_FRAGMENT

"The `@stream` directive may be provided for a field of `List` type so that the backend can leverage technology such as asynchronous iterators to provide a partial list in the initial response, and additional list items in subsequent responses. `@include` and `@skip` take precedence over `@stream`."
directive @stream("If this argument label has a value other than null, it will be passed on to the result of this stream directive. This label is intended to give client applications a way to identify to which fragment a streamed result belongs to." label: String "The initial elements that shall be send down to the consumer." initialCount: Int! "Streamed when true." if: Boolean!) on FIELD
Loading