From 1056efdbf6fa6ed91570bb7d3e36b778b295886d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 19 Jun 2024 14:56:06 +0100 Subject: [PATCH] Changing how counting occurs in SQL layer. --- packages/backend-core/src/sql/sql.ts | 47 +++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/backend-core/src/sql/sql.ts b/packages/backend-core/src/sql/sql.ts index 8f45595988..a2ca837fde 100644 --- a/packages/backend-core/src/sql/sql.ts +++ b/packages/backend-core/src/sql/sql.ts @@ -595,19 +595,23 @@ class InternalBuilder { return query.upsert(parsedBody) } - read(knex: Knex, json: QueryJson, limit: number): Knex.QueryBuilder { + read( + knex: Knex, + json: QueryJson, + limits?: { base?: number; query?: number } + ): Knex.QueryBuilder { let { endpoint, resource, filters, paginate, relationships, tableAliases } = json - const counting = endpoint.operation === Operation.COUNT const tableName = endpoint.entityId + const counting = endpoint.operation === Operation.COUNT // select all if not specified if (!resource) { resource = { fields: [] } } let selectStatement: string | (string | Knex.Raw)[] = "*" // handle select - if (!counting && resource.fields && resource.fields.length > 0) { + if (resource.fields && resource.fields.length > 0) { // select the resources as the format "table.columnName" - this is what is provided // by the resource builder further up selectStatement = generateSelectStatement(json, knex) @@ -616,7 +620,7 @@ class InternalBuilder { let query = this.knexWithAlias(knex, endpoint, tableAliases) // handle pagination let foundOffset: number | null = null - let foundLimit = limit || BASE_LIMIT + let foundLimit = limits?.query || limits?.base if (paginate && paginate.page && paginate.limit) { // @ts-ignore const page = paginate.page <= 1 ? 0 : paginate.page - 1 @@ -629,12 +633,12 @@ class InternalBuilder { } else if (paginate && paginate.limit) { foundLimit = paginate.limit } - // always add the found limit, unless counting - if (!counting) { + // add the found limit if supplied + if (foundLimit) { query = query.limit(foundLimit) } // add overall pagination - if (!counting && foundOffset) { + if (foundOffset) { query = query.offset(foundOffset) } // add filters to the query (where) @@ -642,9 +646,11 @@ class InternalBuilder { aliases: tableAliases, }) // add sorting to pre-query + // no point in sorting when counting if (!counting) { query = this.addSorting(query, json) } + const alias = tableAliases?.[tableName] || tableName let preQuery: Knex.QueryBuilder = knex({ // the typescript definition for the knex constructor doesn't support this @@ -653,11 +659,7 @@ class InternalBuilder { // be a table name, not a pre-query [alias]: query as any, }) - if (counting) { - preQuery = preQuery.count("* as total") - } else { - preQuery = preQuery.select(selectStatement) - } + preQuery = preQuery.select(selectStatement) // have to add after as well (this breaks MS-SQL) if (this.client !== SqlClient.MS_SQL && !counting) { preQuery = this.addSorting(preQuery, json) @@ -672,8 +674,9 @@ class InternalBuilder { ) // add a base limit over the whole query - if (!counting) { - query = query.limit(BASE_LIMIT) + // if counting we can't set this limit + if (limits?.base) { + query = query.limit(limits.base) } return this.addFilters(query, filters, json.meta.table, { @@ -682,6 +685,15 @@ class InternalBuilder { }) } + count(knex: Knex, json: QueryJson) { + const readQuery = this.read(knex, json) + // have to alias the sub-query, this is a requirement for my-sql and ms-sql + // without this we get an error "Every derived table must have its own alias" + return knex({ + subquery: readQuery as any, + }).count("* as total") + } + update(knex: Knex, json: QueryJson, opts: QueryOptions): Knex.QueryBuilder { const { endpoint, body, filters, tableAliases } = json let query = this.knexWithAlias(knex, endpoint, tableAliases) @@ -756,8 +768,13 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { query = builder.create(client, json, opts) break case Operation.READ: + query = builder.read(client, json, { + query: this.limit, + base: BASE_LIMIT, + }) + break case Operation.COUNT: - query = builder.read(client, json, this.limit) + query = builder.count(client, json) break case Operation.UPDATE: query = builder.update(client, json, opts)