Graphql-ruby: Duplicated records on paged/sorted connections

Created on 1 Sep 2017  路  7Comments  路  Source: rmosolgo/graphql-ruby

As we talked at Slack, I'm facing a problem with GraphQL::Pro::RelationConnection when I sort Relations by any other field instead ID. I'm receiving duplicated records on subsequent pages.

I already tried to include Primary Key to order clause (as you can see it below).

Connection Definition

# ./graphql/types/query_type.rb
QueryGQLType = GraphQL::ObjectType.define do
  ...
  connection :table, TableWithCountConnection, max_page_size: 50 do
    resolve ->(_obj, _args, _ctx) { Table.joins(:child_table).order('"child_table"."index", "table"."id"') }
  end
  ...
end
# ./graphql/connections/table_with_count_connection.rb
TableWithCountConnection = TableType.define_connection do
  name 'TableWithCountConnection'
  field :count do
    type types.Int
    resolve ->(obj, _args, _ctx) { obj.nodes.count }
  end
end

GraphQL Query for First Page

query { 
  table(first: 10) { 
    edges { node { id title } } 
    pageInfo { startCursor endCursor }
  } 
}

GraphQL Response for First Page

{
  "data": {
    "table": {
      "edges": [
        {
          "node": { "id": "2", "title": "Record #1" },
          "cursor": "WyIxLjAiLDJd"
        },
        {
          "node": { "id": "18", "title": "Record #10" },
          "cursor": "WyI2LjAiLDE4XQ=="
        },
        {
          "node": { "id": "31", "title": "Record #11" },
          "cursor": "WyIzLjAiLDMxXQ=="
        },
        {
          "node": { "id": "34", "title": "Record #12" },
          "cursor": "WyIxNC4wIiwzNF0="
        },
        {
          "node": { "id": "32", "title": "Record #15" },
          "cursor": "WyIxMi4wIiwzMl0="
        },
        {
          "node": { "id": "37", "title": "Record #16" },
          "cursor": "WyI0LjAiLDM3XQ=="
        },
        {
          "node": { "id": "33", "title": "Record #17" },
          "cursor": "WyIxMy4wIiwzM10="
        },
        {
          "node": { "id": "35", "title": "Record #19" },
          "cursor": "WyIxNS4wIiwzNV0="
        },
        {
          "node": { "id": "21", "title": "Record #2" },
          "cursor": "WyI5LjAiLDIxXQ=="
        },
        {
          "node": { "id": "17", "title": "Record #3" },
          "cursor": "WyI1LjAiLDE3XQ=="
        }
      ],
      "pageInfo": {
        "startCursor": "WyIxLjAiLDJd",
        "endCursor": "WyI1LjAiLDE3XQ=="
      }
    }
  }
}

SQL Query for First Page

SELECT "table".*
FROM "table" JOIN "child_table" ON "table"."id" = "child_table"."id"
ORDER BY "child_table"."index", "table"."id"
LIMIT 11

GraphQL Query for Second Page

query { 
  table(first: 10, after: "WyI1LjAiLDE3XQ==") { 
    edges { node { id title } } 
    pageInfo { startCursor endCursor }
  } 
}

GraphQL Response for Second Page

{
  "data": {
    "table": {
      "edges": [
        {
          "node": { "id": "34", "title": "Record #12" },
          "cursor": "WyIxNC4wIiwzNF0="
        },
        {
          "node": { "id": "32", "title": "Record #15" },
          "cursor": "WyIxMi4wIiwzMl0="
        },
        {
          "node": { "id": "37", "title": "Record #16" },
          "cursor": "WyI0LjAiLDM3XQ=="
        },
        {
          "node": { "id": "33", "title": "Record #17" },
          "cursor": "WyIxMy4wIiwzM10="
        },
        {
          "node": { "id": "35", "title": "Record #19" },
          "cursor": "WyIxNS4wIiwzNV0="
        },
        {
          "node": { "id": "21", "title": "Record #2" },
          "cursor": "WyI5LjAiLDIxXQ=="
        },
        {
          "node": { "id": "17", "title": "Record #3" },
          "cursor": "WyI1LjAiLDE3XQ=="
        },
        {
          "node": { "id": "23", "title": "Record #4" },
          "cursor": "WyIxMS4wIiwyM10="
        },
        {
          "node": { "id": "19", "title": "Record #5" },
          "cursor": "WyI3LjAiLDE5XQ=="
        },
        {
          "node": { "id": "24", "title": "Record #6" },
          "cursor": "WyIyLjAiLDI0XQ=="
        }
      ],
      "pageInfo": {
        "startCursor": "WyIxNC4wIiwzNF0=",
        "endCursor": "WyIyLjAiLDI0XQ=="
      }
    }
  }
}

SQL Query for Second Page

SELECT "table".*
FROM "table" JOIN "child_table" ON "table"."id" = "child_table"."id"
WHERE ((("child_table"."index" > '5.0') OR ("child_table"."index" = '5.0' AND "table"."id" > 17)))
ORDER BY "child_table"."index", "table"."id"
LIMIT 11

Ruby and Gems Versions

ruby 2.4.1
rails 4.2.9
graphql-pro 1.4.8
graphql-batch 0.3.3

Most helpful comment

I'm glad to hear that you found a workaround that works for you!

In the meantime, I've updated graphql-pro to support that kind of situation, see #939 . So, if you get a chance to try it out, let me know how it goes. Otherwise, I'm glad the workaround did the job 馃樃

All 7 comments

Hi, thanks for the great bug report! Sorry this is happening ... so confusing!

I was just poking around the tests for this feature and I noticed a strange bug. If join a table, but the main table has a column with the same name as the joined table, it will use a value from the main table.

Is that possible here, does the tables table have an index column?

@rmosolgo, yes. The main table have a column with the same name.

@rmosolgo, based on what you said about columns with the same name I tried a workaround and just worked.

I founded two options:

  1. Rename the column on the child table
  2. Select the column from the child table (the same used to order query) and suppress the other one from SELECT

馃槈

I'm glad to hear that you found a workaround that works for you!

In the meantime, I've updated graphql-pro to support that kind of situation, see #939 . So, if you get a chance to try it out, let me know how it goes. Otherwise, I'm glad the workaround did the job 馃樃

@rmosolgo, I'll try it ASAP 馃槈

@rmosolgo, it works... I already removed my workaround. 馃槃

yay, glad to hear it!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jesster2k10 picture jesster2k10  路  3Comments

rmosolgo picture rmosolgo  路  4Comments

peterphan1996 picture peterphan1996  路  3Comments

pareeohnos picture pareeohnos  路  3Comments

jturkel picture jturkel  路  3Comments