Skip to content
This repository was archived by the owner on Sep 3, 2021. It is now read-only.

DateTime Ordering Argument Not Impacting Order #373

Closed
johnymontana opened this issue Jan 7, 2020 · 8 comments
Closed

DateTime Ordering Argument Not Impacting Order #373

johnymontana opened this issue Jan 7, 2020 · 8 comments

Comments

@johnymontana
Copy link
Contributor

Hi @johnymontana
It doesn't work for us. We still have the problem with:

type  Post {
   ttuid: ID!,
   title: String!,
   comments: [Comment] @relation(direction:"OUT", name: "HAS"),
   published_at: DateTime,
   created_at: DateTime,
   updated_at: DateTime,
   deleted_at: DateTime,
}

type Comment {
   ttuid: ID!,
   body: String!,
   author: User @relation(direction:"OUT", name:"POSTED_BY"),
   post: Post @relation(direction:"IN", name:"HAS"),
   comments: [Comment] @relation(direction:"OUT", name: "HAS"),
   created_at: DateTime,
   deleted_at: DateTime,
   updated_at: DateTime
}

The following GraphqL query doens't change the order of the comments whatever we fill in orderBy: created_at_asc, created_at_desc, body_asc, body_desc

query getPostComments($postTtuid: ID!, $nbComments: Int!, $nbChildComments: Int!){
  Post(ttuid: $postTtuid){
      comments(first: $nbComments, orderBy: created_at_asc){
          ...Comment
          comments(first: $nbChildComments, orderBy: created_at_asc){
            ...Comment
          }
      }
  }
}

Any idea why?

We've now neo4j-graphql-js@2.11.3

Originally posted by @jonasdumas in #353 (comment)

@johnymontana
Copy link
Contributor Author

Hi @jonasdumas - could you please share the generated Cypher statement from your GraphQL query?

Also, I wonder if this could be a bug related to fragments. Could you try the GraphQL query with using the ... Comment fragment and see if you have the same results?

@jonasdumas
Copy link

jonasdumas commented Jan 7, 2020

Hi @johnymontana
Thanks for your answer.
Sure, here's the generated Cypher statement:

MATCH (`post`:`Post` {ttuid:$ttuid}) 
RETURN `post` 
{ 
  .ttuid , 
  comments: [ 
      post_comments IN apoc.cypher.runFirstColumn(
          "MATCH (this)-[:HAS]->(comment:Comment) RETURN comment ORDER BY comment.created_at DESC", 
          { 
              this: post, 
              cypherParams: $cypherParams, 
              first: $1_first, 
              offset: $1_offset, 
              orderBy: $1_orderBy
          }, 
          true
      )
      | post_comments { 
          .body, 
          created_at: { formatted: toString(`post_comments`.created_at) }, 
          comments: apoc.coll.sortMulti(
              [
                  (`post_comments`)-[:`HAS`]->(`post_comments_comments`:`Comment`) 
                  | post_comments_comments { 
                        .body , 
                        created_at: { formatted: toString(`post_comments_comments`.created_at) }
                  }
              ], 
              ['^created']
          )[0..3] 
      }
  ][0..3] 
} AS `post`
{
  "offset": 0,
  "first": -1,
  "ttuid": "76776d93-a98f-4c53-b285-7ae49c8bb21e",
  "1_first": 3,
  "1_offset": 0,
  "1_orderBy": "created_at_desc",
  "2_first": 3,
  "2_offset": 0,
  "2_orderBy": "created_at_asc",
  "cypherParams": {
    "currentUserId": 60
  }
}

No it's not related to fragments as you can see on the Playground printscreen. It's also not specific to DateTime such as it doesn't work with the body_asc (String). It's always the same order of records returned.
graphqlQuery

@johnymontana
Copy link
Contributor Author

@jonasdumas Looks like there was a bug with how we handled nested ordering when the field included an underscore character.

I've pushed a fix and a release. Could you please try with the latest v2.11.4 and let us know if that fixes the issue for you?

@jonasdumas
Copy link

jonasdumas commented Jan 8, 2020

@johnymontana thanks for your return. Things changes with your last commit. Now we got an error in the GraphQL response:

{
  "errors": [
    {
      "message": "Resolve function for \"_Neo4jDateTime.formatted\" returned undefined",
      "locations": [
        {
          "line": 7,
          "column": 9
        }
      ],
      "path": [
        "Post",
        0,
        "comments",
        0,
        "created_at",
        "formatted"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "Error: Resolve function for \"_Neo4jDateTime.formatted\" returned undefined",
            "    at [..pathname..]/node_modules/graphql-tools/src/makeExecutableSchema.ts:104:13",
            "    at field.resolve ([..pathname..]/node_modules/graphql-extensions/src/index.ts:274:18)",
            "    at resolveFieldValueOrError ([..pathname..]/node_modules/graphql/execution/execute.js:467:18)",
            "    at resolveField ([..pathname..]/node_modules/graphql/execution/execute.js:434:16)",
            "    at executeFields ([..pathname..]/node_modules/graphql/execution/execute.js:275:18)",
            "    at collectAndExecuteSubfields ([..pathname..]/node_modules/graphql/execution/execute.js:713:10)",
            "    at completeObjectValue ([..pathname..]/node_modules/graphql/execution/execute.js:703:10)",
            "    at completeValue ([..pathname..]/node_modules/graphql/execution/execute.js:591:12)",
            "    at completeValueCatchingError ([..pathname..]/node_modules/graphql/execution/execute.js:495:19)",
            "    at resolveField ([..pathname..]/node_modules/graphql/execution/execute.js:435:10)"
          ]
        }
      }
    },
    {
      "message": "Resolve function for \"_Neo4jDateTime.formatted\" returned undefined",
      "locations": [
        {
          "line": 7,
          "column": 9
        }
      ],
      "path": [
        "Post",
        0,
        "comments",
        1,
        "created_at",
        "formatted"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "Error: Resolve function for \"_Neo4jDateTime.formatted\" returned undefined",
            "    at [..pathname..]/node_modules/graphql-tools/src/makeExecutableSchema.ts:104:13",
            "    at field.resolve ([..pathname..]/node_modules/graphql-extensions/src/index.ts:274:18)",
            "    at resolveFieldValueOrError ([..pathname..]/node_modules/graphql/execution/execute.js:467:18)",
            "    at resolveField ([..pathname..]/node_modules/graphql/execution/execute.js:434:16)",
            "    at executeFields ([..pathname..]/node_modules/graphql/execution/execute.js:275:18)",
            "    at collectAndExecuteSubfields ([..pathname..]/node_modules/graphql/execution/execute.js:713:10)",
            "    at completeObjectValue ([..pathname..]/node_modules/graphql/execution/execute.js:703:10)",
            "    at completeValue ([..pathname..]/node_modules/graphql/execution/execute.js:591:12)",
            "    at completeValueCatchingError ([..pathname..]/node_modules/graphql/execution/execute.js:495:19)",
            "    at resolveField ([..pathname..]/node_modules/graphql/execution/execute.js:435:10)"
          ]
        }
      }
    },
    {
      "message": "Resolve function for \"_Neo4jDateTime.formatted\" returned undefined",
      "locations": [
        {
          "line": 7,
          "column": 9
        }
      ],
      "path": [
        "Post",
        0,
        "comments",
        2,
        "created_at",
        "formatted"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "Error: Resolve function for \"_Neo4jDateTime.formatted\" returned undefined",
            "    at [..pathname..]/node_modules/graphql-tools/src/makeExecutableSchema.ts:104:13",
            "    at field.resolve ([..pathname..]/node_modules/graphql-extensions/src/index.ts:274:18)",
            "    at resolveFieldValueOrError ([..pathname..]/node_modules/graphql/execution/execute.js:467:18)",
            "    at resolveField ([..pathname..]/node_modules/graphql/execution/execute.js:434:16)",
            "    at executeFields ([..pathname..]/node_modules/graphql/execution/execute.js:275:18)",
            "    at collectAndExecuteSubfields ([..pathname..]/node_modules/graphql/execution/execute.js:713:10)",
            "    at completeObjectValue ([..pathname..]/node_modules/graphql/execution/execute.js:703:10)",
            "    at completeValue ([..pathname..]/node_modules/graphql/execution/execute.js:591:12)",
            "    at completeValueCatchingError ([..pathname..]/node_modules/graphql/execution/execute.js:495:19)",
            "    at resolveField ([..pathname..]/node_modules/graphql/execution/execute.js:435:10)"
          ]
        }
      }
    }
  ],
  "data": {
    "Post": [
      {
        "ttuid": "76776d93-a98f-4c53-b285-7ae49c8bb21e",
        "comments": [
          {
            "body": "S",
            "created_at": {
              "formatted": null
            }
          },
          {
            "body": "A",
            "created_at": {
              "formatted": null
            }
          },
          {
            "body": "Autre",
            "created_at": {
              "formatted": null
            }
          }
        ]
      }
    ]
  }
}

The GraphQL query:


{
    Post(ttuid: "76776d93-a98f-4c53-b285-7ae49c8bb21e"){
	ttuid
        comments(first: 3, offset:0, orderBy: created_at_asc){
              body
	      created_at {formatted}
         }
    }
}

The CYPHER output is the following:

MATCH (`post`:`Post` {ttuid:$ttuid}) RETURN `post` { .ttuid ,comments: [ post_comments IN apoc.cypher.runFirstColumn("MATCH (this)-[:HAS]->(comment:Comment) RETURN comment ORDER BY comment.created_at DESC", {this: post, cypherParams: $cypherParams, first: $1_first, offset: $1_offset, orderBy: $1_orderBy}, true) | post_comments { .body ,created_at: `post_comments`.created_at}][0..3] } AS `post`
{
  "offset": 0,
  "first": -1,
  "ttuid": "76776d93-a98f-4c53-b285-7ae49c8bb21e",
  "1_first": 3,
  "1_offset": 0,
  "1_orderBy": "created_at_asc",
  "cypherParams": {
    "currentUserId": 60
  }
}

@johnymontana
Copy link
Contributor Author

@jonasdumas are you using a @cypher directive on the Post.comments field instead of a @relation directive?

I'm not able to reproduce it with the GraphQL schema you shared. Instead, for the query

{
    Post(ttuid: "76776d93-a98f-4c53-b285-7ae49c8bb21e"){
	ttuid
        comments(first: 3, offset:0, orderBy: created_at_asc){
              body
	      created_at {formatted}
         }
    }
}

the generated Cypher is

MATCH (`post`:`Post` {ttuid:$ttuid}) 
RETURN `post` { .ttuid ,
  comments: 
    [sortedElement IN apoc.coll.sortMulti([(`post`)-[:`HAS`]->(`post_comments`:`Comment`) | post_comments { 
      .body ,
      created_at: `post_comments`.created_at}], ['^created_at']) | sortedElement { .*,  created_at: {formatted: toString(sortedElement.created_at)}}][0..3] } AS `post`

which includes data for the formatted field, so the formatted resolver is not called. Can you share the GraphQL Schema you're using? Or check to make sure you are using @relation?

@jonasdumas
Copy link

jonasdumas commented Jan 8, 2020

Thanks @johnymontana. Right, in my previous comment, due to our tests, we had a temporary @cypher directive in our Schema definition in Post Schema who was at the origin of the error in the GraphQL playground. Thanks for pointing that.
After changing it to @relation it solve the error in playground.
But, we still have an error in our app and after few tests it seems to come from DateTime field.

Here's (part of) our schema:

type Comment {
            ttuid: ID!,
            body: String!,
            author: User @relation(direction:"OUT", name:"POSTED_BY"),
            post: Post @relation(direction:"IN", name:"HAS"),
            comments: [Comment] @relation(direction:"OUT", name: "HAS"),
            created_at: DateTime,
            deleted_at: DateTime,
            updated_at: DateTime
},
type  Post {
              ttuid: ID!,
 
              published_at: DateTime,
              created_at: DateTime,
              updated_at: DateTime,
              deleted_at: DateTime,

              # COMMENTS
              comments: [Comment] @relation(direction:"OUT", name:"HAS"),

              # LOT OF OTHER FIELDS NOT RELATED TO COMMENTS
              ....
}

Our graphQL query:

query getPostComments($postTtuid: ID!, $nbParentComments: Int!, $nbChildComments: Int!){
	Post(ttuid: $postTtuid){
	  ttuid
      comments(first: $nbParentComments, orderBy: created_at_asc){
          ...Comment
          comments(first: $nbChildComments, orderBy: created_at_asc){
            ...Comment
          }
      }
  }
}

Fragments:

fragment Comment on Comment {
  ttuid
  body
  created_at{
    formatted
  }
  updated_at{
    formatted
  }
  author{
    ...UserPreview
  }
}
fragment UserPreview on User {
      _id
      ttuid
      first_name
      last_name
      avatar
      slug
}

Here's the graphql Error:

[GraphQL error]: Message: Invalid input '}': expected whitespace, comment, literal entry, property selector, variable selector or all properties selector (line 1, column 990 (offset: 989))
"MATCH (`post`:`Post` {ttuid:$ttuid}) RETURN `post` { .ttuid ,comments: [sortedElement IN apoc.coll.sortMulti([(`post`)-[:`HAS`]->(`post_comments`:`Comment`) | post_comments { .ttuid , .body ,created_at: `post_comments`.created_at,updated_at: `post_comments`.updated_at,author: head([(`post_comments`)-[:`POSTED_BY`]->(`post_comments_author`:`User`) | post_comments_author {_id: ID(`post_comments_author`), .ttuid , .first_name , .last_name , .avatar , .slug }]) ,comments: [sortedElement IN apoc.coll.sortMulti([(`post_comments`)-[:`HAS`]->(`post_comments_comments`:`Comment`) | post_comments_comments { .ttuid , .body ,created_at: `post_comments_comments`.created_at,updated_at: `post_comments_comments`.updated_at,author: head([(`post_comments_comments`)-[:`POSTED_BY`]->(`post_comments_comments_author`:`User`) | post_comments_comments_author {_id: ID(`post_comments_comments_author`), .ttuid , .first_name , .last_name , .avatar , .slug }]) }], ['^created_at'])
| sortedElement >>>{ .*,  }<<<][..0] }], ['^created_at']) |
 sortedElement >>>{ .*,  }<<<][..0] } AS `post`"

### => After few test, it seems to come from DateTime type. As if OrderBy (both) use body_asc it works.

I noticed this at the end of the error message in the cypher output:
sortedElement { .*, }

It seems to be where it should have the created_at fields, right after the comma:
{formatted: toString(sortedElement.created_at)}

But it's not there...

@jonasdumas
Copy link

jonasdumas commented Jan 9, 2020

As the GraphQL query work in the playground but not when it’s fired thru the app, do you have any idea why?

Also, @johnymontana, your first remark/answer (in #353 ) to our bug alert was to directly point DateTime ordering issue, does it mean there’s already known issue on that?

@nolanvenhola
Copy link

This is still an issue in 2.15.1.

Getting "Resolve function for "_Neo4jDateTime.formatted" returned undefined" for this:

{ VipById(id: "C664A1AC-9545-B29E-3D4B-E519FBF63713") { id firstName lastName notes(orderBy: createdOn_asc) { id value createdOn { formatted } } } }

And this works fine:
{ VipById(id: "C664A1AC-9545-B29E-3D4B-E519FBF63713") { id firstName lastName notes(orderBy: createdOn_asc) { id value } } }

# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants