From 71be3e3df42442485ad77d2794108b09ab9b8d91 Mon Sep 17 00:00:00 2001 From: lstrihic Date: Tue, 21 Jun 2022 15:34:33 +0200 Subject: [PATCH 1/4] fix: mssql cursor pagination --- query_select.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query_select.go b/query_select.go index e993280d8..c59989143 100644 --- a/query_select.go +++ b/query_select.go @@ -505,7 +505,7 @@ func (q *SelectQuery) appendQuery( } if fmter.Dialect().Features().Has(feature.OffsetFetch) { - if q.offset != 0 { + if q.offset >= 0 { b = append(b, " OFFSET "...) b = strconv.AppendInt(b, int64(q.offset), 10) b = append(b, " ROWS"...) From 4de016617487af3b30fd5157ea8b1ab3a45076d5 Mon Sep 17 00:00:00 2001 From: lstrihic Date: Tue, 21 Jun 2022 20:11:16 +0200 Subject: [PATCH 2/4] fix: use limit and offset only if they are set --- query_select.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/query_select.go b/query_select.go index c59989143..665e1a04b 100644 --- a/query_select.go +++ b/query_select.go @@ -45,6 +45,8 @@ func NewSelectQuery(db *DB) *SelectQuery { conn: db.DB, }, }, + offset: -1, + limit: -1, } } @@ -505,7 +507,7 @@ func (q *SelectQuery) appendQuery( } if fmter.Dialect().Features().Has(feature.OffsetFetch) { - if q.offset >= 0 { + if q.limit >= 0 && q.offset >= 0 { b = append(b, " OFFSET "...) b = strconv.AppendInt(b, int64(q.offset), 10) b = append(b, " ROWS"...) @@ -513,13 +515,17 @@ func (q *SelectQuery) appendQuery( b = append(b, " FETCH NEXT "...) b = strconv.AppendInt(b, int64(q.limit), 10) b = append(b, " ROWS ONLY"...) + } else if q.offset >= 0 { + b = append(b, " OFFSET "...) + b = strconv.AppendInt(b, int64(q.offset), 10) + b = append(b, " ROWS"...) } } else { - if q.limit != 0 { + if q.limit >= 0 { b = append(b, " LIMIT "...) b = strconv.AppendInt(b, int64(q.limit), 10) } - if q.offset != 0 { + if q.offset >= 0 { b = append(b, " OFFSET "...) b = strconv.AppendInt(b, int64(q.offset), 10) } From 5c5f9b34e49ec45c6c7f83276c62beb789ba4d13 Mon Sep 17 00:00:00 2001 From: lstrihic Date: Wed, 22 Jun 2022 08:49:38 +0200 Subject: [PATCH 3/4] fix: when using limit start iteration from beginning --- internal/dbtest/query_test.go | 19 +++++++++++++++++++ .../testdata/snapshots/TestQuery-mariadb-131 | 1 + .../testdata/snapshots/TestQuery-mariadb-132 | 1 + .../testdata/snapshots/TestQuery-mariadb-133 | 1 + .../snapshots/TestQuery-mssql2019-131 | 1 + .../snapshots/TestQuery-mssql2019-132 | 1 + .../snapshots/TestQuery-mssql2019-133 | 1 + .../testdata/snapshots/TestQuery-mysql5-131 | 1 + .../testdata/snapshots/TestQuery-mysql5-132 | 1 + .../testdata/snapshots/TestQuery-mysql5-133 | 1 + .../testdata/snapshots/TestQuery-mysql8-131 | 1 + .../testdata/snapshots/TestQuery-mysql8-132 | 1 + .../testdata/snapshots/TestQuery-mysql8-133 | 1 + .../testdata/snapshots/TestQuery-pg-131 | 1 + .../testdata/snapshots/TestQuery-pg-132 | 1 + .../testdata/snapshots/TestQuery-pg-133 | 1 + .../testdata/snapshots/TestQuery-pgx-131 | 1 + .../testdata/snapshots/TestQuery-pgx-132 | 1 + .../testdata/snapshots/TestQuery-pgx-133 | 1 + .../testdata/snapshots/TestQuery-sqlite-131 | 1 + .../testdata/snapshots/TestQuery-sqlite-132 | 1 + .../testdata/snapshots/TestQuery-sqlite-133 | 1 + query_select.go | 6 ++++++ 23 files changed, 46 insertions(+) create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mariadb-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mariadb-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mariadb-133 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mssql2019-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mssql2019-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mssql2019-133 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mysql5-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mysql5-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mysql5-133 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mysql8-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mysql8-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-mysql8-133 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-pg-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-pg-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-pg-133 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-pgx-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-pgx-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-pgx-133 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-sqlite-131 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-sqlite-132 create mode 100644 internal/dbtest/testdata/snapshots/TestQuery-sqlite-133 diff --git a/internal/dbtest/query_test.go b/internal/dbtest/query_test.go index b5a6c79fb..3d513b582 100644 --- a/internal/dbtest/query_test.go +++ b/internal/dbtest/query_test.go @@ -798,6 +798,25 @@ func TestQuery(t *testing.T) { Value("updated_at", "NOW()"). Returning("*") }, + func(db *bun.DB) schema.QueryAppender { + return db.NewSelect(). + Model((*Model)(nil)). + Order("id DESC"). + Limit(20) + }, + func(db *bun.DB) schema.QueryAppender { + return db.NewSelect(). + Model((*Model)(nil)). + Order("id DESC"). + Offset(20). + Limit(20) + }, + func(db *bun.DB) schema.QueryAppender { + return db.NewSelect(). + Model((*Model)(nil)). + Order("id DESC"). + Offset(20) + }, } timeRE := regexp.MustCompile(`'2\d{3}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?(\+\d{2}:\d{2})?'`) diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mariadb-131 b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-131 new file mode 100644 index 000000000..e8a0866c9 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-131 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC LIMIT 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mariadb-132 b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-132 new file mode 100644 index 000000000..b435f87a4 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-132 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC LIMIT 20 OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mariadb-133 b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-133 new file mode 100644 index 000000000..4a1801b5a --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mariadb-133 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-131 b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-131 new file mode 100644 index 000000000..b593164f8 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-131 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-132 b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-132 new file mode 100644 index 000000000..ba49a5349 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-132 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC OFFSET 20 ROWS FETCH NEXT 20 ROWS ONLY diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-133 b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-133 new file mode 100644 index 000000000..9e9331264 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mssql2019-133 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC OFFSET 20 ROWS diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql5-131 b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-131 new file mode 100644 index 000000000..e8a0866c9 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-131 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC LIMIT 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql5-132 b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-132 new file mode 100644 index 000000000..b435f87a4 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-132 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC LIMIT 20 OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql5-133 b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-133 new file mode 100644 index 000000000..4a1801b5a --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql5-133 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql8-131 b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-131 new file mode 100644 index 000000000..e8a0866c9 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-131 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC LIMIT 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql8-132 b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-132 new file mode 100644 index 000000000..b435f87a4 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-132 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC LIMIT 20 OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-mysql8-133 b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-133 new file mode 100644 index 000000000..4a1801b5a --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-mysql8-133 @@ -0,0 +1 @@ +SELECT `model`.`id`, `model`.`str` FROM `models` AS `model` ORDER BY `id` DESC OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pg-131 b/internal/dbtest/testdata/snapshots/TestQuery-pg-131 new file mode 100644 index 000000000..d4b0e6b95 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pg-131 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC LIMIT 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pg-132 b/internal/dbtest/testdata/snapshots/TestQuery-pg-132 new file mode 100644 index 000000000..cf6f3dd67 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pg-132 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC LIMIT 20 OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pg-133 b/internal/dbtest/testdata/snapshots/TestQuery-pg-133 new file mode 100644 index 000000000..bd1f35781 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pg-133 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pgx-131 b/internal/dbtest/testdata/snapshots/TestQuery-pgx-131 new file mode 100644 index 000000000..d4b0e6b95 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pgx-131 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC LIMIT 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pgx-132 b/internal/dbtest/testdata/snapshots/TestQuery-pgx-132 new file mode 100644 index 000000000..cf6f3dd67 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pgx-132 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC LIMIT 20 OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-pgx-133 b/internal/dbtest/testdata/snapshots/TestQuery-pgx-133 new file mode 100644 index 000000000..bd1f35781 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-pgx-133 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-sqlite-131 b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-131 new file mode 100644 index 000000000..d4b0e6b95 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-131 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC LIMIT 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-sqlite-132 b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-132 new file mode 100644 index 000000000..cf6f3dd67 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-132 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC LIMIT 20 OFFSET 20 diff --git a/internal/dbtest/testdata/snapshots/TestQuery-sqlite-133 b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-133 new file mode 100644 index 000000000..bd1f35781 --- /dev/null +++ b/internal/dbtest/testdata/snapshots/TestQuery-sqlite-133 @@ -0,0 +1 @@ +SELECT "model"."id", "model"."str" FROM "models" AS "model" ORDER BY "id" DESC OFFSET 20 diff --git a/query_select.go b/query_select.go index 665e1a04b..e4e68b211 100644 --- a/query_select.go +++ b/query_select.go @@ -512,6 +512,12 @@ func (q *SelectQuery) appendQuery( b = strconv.AppendInt(b, int64(q.offset), 10) b = append(b, " ROWS"...) + b = append(b, " FETCH NEXT "...) + b = strconv.AppendInt(b, int64(q.limit), 10) + b = append(b, " ROWS ONLY"...) + } else if q.limit >= 0 { + b = append(b, " OFFSET 0 ROWS"...) + b = append(b, " FETCH NEXT "...) b = strconv.AppendInt(b, int64(q.limit), 10) b = append(b, " ROWS ONLY"...) From 0c9fa162bbaf7425713922b3c1c081b57e84d4ef Mon Sep 17 00:00:00 2001 From: lstrihic Date: Wed, 22 Jun 2022 10:36:53 +0200 Subject: [PATCH 4/4] fix: test in order to use limit in mssql we have to use order --- internal/dbtest/orm_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/dbtest/orm_test.go b/internal/dbtest/orm_test.go index a5e46006e..fdcfb5037 100644 --- a/internal/dbtest/orm_test.go +++ b/internal/dbtest/orm_test.go @@ -127,6 +127,7 @@ func testAuthorRelations(t *testing.T, db *bun.DB) { Relation("Books.Translations", func(q *bun.SelectQuery) *bun.SelectQuery { return q.OrderExpr("tr.id ASC") }). + OrderExpr("author.id ASC"). Limit(1). Scan(ctx) require.NoError(t, err)