Skip to content

Commit 4de5f8d

Browse files
committed
Pagination cleanup and refactoring
1 parent 41eefc1 commit 4de5f8d

File tree

4 files changed

+94
-26
lines changed

4 files changed

+94
-26
lines changed

DataGateway.Service/Resolvers/CosmosQueryEngine.cs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Azure.DataGateway.Service.Resolvers;
33
using Microsoft.Azure.Cosmos;
44
using Newtonsoft.Json.Linq;
5+
using System;
56
using System.Collections.Generic;
67
using System.Text.Json;
78
using System.Threading.Tasks;
@@ -36,7 +37,7 @@ public void RegisterResolver(GraphQLQueryResolver resolver)
3637
// <summary>
3738
// ExecuteAsync the given named graphql query on the backend.
3839
// </summary>
39-
public async Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionary<string, object> parameters)
40+
public async Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionary<string, object> parameters, bool isContinuationQuery)
4041
{
4142
// TODO: fixme we have multiple rounds of serialization/deserialization JsomDocument/JObject
4243
// TODO: add support for nesting
@@ -46,6 +47,8 @@ public async Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionar
4647
GraphQLQueryResolver resolver = this._metadataStoreProvider.GetQueryResolver(graphQLQueryName);
4748
Container container = this._clientProvider.Client.GetDatabase(resolver.DatabaseName).GetContainer(resolver.ContainerName);
4849
var querySpec = new QueryDefinition(resolver.ParametrizedQuery);
50+
var queryRequestOptions = new QueryRequestOptions();
51+
string requestContinuation = null;
4952

5053
if (parameters != null)
5154
{
@@ -55,7 +58,38 @@ public async Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionar
5558
}
5659
}
5760

58-
FeedResponse<JObject> firstPage = await container.GetItemQueryIterator<JObject>(querySpec).ReadNextAsync();
61+
if (parameters.TryGetValue("first", out object maxSize))
62+
{
63+
queryRequestOptions.MaxItemCount = Convert.ToInt32(maxSize);
64+
}
65+
66+
if (parameters.TryGetValue("after", out object after))
67+
{
68+
requestContinuation = after as string;
69+
}
70+
71+
FeedResponse<JObject> firstPage = await container.GetItemQueryIterator<JObject>(querySpec, requestContinuation, queryRequestOptions).ReadNextAsync();
72+
73+
if (isContinuationQuery)
74+
{
75+
JArray jarray = new();
76+
IEnumerator<JObject> enumerator = firstPage.GetEnumerator();
77+
while (enumerator.MoveNext())
78+
{
79+
JObject item = enumerator.Current;
80+
jarray.Add(item);
81+
}
82+
83+
string responseContinuation = firstPage.ContinuationToken;
84+
JObject res = new(
85+
new JProperty("endCursor", responseContinuation),
86+
new JProperty("hasNextPage", responseContinuation != null),
87+
new JProperty("nodes", jarray));
88+
89+
// This extra deserialize/serialization will be removed after moving to Newtonsoft from System.Text.Json
90+
var resultJsonDoc = JsonDocument.Parse(res.ToString());
91+
return resultJsonDoc;
92+
}
5993

6094
JObject firstItem = null;
6195

DataGateway.Service/Resolvers/IQueryEngine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public interface IQueryEngine
1818
// <summary>
1919
// Executes the given named graphql query on the backend and expecting a single Json back.
2020
// </summary>
21-
public Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionary<string, object> parameters);
21+
public Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionary<string, object> parameters, bool isContinuationQuery);
2222

2323
// <summary>
2424
// Executes the given named graphql query on the backend and expecting a list of Jsons back.

DataGateway.Service/Resolvers/SqlQueryEngine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void RegisterResolver(GraphQLQueryResolver resolver)
3939
// <summary>
4040
// ExecuteAsync the given named graphql query on the backend.
4141
// </summary>
42-
public async Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionary<string, object> parameters)
42+
public async Task<JsonDocument> ExecuteAsync(string graphQLQueryName, IDictionary<string, object> parameters, bool isContinuationQuery)
4343
{
4444
// TODO: add support for nesting
4545
// TODO: add support for join query against another table

DataGateway.Service/Services/ResolverMiddleware.cs

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System.Collections.Generic;
66
using System.Text.Json;
77
using System.Threading.Tasks;
8+
using Newtonsoft.Json;
9+
using Newtonsoft.Json.Linq;
810

911
namespace Azure.DataGateway.Services
1012
{
@@ -42,54 +44,86 @@ public async Task InvokeAsync(IMiddlewareContext context)
4244
if (context.Selection.Field.Coordinate.TypeName.Value == "Query")
4345
{
4446
IDictionary<string, object> parameters = GetParametersFromContext(context);
47+
string queryId = context.Selection.Field.Name.Value;
48+
bool isContinuationQuery = IsContinuationQuery(parameters);
4549

4650
if (context.Selection.Type.IsListType())
4751
{
48-
context.Result = await _queryEngine.ExecuteListAsync(context.Selection.Field.Name.Value, parameters);
52+
context.Result = await _queryEngine.ExecuteListAsync(queryId, parameters);
4953
}
5054
else
5155
{
52-
context.Result = await _queryEngine.ExecuteAsync(context.Selection.Field.Name.Value, parameters);
56+
context.Result = await _queryEngine.ExecuteAsync(context.Selection.Field.Name.Value, parameters, isContinuationQuery);
5357
}
5458
}
55-
56-
if (IsInnerObject(context))
59+
else
5760
{
5861
JsonDocument result = context.Parent<JsonDocument>();
5962

6063
JsonElement jsonElement;
6164
bool hasProperty =
6265
result.RootElement.TryGetProperty(context.Selection.Field.Name.Value, out jsonElement);
63-
if (result != null && hasProperty)
66+
67+
if (IsInnerObject(context))
6468
{
65-
//TODO: Try to avoid additional deserialization/serialization here.
66-
context.Result = JsonDocument.Parse(jsonElement.ToString());
69+
70+
if (result != null && hasProperty)
71+
{
72+
//TODO: Try to avoid additional deserialization/serialization here.
73+
context.Result = JsonDocument.Parse(jsonElement.ToString());
74+
}
75+
else
76+
{
77+
context.Result = null;
78+
}
6779
}
68-
else
80+
else if (context.Selection.Field.Type.IsListType())
6981
{
70-
context.Result = null;
71-
}
72-
}
82+
if (result != null && hasProperty)
83+
{
84+
//TODO: System.Text.Json seem to to have very limited capabilities. This will be moved to Newtonsoft
85+
IEnumerable<JObject> resultArray = JsonConvert.DeserializeObject<JObject[]>(jsonElement.ToString());
86+
List<JsonDocument> resultList = new();
87+
IEnumerator<JObject> enumerator = resultArray.GetEnumerator();
88+
while (enumerator.MoveNext())
89+
{
90+
resultList.Add(JsonDocument.Parse(enumerator.Current.ToString()));
91+
}
92+
context.Result = resultList;
93+
}
94+
else
95+
{
96+
context.Result = null;
97+
}
7398

74-
if (context.Selection.Field.Type.IsLeafType())
75-
{
76-
JsonDocument result = context.Parent<JsonDocument>();
77-
JsonElement jsonElement;
78-
bool hasProperty =
79-
result.RootElement.TryGetProperty(context.Selection.Field.Name.Value, out jsonElement);
80-
if (result != null && hasProperty)
81-
{
82-
context.Result = jsonElement.ToString();
8399
}
84-
else
100+
101+
if (context.Selection.Field.Type.IsLeafType())
85102
{
86-
context.Result = null;
103+
if (result != null && hasProperty)
104+
{
105+
context.Result = jsonElement.ToString();
106+
}
107+
else
108+
{
109+
context.Result = null;
110+
}
87111
}
88112
}
89113

90114
await _next(context);
91115
}
92116

117+
private static bool IsContinuationQuery(IDictionary<string, object> parameters)
118+
{
119+
if (parameters.ContainsKey("after"))
120+
{
121+
return true;
122+
}
123+
124+
return false;
125+
}
126+
93127
private static bool IsInnerObject(IMiddlewareContext context)
94128
{
95129
return context.Selection.Field.Type.IsObjectType() && context.Parent<JsonDocument>() != default;

0 commit comments

Comments
 (0)