Fix range queries.
This commit is contained in:
parent
0599257935
commit
bc7501f72b
|
@ -8,7 +8,6 @@ import {
|
||||||
sqlLog,
|
sqlLog,
|
||||||
isInvalidISODateString,
|
isInvalidISODateString,
|
||||||
} from "./utils"
|
} from "./utils"
|
||||||
import { SqlStatements } from "./sqlStatements"
|
|
||||||
import SqlTableQueryBuilder from "./sqlTable"
|
import SqlTableQueryBuilder from "./sqlTable"
|
||||||
import {
|
import {
|
||||||
AnySearchFilter,
|
AnySearchFilter,
|
||||||
|
@ -77,10 +76,12 @@ class InternalBuilder {
|
||||||
private readonly client: SqlClient
|
private readonly client: SqlClient
|
||||||
private readonly query: QueryJson
|
private readonly query: QueryJson
|
||||||
private readonly splitter: dataFilters.ColumnSplitter
|
private readonly splitter: dataFilters.ColumnSplitter
|
||||||
|
private readonly knex: Knex
|
||||||
|
|
||||||
constructor(client: SqlClient, query: QueryJson) {
|
constructor(client: SqlClient, knex: Knex, query: QueryJson) {
|
||||||
this.client = client
|
this.client = client
|
||||||
this.query = query
|
this.query = query
|
||||||
|
this.knex = knex
|
||||||
|
|
||||||
this.splitter = new dataFilters.ColumnSplitter([this.table], {
|
this.splitter = new dataFilters.ColumnSplitter([this.table], {
|
||||||
aliases: this.query.tableAliases,
|
aliases: this.query.tableAliases,
|
||||||
|
@ -92,6 +93,11 @@ class InternalBuilder {
|
||||||
return this.query.meta.table
|
return this.query.meta.table
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFieldSchema(key: string): FieldSchema | undefined {
|
||||||
|
const { column } = this.splitter.run(key)
|
||||||
|
return this.table.schema[column]
|
||||||
|
}
|
||||||
|
|
||||||
// Takes a string like foo and returns a quoted string like [foo] for SQL Server
|
// Takes a string like foo and returns a quoted string like [foo] for SQL Server
|
||||||
// and "foo" for Postgres.
|
// and "foo" for Postgres.
|
||||||
private quote(str: string): string {
|
private quote(str: string): string {
|
||||||
|
@ -116,9 +122,8 @@ class InternalBuilder {
|
||||||
.join(".")
|
.join(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateSelectStatement(knex: Knex): (string | Knex.Raw)[] | "*" {
|
private generateSelectStatement(): (string | Knex.Raw)[] | "*" {
|
||||||
const { resource, meta } = this.query
|
const { resource, meta } = this.query
|
||||||
const client = knex.client.config.client as SqlClient
|
|
||||||
|
|
||||||
if (!resource || !resource.fields || resource.fields.length === 0) {
|
if (!resource || !resource.fields || resource.fields.length === 0) {
|
||||||
return "*"
|
return "*"
|
||||||
|
@ -154,10 +159,10 @@ class InternalBuilder {
|
||||||
const columnSchema = schema[column]
|
const columnSchema = schema[column]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
client === SqlClient.POSTGRES &&
|
this.client === SqlClient.POSTGRES &&
|
||||||
columnSchema?.externalType?.includes("money")
|
columnSchema?.externalType?.includes("money")
|
||||||
) {
|
) {
|
||||||
return knex.raw(
|
return this.knex.raw(
|
||||||
`${this.quotedIdentifier(
|
`${this.quotedIdentifier(
|
||||||
[table, column].join(".")
|
[table, column].join(".")
|
||||||
)}::money::numeric as ${this.quote(field)}`
|
)}::money::numeric as ${this.quote(field)}`
|
||||||
|
@ -165,13 +170,13 @@ class InternalBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
client === SqlClient.MS_SQL &&
|
this.client === SqlClient.MS_SQL &&
|
||||||
columnSchema?.type === FieldType.DATETIME &&
|
columnSchema?.type === FieldType.DATETIME &&
|
||||||
columnSchema.timeOnly
|
columnSchema.timeOnly
|
||||||
) {
|
) {
|
||||||
// Time gets returned as timestamp from mssql, not matching the expected
|
// Time gets returned as timestamp from mssql, not matching the expected
|
||||||
// HH:mm format
|
// HH:mm format
|
||||||
return knex.raw(`CONVERT(varchar, ${field}, 108) as "${field}"`)
|
return this.knex.raw(`CONVERT(varchar, ${field}, 108) as "${field}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's at least two edge cases being handled in the expression below.
|
// There's at least two edge cases being handled in the expression below.
|
||||||
|
@ -183,11 +188,11 @@ class InternalBuilder {
|
||||||
// aren't actually clear to me, but `table`.`doc1` breaks things with the
|
// aren't actually clear to me, but `table`.`doc1` breaks things with the
|
||||||
// sample data tests.
|
// sample data tests.
|
||||||
if (table) {
|
if (table) {
|
||||||
return knex.raw(
|
return this.knex.raw(
|
||||||
`${this.quote(table)}.${this.quote(column)} as ${this.quote(field)}`
|
`${this.quote(table)}.${this.quote(column)} as ${this.quote(field)}`
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return knex.raw(`${this.quote(field)} as ${this.quote(field)}`)
|
return this.knex.raw(`${this.quote(field)} as ${this.quote(field)}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -333,10 +338,6 @@ class InternalBuilder {
|
||||||
const aliases = this.query.tableAliases
|
const aliases = this.query.tableAliases
|
||||||
// if all or specified in filters, then everything is an or
|
// if all or specified in filters, then everything is an or
|
||||||
const allOr = filters.allOr
|
const allOr = filters.allOr
|
||||||
const sqlStatements = new SqlStatements(this.client, this.table, {
|
|
||||||
allOr,
|
|
||||||
columnPrefix: this.query.meta.columnPrefix,
|
|
||||||
})
|
|
||||||
const tableName =
|
const tableName =
|
||||||
this.client === SqlClient.SQL_LITE ? this.table._id! : this.table.name
|
this.client === SqlClient.SQL_LITE ? this.table._id! : this.table.name
|
||||||
|
|
||||||
|
@ -506,12 +507,53 @@ class InternalBuilder {
|
||||||
}
|
}
|
||||||
const lowValid = isValidFilter(value.low),
|
const lowValid = isValidFilter(value.low),
|
||||||
highValid = isValidFilter(value.high)
|
highValid = isValidFilter(value.high)
|
||||||
|
|
||||||
|
const schema = this.getFieldSchema(key)
|
||||||
|
|
||||||
|
if (this.client === SqlClient.ORACLE) {
|
||||||
|
// @ts-ignore
|
||||||
|
key = this.knex.raw(this.convertClobs(key))
|
||||||
|
}
|
||||||
|
|
||||||
if (lowValid && highValid) {
|
if (lowValid && highValid) {
|
||||||
query = sqlStatements.between(query, key, value.low, value.high)
|
if (
|
||||||
|
schema?.type === FieldType.BIGINT &&
|
||||||
|
this.client === SqlClient.SQL_LITE
|
||||||
|
) {
|
||||||
|
query = query.whereRaw(
|
||||||
|
`CAST(${key} AS INTEGER) BETWEEN CAST(? AS INTEGER) AND CAST(? AS INTEGER)`,
|
||||||
|
[value.low, value.high]
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
const fnc = allOr ? "orWhereBetween" : "whereBetween"
|
||||||
|
query = query[fnc](key, [value.low, value.high])
|
||||||
|
}
|
||||||
} else if (lowValid) {
|
} else if (lowValid) {
|
||||||
query = sqlStatements.lte(query, key, value.low)
|
if (
|
||||||
|
schema?.type === FieldType.BIGINT &&
|
||||||
|
this.client === SqlClient.SQL_LITE
|
||||||
|
) {
|
||||||
|
query = query.whereRaw(
|
||||||
|
`CAST(${key} AS INTEGER) >= CAST(? AS INTEGER)`,
|
||||||
|
[value.low]
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
const fnc = allOr ? "orWhere" : "where"
|
||||||
|
query = query[fnc](key, ">=", value.low)
|
||||||
|
}
|
||||||
} else if (highValid) {
|
} else if (highValid) {
|
||||||
query = sqlStatements.gte(query, key, value.high)
|
if (
|
||||||
|
schema?.type === FieldType.BIGINT &&
|
||||||
|
this.client === SqlClient.SQL_LITE
|
||||||
|
) {
|
||||||
|
query = query.whereRaw(
|
||||||
|
`CAST(${key} AS INTEGER) <= CAST(? AS INTEGER)`,
|
||||||
|
[value.high]
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
const fnc = allOr ? "orWhere" : "where"
|
||||||
|
query = query[fnc](key, "<=", value.high)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -621,17 +663,19 @@ class InternalBuilder {
|
||||||
for (let [key, value] of Object.entries(sort)) {
|
for (let [key, value] of Object.entries(sort)) {
|
||||||
const direction =
|
const direction =
|
||||||
value.direction === SortOrder.ASCENDING ? "asc" : "desc"
|
value.direction === SortOrder.ASCENDING ? "asc" : "desc"
|
||||||
let nulls
|
const nulls = value.direction === SortOrder.ASCENDING ? "first" : "last"
|
||||||
if (
|
|
||||||
this.client === SqlClient.POSTGRES ||
|
|
||||||
this.client === SqlClient.ORACLE
|
|
||||||
) {
|
|
||||||
// All other clients already sort this as expected by default, and
|
|
||||||
// adding this to the rest of the clients is causing issues
|
|
||||||
nulls = value.direction === SortOrder.ASCENDING ? "first" : "last"
|
|
||||||
}
|
|
||||||
|
|
||||||
query = query.orderBy(`${aliased}.${key}`, direction, nulls)
|
let composite = `${aliased}.${key}`
|
||||||
|
if (this.client === SqlClient.ORACLE) {
|
||||||
|
query = query.orderBy(
|
||||||
|
// @ts-ignore
|
||||||
|
this.knex.raw(this.convertClobs(composite)),
|
||||||
|
direction,
|
||||||
|
nulls
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
query = query.orderBy(composite, direction, nulls)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,17 +776,14 @@ class InternalBuilder {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
qualifiedKnex(
|
qualifiedKnex(opts?: { alias?: string | boolean }): Knex.QueryBuilder {
|
||||||
knex: Knex,
|
|
||||||
opts?: { alias?: string | boolean }
|
|
||||||
): Knex.QueryBuilder {
|
|
||||||
let alias = this.query.tableAliases?.[this.query.endpoint.entityId]
|
let alias = this.query.tableAliases?.[this.query.endpoint.entityId]
|
||||||
if (opts?.alias === false) {
|
if (opts?.alias === false) {
|
||||||
alias = undefined
|
alias = undefined
|
||||||
} else if (typeof opts?.alias === "string") {
|
} else if (typeof opts?.alias === "string") {
|
||||||
alias = opts.alias
|
alias = opts.alias
|
||||||
}
|
}
|
||||||
return knex(
|
return this.knex(
|
||||||
this.tableNameWithSchema(this.query.endpoint.entityId, {
|
this.tableNameWithSchema(this.query.endpoint.entityId, {
|
||||||
alias,
|
alias,
|
||||||
schema: this.query.endpoint.schema,
|
schema: this.query.endpoint.schema,
|
||||||
|
@ -750,9 +791,9 @@ class InternalBuilder {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
create(knex: Knex, opts: QueryOptions): Knex.QueryBuilder {
|
create(opts: QueryOptions): Knex.QueryBuilder {
|
||||||
const { body } = this.query
|
const { body } = this.query
|
||||||
let query = this.qualifiedKnex(knex, { alias: false })
|
let query = this.qualifiedKnex({ alias: false })
|
||||||
const parsedBody = this.parseBody(body)
|
const parsedBody = this.parseBody(body)
|
||||||
// make sure no null values in body for creation
|
// make sure no null values in body for creation
|
||||||
for (let [key, value] of Object.entries(parsedBody)) {
|
for (let [key, value] of Object.entries(parsedBody)) {
|
||||||
|
@ -769,9 +810,9 @@ class InternalBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkCreate(knex: Knex): Knex.QueryBuilder {
|
bulkCreate(): Knex.QueryBuilder {
|
||||||
const { body } = this.query
|
const { body } = this.query
|
||||||
let query = this.qualifiedKnex(knex, { alias: false })
|
let query = this.qualifiedKnex({ alias: false })
|
||||||
if (!Array.isArray(body)) {
|
if (!Array.isArray(body)) {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
@ -779,9 +820,9 @@ class InternalBuilder {
|
||||||
return query.insert(parsedBody)
|
return query.insert(parsedBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkUpsert(knex: Knex): Knex.QueryBuilder {
|
bulkUpsert(): Knex.QueryBuilder {
|
||||||
const { body } = this.query
|
const { body } = this.query
|
||||||
let query = this.qualifiedKnex(knex, { alias: false })
|
let query = this.qualifiedKnex({ alias: false })
|
||||||
if (!Array.isArray(body)) {
|
if (!Array.isArray(body)) {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
@ -809,7 +850,6 @@ class InternalBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
read(
|
read(
|
||||||
knex: Knex,
|
|
||||||
opts: {
|
opts: {
|
||||||
limits?: { base: number; query: number }
|
limits?: { base: number; query: number }
|
||||||
} = {}
|
} = {}
|
||||||
|
@ -821,7 +861,7 @@ class InternalBuilder {
|
||||||
|
|
||||||
const tableName = endpoint.entityId
|
const tableName = endpoint.entityId
|
||||||
// start building the query
|
// start building the query
|
||||||
let query = this.qualifiedKnex(knex)
|
let query = this.qualifiedKnex()
|
||||||
// handle pagination
|
// handle pagination
|
||||||
let foundOffset: number | null = null
|
let foundOffset: number | null = null
|
||||||
let foundLimit = limits?.query || limits?.base
|
let foundLimit = limits?.query || limits?.base
|
||||||
|
@ -855,7 +895,7 @@ class InternalBuilder {
|
||||||
query = this.addFilters(query, filters)
|
query = this.addFilters(query, filters)
|
||||||
|
|
||||||
const alias = tableAliases?.[tableName] || tableName
|
const alias = tableAliases?.[tableName] || tableName
|
||||||
let preQuery: Knex.QueryBuilder = knex({
|
let preQuery: Knex.QueryBuilder = this.knex({
|
||||||
// the typescript definition for the knex constructor doesn't support this
|
// the typescript definition for the knex constructor doesn't support this
|
||||||
// syntax, but it is the only way to alias a pre-query result as part of
|
// syntax, but it is the only way to alias a pre-query result as part of
|
||||||
// a query - there is an alias dictionary type, but it assumes it can only
|
// a query - there is an alias dictionary type, but it assumes it can only
|
||||||
|
@ -864,7 +904,7 @@ class InternalBuilder {
|
||||||
})
|
})
|
||||||
// if counting, use distinct count, else select
|
// if counting, use distinct count, else select
|
||||||
preQuery = !counting
|
preQuery = !counting
|
||||||
? preQuery.select(this.generateSelectStatement(knex))
|
? preQuery.select(this.generateSelectStatement())
|
||||||
: this.addDistinctCount(preQuery)
|
: this.addDistinctCount(preQuery)
|
||||||
// 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 && !counting) {
|
if (this.client !== SqlClient.MS_SQL && !counting) {
|
||||||
|
@ -888,9 +928,9 @@ class InternalBuilder {
|
||||||
return this.addFilters(query, filters, { relationship: true })
|
return this.addFilters(query, filters, { relationship: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
update(knex: Knex, opts: QueryOptions): Knex.QueryBuilder {
|
update(opts: QueryOptions): Knex.QueryBuilder {
|
||||||
const { body, filters } = this.query
|
const { body, filters } = this.query
|
||||||
let query = this.qualifiedKnex(knex)
|
let query = this.qualifiedKnex()
|
||||||
const parsedBody = this.parseBody(body)
|
const parsedBody = this.parseBody(body)
|
||||||
query = this.addFilters(query, filters)
|
query = this.addFilters(query, filters)
|
||||||
// mysql can't use returning
|
// mysql can't use returning
|
||||||
|
@ -901,15 +941,15 @@ class InternalBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(knex: Knex, opts: QueryOptions): Knex.QueryBuilder {
|
delete(opts: QueryOptions): Knex.QueryBuilder {
|
||||||
const { filters } = this.query
|
const { filters } = this.query
|
||||||
let query = this.qualifiedKnex(knex)
|
let query = this.qualifiedKnex()
|
||||||
query = this.addFilters(query, filters)
|
query = this.addFilters(query, filters)
|
||||||
// mysql can't use returning
|
// mysql can't use returning
|
||||||
if (opts.disableReturning) {
|
if (opts.disableReturning) {
|
||||||
return query.delete()
|
return query.delete()
|
||||||
} else {
|
} else {
|
||||||
return query.delete().returning(this.generateSelectStatement(knex))
|
return query.delete().returning(this.generateSelectStatement())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -953,13 +993,13 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
|
||||||
|
|
||||||
const client = knex(config)
|
const client = knex(config)
|
||||||
let query: Knex.QueryBuilder
|
let query: Knex.QueryBuilder
|
||||||
const builder = new InternalBuilder(sqlClient, json)
|
const builder = new InternalBuilder(sqlClient, client, json)
|
||||||
switch (this._operation(json)) {
|
switch (this._operation(json)) {
|
||||||
case Operation.CREATE:
|
case Operation.CREATE:
|
||||||
query = builder.create(client, opts)
|
query = builder.create(opts)
|
||||||
break
|
break
|
||||||
case Operation.READ:
|
case Operation.READ:
|
||||||
query = builder.read(client, {
|
query = builder.read({
|
||||||
limits: {
|
limits: {
|
||||||
query: this.limit,
|
query: this.limit,
|
||||||
base: BASE_LIMIT,
|
base: BASE_LIMIT,
|
||||||
|
@ -968,19 +1008,19 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
|
||||||
break
|
break
|
||||||
case Operation.COUNT:
|
case Operation.COUNT:
|
||||||
// read without any limits to count
|
// read without any limits to count
|
||||||
query = builder.read(client)
|
query = builder.read()
|
||||||
break
|
break
|
||||||
case Operation.UPDATE:
|
case Operation.UPDATE:
|
||||||
query = builder.update(client, opts)
|
query = builder.update(opts)
|
||||||
break
|
break
|
||||||
case Operation.DELETE:
|
case Operation.DELETE:
|
||||||
query = builder.delete(client, opts)
|
query = builder.delete(opts)
|
||||||
break
|
break
|
||||||
case Operation.BULK_CREATE:
|
case Operation.BULK_CREATE:
|
||||||
query = builder.bulkCreate(client)
|
query = builder.bulkCreate()
|
||||||
break
|
break
|
||||||
case Operation.BULK_UPSERT:
|
case Operation.BULK_UPSERT:
|
||||||
query = builder.bulkUpsert(client)
|
query = builder.bulkUpsert()
|
||||||
break
|
break
|
||||||
case Operation.CREATE_TABLE:
|
case Operation.CREATE_TABLE:
|
||||||
case Operation.UPDATE_TABLE:
|
case Operation.UPDATE_TABLE:
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
import { FieldType, Table, FieldSchema, SqlClient } from "@budibase/types"
|
|
||||||
import { Knex } from "knex"
|
|
||||||
|
|
||||||
export class SqlStatements {
|
|
||||||
client: string
|
|
||||||
table: Table
|
|
||||||
allOr: boolean | undefined
|
|
||||||
columnPrefix: string | undefined
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
client: string,
|
|
||||||
table: Table,
|
|
||||||
{ allOr, columnPrefix }: { allOr?: boolean; columnPrefix?: string } = {}
|
|
||||||
) {
|
|
||||||
this.client = client
|
|
||||||
this.table = table
|
|
||||||
this.allOr = allOr
|
|
||||||
this.columnPrefix = columnPrefix
|
|
||||||
}
|
|
||||||
|
|
||||||
getField(key: string): FieldSchema | undefined {
|
|
||||||
const fieldName = key.split(".")[1]
|
|
||||||
let found = this.table.schema[fieldName]
|
|
||||||
if (!found && this.columnPrefix) {
|
|
||||||
const prefixRemovedFieldName = fieldName.replace(this.columnPrefix, "")
|
|
||||||
found = this.table.schema[prefixRemovedFieldName]
|
|
||||||
}
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
|
|
||||||
between(
|
|
||||||
query: Knex.QueryBuilder,
|
|
||||||
key: string,
|
|
||||||
low: number | string,
|
|
||||||
high: number | string
|
|
||||||
) {
|
|
||||||
// Use a between operator if we have 2 valid range values
|
|
||||||
const field = this.getField(key)
|
|
||||||
if (
|
|
||||||
field?.type === FieldType.BIGINT &&
|
|
||||||
this.client === SqlClient.SQL_LITE
|
|
||||||
) {
|
|
||||||
query = query.whereRaw(
|
|
||||||
`CAST(${key} AS INTEGER) BETWEEN CAST(? AS INTEGER) AND CAST(? AS INTEGER)`,
|
|
||||||
[low, high]
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
const fnc = this.allOr ? "orWhereBetween" : "whereBetween"
|
|
||||||
query = query[fnc](key, [low, high])
|
|
||||||
}
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
|
|
||||||
lte(query: Knex.QueryBuilder, key: string, low: number | string) {
|
|
||||||
// Use just a single greater than operator if we only have a low
|
|
||||||
const field = this.getField(key)
|
|
||||||
if (
|
|
||||||
field?.type === FieldType.BIGINT &&
|
|
||||||
this.client === SqlClient.SQL_LITE
|
|
||||||
) {
|
|
||||||
query = query.whereRaw(`CAST(${key} AS INTEGER) >= CAST(? AS INTEGER)`, [
|
|
||||||
low,
|
|
||||||
])
|
|
||||||
} else {
|
|
||||||
const fnc = this.allOr ? "orWhere" : "where"
|
|
||||||
query = query[fnc](key, ">=", low)
|
|
||||||
}
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
|
|
||||||
gte(query: Knex.QueryBuilder, key: string, high: number | string) {
|
|
||||||
const field = this.getField(key)
|
|
||||||
// Use just a single less than operator if we only have a high
|
|
||||||
if (
|
|
||||||
field?.type === FieldType.BIGINT &&
|
|
||||||
this.client === SqlClient.SQL_LITE
|
|
||||||
) {
|
|
||||||
query = query.whereRaw(`CAST(${key} AS INTEGER) <= CAST(? AS INTEGER)`, [
|
|
||||||
high,
|
|
||||||
])
|
|
||||||
} else {
|
|
||||||
const fnc = this.allOr ? "orWhere" : "where"
|
|
||||||
query = query[fnc](key, "<=", high)
|
|
||||||
}
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -958,7 +958,7 @@ describe.each([
|
||||||
}).toMatchExactly([{ name: "bar" }, { name: "foo" }])
|
}).toMatchExactly([{ name: "bar" }, { name: "foo" }])
|
||||||
})
|
})
|
||||||
|
|
||||||
it.only("sorts descending", async () => {
|
it("sorts descending", async () => {
|
||||||
await expectSearch({
|
await expectSearch({
|
||||||
query: {},
|
query: {},
|
||||||
sort: "name",
|
sort: "name",
|
||||||
|
|
Loading…
Reference in New Issue