re-jigging things to get counting working properly again.

This commit is contained in:
mike12345567 2024-06-19 17:10:15 +01:00
parent a97b24658f
commit 2aa911b217
1 changed files with 33 additions and 33 deletions

View File

@ -114,7 +114,7 @@ function generateSelectStatement(
): (string | Knex.Raw)[] | "*" { ): (string | Knex.Raw)[] | "*" {
const { resource, meta } = json const { resource, meta } = json
if (!resource) { if (!resource || !resource.fields || resource.fields.length === 0) {
return "*" return "*"
} }
@ -410,14 +410,32 @@ class InternalBuilder {
return query return query
} }
addDistinctCount(
query: Knex.QueryBuilder,
json: QueryJson
): Knex.QueryBuilder {
const table = json.meta.table
const primary = table.primary
const aliases = json.tableAliases
const aliased =
table.name && aliases?.[table.name] ? aliases[table.name] : table.name
if (!primary) {
throw new Error("SQL counting requires primary key to be supplied")
}
return query.countDistinct(`${aliased}.${primary[0]} as total`)
}
addSorting(query: Knex.QueryBuilder, json: QueryJson): Knex.QueryBuilder { addSorting(query: Knex.QueryBuilder, json: QueryJson): Knex.QueryBuilder {
let { sort } = json let { sort } = json
const table = json.meta.table const table = json.meta.table
const mainPrimaryKey = table.primary![0] const primaryKey = table.primary
const tableName = getTableName(table) const tableName = getTableName(table)
const aliases = json.tableAliases const aliases = json.tableAliases
const aliased = const aliased =
tableName && aliases?.[tableName] ? aliases[tableName] : table?.name tableName && aliases?.[tableName] ? aliases[tableName] : table?.name
if (!Array.isArray(primaryKey)) {
throw new Error("Sorting requires primary key to be specified for table")
}
if (sort && Object.keys(sort || {}).length > 0) { if (sort && Object.keys(sort || {}).length > 0) {
for (let [key, value] of Object.entries(sort)) { for (let [key, value] of Object.entries(sort)) {
const direction = const direction =
@ -432,7 +450,7 @@ class InternalBuilder {
} }
} }
// always add sorting by the primary key - make sure result is deterministic // always add sorting by the primary key - make sure result is deterministic
query = query.orderBy(`${aliased}.${mainPrimaryKey}`) query = query.orderBy(`${aliased}.${primaryKey[0]}`)
return query return query
} }
@ -600,25 +618,13 @@ class InternalBuilder {
json: QueryJson, json: QueryJson,
opts: { opts: {
limits?: { base: number; query: number } limits?: { base: number; query: number }
disableSorting?: boolean
} = {} } = {}
): Knex.QueryBuilder { ): Knex.QueryBuilder {
let { endpoint, resource, filters, paginate, relationships, tableAliases } = let { endpoint, filters, paginate, relationships, tableAliases } = json
json const { limits } = opts
const { limits, disableSorting } = opts const counting = endpoint.operation === Operation.COUNT
const tableName = endpoint.entityId const tableName = endpoint.entityId
// select all if not specified
if (!resource) {
resource = { fields: [] }
}
let selectStatement: string | (string | Knex.Raw)[] = "*"
// handle select
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)
}
// start building the query // start building the query
let query = this.knexWithAlias(knex, endpoint, tableAliases) let query = this.knexWithAlias(knex, endpoint, tableAliases)
// handle pagination // handle pagination
@ -650,7 +656,7 @@ class InternalBuilder {
}) })
// add sorting to pre-query // add sorting to pre-query
// no point in sorting when counting // no point in sorting when counting
if (!disableSorting) { if (!counting) {
query = this.addSorting(query, json) query = this.addSorting(query, json)
} }
@ -662,9 +668,13 @@ class InternalBuilder {
// be a table name, not a pre-query // be a table name, not a pre-query
[alias]: query as any, [alias]: query as any,
}) })
preQuery = preQuery.select(selectStatement) if (!counting) {
preQuery = preQuery.select(generateSelectStatement(json, knex))
} else {
preQuery = this.addDistinctCount(preQuery, json)
}
// have to add after as well (this breaks MS-SQL) // have to add after as well (this breaks MS-SQL)
if (this.client !== SqlClient.MS_SQL && !disableSorting) { if (this.client !== SqlClient.MS_SQL && !counting) {
preQuery = this.addSorting(preQuery, json) preQuery = this.addSorting(preQuery, json)
} }
// handle joins // handle joins
@ -688,17 +698,6 @@ class InternalBuilder {
}) })
} }
count(knex: Knex, json: QueryJson) {
const readQuery = this.read(knex, json, {
disableSorting: true,
})
// 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 { update(knex: Knex, json: QueryJson, opts: QueryOptions): Knex.QueryBuilder {
const { endpoint, body, filters, tableAliases } = json const { endpoint, body, filters, tableAliases } = json
let query = this.knexWithAlias(knex, endpoint, tableAliases) let query = this.knexWithAlias(knex, endpoint, tableAliases)
@ -781,7 +780,8 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
}) })
break break
case Operation.COUNT: case Operation.COUNT:
query = builder.count(client, json) // read without any limits to count
query = builder.read(client, json)
break break
case Operation.UPDATE: case Operation.UPDATE:
query = builder.update(client, json, opts) query = builder.update(client, json, opts)