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

Pagination broken for composite keys in version 9 #65

Open
stmfcgcg opened this issue Oct 30, 2022 · 6 comments
Open

Pagination broken for composite keys in version 9 #65

stmfcgcg opened this issue Oct 30, 2022 · 6 comments

Comments

@stmfcgcg
Copy link

Pagination does not work for composite keys in version 9.x (works in version 6.x)

Below are version 9 and version 6 generated code (issuer_id, parent_issuer_id, start_date and source_id are the composite keys). As you can see the criteria to add the nth page is different between the 2.

The difference in the 'where' criteria results in the application only iterating over a subset of the data in v9.x

version 9.x

SELECT "ih"."issuer_id"        AS "ih_issuer_id",
       "ih"."parent_issuer_id" AS "ih_parent_issuer_id",
       "ih"."level"            AS "ih_level",
       "ih"."start_date"       AS "ih_start_date",
       "ih"."end_date"         AS "ih_end_date",
       "ih"."source_id"        AS "ih_source_id"
FROM "ethos_app"."issuer_hierarchy_view" "ih"
WHERE 1 = 1
  AND "ih"."start_date" <= $1
  AND $2 <= "ih"."end_date"
  **AND (("ih"."issuer_id" < $3 OR "ih"."issuer_id" = $4) AND
       ("ih"."parent_issuer_id" < $5 OR "ih"."parent_issuer_id" = $6) AND
       ("ih"."start_date" < $7 OR "ih"."start_date" = $8) AND ("ih"."source_id" < $9 OR "ih"."source_id" = $10))**
ORDER BY "ih"."issuer_id" DESC, "ih"."parent_issuer_id" DESC, "ih"."start_date" DESC, "ih"."source_id" DESC
LIMIT 1001 -- PARAMETERS: ["2022-09-30","2022-09-30",22080794,22080794,22080794,22080794,"2020-05-29","2020-05-29","866561ab-0973-4544-9350-8a3a413f9fee","866561ab-0973-4544-9350-8a3a413f9fee"]

version 6.x

SELECT "ih"."issuer_id"        AS "ih_issuer_id",
       "ih"."parent_issuer_id" AS "ih_parent_issuer_id",
       "ih"."level"            AS "ih_level",
       "ih"."start_date"       AS "ih_start_date",
       "ih"."end_date"         AS "ih_end_date",
       "ih"."source_id"        AS "ih_source_id"
FROM "ethos_app"."issuer_hierarchy_view" "ih"
WHERE 1 = 1
  AND "ih"."start_date" <= $1
  AND $2 <= "ih"."end_date"
  **AND ("ih"."issuer_id" < $3 OR "ih"."issuer_id" = $4 AND "ih"."parent_issuer_id" < $5 OR
       "ih"."issuer_id" = $6 AND "ih"."parent_issuer_id" = $7 AND "ih"."start_date" < $8 OR
       "ih"."issuer_id" = $9 AND "ih"."parent_issuer_id" = $10 AND "ih"."start_date" = $11 AND "ih"."source_id" < $12)**
ORDER BY "ih"."issuer_id" DESC, "ih"."parent_issuer_id" DESC, "ih"."start_date" DESC, "ih"."source_id" DESC
LIMIT 1001 -- PARAMETERS: ["2022-09-30","2022-09-30",212311729,212311729,212311729,212311729,212311729,"2022-08-31",212311729,212311729,"2022-08-31","b55f9205-59c9-4cd8-8bfa-b9245b5858fe"]
@benjamin658
Copy link
Owner

Please upgrade to v0.10.0 to see if it works.

@stmfcgcg
Copy link
Author

stmfcgcg commented Oct 31, 2022 via email

@stuartf123
Copy link

Here is a sample dataset and generated queries that shows the problem:

Col1 Col2
10 20
9 21
8 22
7 23
6 24

1st query – paging 2 rows at a time

Select Col1, Col2
Order by Col1 desc, Col2 desc
Limit 3

Results:
Col1 Col2
10 20
9 21
8 22 <- row used in the 2nd query

2nd query
Select Col1, Col2
Where (Col1 < 8 or Col1 = 8) and (Col2 < 22 or Col2 = 22)
Order by Col1 desc, Col2 desc
Limit 3

Results:
Col1 Col2
8 22

As you can see in the above results – there are rows missing

@stuartf123
Copy link

Your original algorithm would have generated

select col1, col2
where col1 < 8 or col1 = 8 and col2 < 22
limit 3

The above also has a flaw.
I think your algorithm should be:

select col1, col2
where col1 < 8 or (col1 = 8 and col2 < 22) or (col1 = 8 and col2 = 22)
oder by col1 desc, col2 desc

or in general for 3 columns:

select col1, col2, col3
where col1 < x or (col1 = x and col2 < y) or (col1 = x and col2 = y and col3 < z) or (col1 = x and col2 = y and col3 = z)

@stuartf123
Copy link

Here is an implementation of Paginator.buildCursorQuery that pages correctly for composite keys:


const operator = this.getOperator();

 

  // adds "(col1 < x) or (col1 = x and col2 < y)" to the criteria

  for (let outerIndex = 0; outerIndex < this.paginationKeys.length; ++outerIndex) {

    where.orWhere(new Brackets(innerQb => {

      for (let innerIndex = 0; innerIndex <= outerIndex; ++innerIndex) {

        const innerKey = this.paginationKeys[innerIndex]

 

        innerQb.andWhere(`${this.alias}.${innerKey} ${innerIndex === outerIndex ? operator : '='} :${innerKey}`, {

          [`${innerKey}`]: cursors[innerKey]

        })

      }

    }))

  }

 

  // adds "or (col1 = x and col2 = y)" to the criteria

  where.orWhere(new Brackets(finalQb=>{

    this.paginationKeys.forEach((finalKey: Extract<keyof T, string>) => {

      finalQb.andWhere(`${this.alias}.${finalKey} = :${finalKey}`, {

        [`${finalKey}`] : cursors[finalKey]

      })

    })

  }))

@benjamin658
Copy link
Owner

@ stuartf123 Could you send a PR with your implementation?

I really appreciate it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants