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

fix(GraphQL): fix order of entities query result #7542

Merged
merged 22 commits into from
Mar 12, 2021

Conversation

minhaj-shakeel
Copy link
Contributor

@minhaj-shakeel minhaj-shakeel commented Mar 10, 2021

Fixes GRAPHQL-1083.


This change is Reviewable

@github-actions github-actions bot added the area/graphql Issues related to GraphQL support on Dgraph. label Mar 10, 2021
Copy link
Contributor

@abhimanyusinghgaur abhimanyusinghgaur left a comment

Choose a reason for hiding this comment

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

Reviewed 4 of 4 files at r1, 1 of 2 files at r2.
Reviewable status: 4 of 6 files reviewed, 12 unresolved discussions (waiting on @abhimanyusinghgaur, @minhaj-shakeel, and @pawanrawal)


graphql/resolve/query.go, line 59 at r1 (raw file):

// 1) rewrite the query using qr (return error if failed)
// 2) execute the rewritten query with ex (return error if failed)
func NewQueryResolver(qr QueryRewriter, ex DgraphExecutor) QueryResolver {

add a comment about the 3rd step of completion too from previous code


graphql/resolve/query.go, line 64 at r1 (raw file):

// NewEntitiesQueryResolver ...
func NewEntitiesQueryResolver(qr QueryRewriter, ex DgraphExecutor) QueryResolver {

proper comment


graphql/resolve/query_rewriter.go, line 164 at r1 (raw file):

string, string, bool, []interface{}

make a struct and put these in that struct. Not a good practice to return so many results from a func.
The signature should be like:

type parsedRepresentations struct {
 ...
}

func parseRepresentationsArgument(field schema.Query) (parsedRepresentations, error) { ... }

graphql/resolve/query_rewriter.go, line 288 at r1 (raw file):

Quoted 4 lines of code…
	// Add the  ascending Order of the keyField in the query.
	// The result will be converted into the exact in the resultCompletion step.
	dgQuery.Order = append(dgQuery.Order,
		&pb.Order{Attr: typeDefn.DgraphPredicate(keyFieldName)})

we need to do this only when the key field is @id and not for ID. For, ID you won't get a DgraphPredicate as that maps to uid and also that for uid the result is by default sorted in the order of uid, so no need to sort for them.

So, put this in the else case above.


graphql/resolve/query_test.yaml, line 3301 at r2 (raw file):

 orderasc: Astronaut.id

so this should be removed as there is nothing called Astronaut.id stored in dgraph, it is only uid


graphql/resolve/resolver.go, line 88 at r1 (raw file):

}

// A ResultCompleter ....

add in the full comments from the previous code


graphql/resolve/resolver.go, line 328 at r1 (raw file):

entitiesCompletion
entitiesQueryCompletion

as it is only for queries


graphql/resolve/resolver.go, line 329 at r1 (raw file):

id

if


graphql/resolve/resolver.go, line 349 at r1 (raw file):

map[interface{}]int

add a comment about why the key in this map is an interface? (as there are multiple types like String, Int, Int64 allowed as @id)


graphql/resolve/resolver.go, line 356 at r1 (raw file):

.(string)

not necessary that they are string. Use a type switch and do the comparison accordingly.
Possible types are:

  • string
  • int/json.Number (one of these)
  • float/json.Number (one of these)

We need to check json.Number case.

Also, add one e2e test case for the case of @id with Int in entities query.


graphql/resolve/resolver.go, line 362 at r1 (raw file):

[]interface{}(data["_entities"])

let's save this bit in a variable entitiesQryResp prior to the for loop and use that.
also, can there be a case that data for a particular key was missing in dgraph, so that dgraph returns null for that index?
That should be handled by this right?
we should add this scenario in the e2e as well.


graphql/resolve/resolver.go, line 378 at r1 (raw file):

func entitiesQueryCompletion() CompletionFunc {
	return entitiesCompletion
}

not required

Copy link
Contributor

@abhimanyusinghgaur abhimanyusinghgaur left a comment

Choose a reason for hiding this comment

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

Reviewed 1 of 2 files at r2, 6 of 7 files at r3.
Reviewable status: 8 of 9 files reviewed, 14 unresolved discussions (waiting on @abhimanyusinghgaur, @minhaj-shakeel, and @pawanrawal)


graphql/resolve/resolver.go, line 350 at r3 (raw file):

key in the map as 

key in the map is of type interface because


graphql/resolve/resolver.go, line 367 at r3 (raw file):

switch uniqueKeyList[i].(type)

switch val := uniqueKeyList[i].(type)

Then you can just use val in each case without having to explicitly cast it.

The order of cases can be optimized to:

  • string
  • json.Number
  • int64
  • float64

graphql/resolve/resolver.go, line 375 at r3 (raw file):

 uniqueKeyList[i].(json.Number) < uniqueKeyList[j].(json.Number)

json.Number is basically a string.
Doing this would end up in a lexicographic comparison, resulting in
[12, 100, 1] being sorted as [1, 100, 12]. Which is not what we want.

So, we should use val.Int64() or val.Float64() depending on the type of the key field, and then compare.

Copy link
Contributor Author

@minhaj-shakeel minhaj-shakeel left a comment

Choose a reason for hiding this comment

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

Reviewable status: 7 of 11 files reviewed, 14 unresolved discussions (waiting on @abhimanyusinghgaur, @minhaj-shakeel, and @pawanrawal)


graphql/resolve/query.go, line 64 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…

proper comment

Done.


graphql/resolve/query_rewriter.go, line 164 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
string, string, bool, []interface{}

make a struct and put these in that struct. Not a good practice to return so many results from a func.
The signature should be like:

type parsedRepresentations struct {
 ...
}

func parseRepresentationsArgument(field schema.Query) (parsedRepresentations, error) { ... }

Done.


graphql/resolve/query_rewriter.go, line 288 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
	// Add the  ascending Order of the keyField in the query.
	// The result will be converted into the exact in the resultCompletion step.
	dgQuery.Order = append(dgQuery.Order,
		&pb.Order{Attr: typeDefn.DgraphPredicate(keyFieldName)})

we need to do this only when the key field is @id and not for ID. For, ID you won't get a DgraphPredicate as that maps to uid and also that for uid the result is by default sorted in the order of uid, so no need to sort for them.

So, put this in the else case above.

Done.


graphql/resolve/resolver.go, line 88 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…

add in the full comments from the previous code

Done.


graphql/resolve/resolver.go, line 328 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
entitiesCompletion
entitiesQueryCompletion

as it is only for queries

Done.


graphql/resolve/resolver.go, line 329 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
id

if

Done.


graphql/resolve/resolver.go, line 349 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
map[interface{}]int

add a comment about why the key in this map is an interface? (as there are multiple types like String, Int, Int64 allowed as @id)

Done.


graphql/resolve/resolver.go, line 356 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
.(string)

not necessary that they are string. Use a type switch and do the comparison accordingly.
Possible types are:

  • string
  • int/json.Number (one of these)
  • float/json.Number (one of these)

We need to check json.Number case.

Also, add one e2e test case for the case of @id with Int in entities query.

Done.


graphql/resolve/resolver.go, line 362 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
[]interface{}(data["_entities"])

let's save this bit in a variable entitiesQryResp prior to the for loop and use that.
also, can there be a case that data for a particular key was missing in dgraph, so that dgraph returns null for that index?
That should be handled by this right?
we should add this scenario in the e2e as well.

Done.


graphql/resolve/resolver.go, line 378 at r1 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
func entitiesQueryCompletion() CompletionFunc {
	return entitiesCompletion
}

not required

Done.


graphql/resolve/resolver.go, line 350 at r3 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
key in the map as 

key in the map is of type interface because

Done.


graphql/resolve/resolver.go, line 367 at r3 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
switch uniqueKeyList[i].(type)

switch val := uniqueKeyList[i].(type)

Then you can just use val in each case without having to explicitly cast it.

The order of cases can be optimized to:

  • string
  • json.Number
  • int64
  • float64

Even if I use the val, the second value will be typecasted explicitly. Can we do it in a single statement for both of the values?


graphql/resolve/resolver.go, line 375 at r3 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
 uniqueKeyList[i].(json.Number) < uniqueKeyList[j].(json.Number)

json.Number is basically a string.
Doing this would end up in a lexicographic comparison, resulting in
[12, 100, 1] being sorted as [1, 100, 12]. Which is not what we want.

So, we should use val.Int64() or val.Float64() depending on the type of the key field, and then compare.

Done.

Copy link
Contributor

@abhimanyusinghgaur abhimanyusinghgaur left a comment

Choose a reason for hiding this comment

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

:lgtm:

Just got one more comment, and then good to go.

Reviewed 4 of 4 files at r4.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @minhaj-shakeel and @pawanrawal)


graphql/resolve/resolver.go, line 375 at r4 (raw file):

case "Int"

case "Int","Int64":

Copy link
Contributor Author

@minhaj-shakeel minhaj-shakeel left a comment

Choose a reason for hiding this comment

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

Reviewable status: 10 of 11 files reviewed, 1 unresolved discussion (waiting on @abhimanyusinghgaur and @pawanrawal)


graphql/resolve/resolver.go, line 375 at r4 (raw file):

Previously, abhimanyusinghgaur (Abhimanyu Singh Gaur) wrote…
case "Int"

case "Int","Int64":

Done.

@minhaj-shakeel minhaj-shakeel merged commit f8a4d53 into release/v21.03 Mar 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/graphql Issues related to GraphQL support on Dgraph.
Development

Successfully merging this pull request may close these issues.

2 participants