Fix the problem, and the tests.
This commit is contained in:
parent
aea9cda8f5
commit
0b2a5162a4
|
@ -122,7 +122,7 @@ function generateSelectStatement(
|
|||
|
||||
const schema = meta.table.schema
|
||||
return resource.fields.map(field => {
|
||||
const [table, column, ..._rest] = field.split(/\./g)
|
||||
const [table, column, ...rest] = field.split(/\./g)
|
||||
if (
|
||||
client === SqlClient.POSTGRES &&
|
||||
schema[column].externalType?.includes("money")
|
||||
|
@ -138,13 +138,21 @@ function generateSelectStatement(
|
|||
// HH:mm format
|
||||
return knex.raw(`CONVERT(varchar, ${field}, 108) as "${field}"`)
|
||||
}
|
||||
return `${field} as ${field}`
|
||||
// return knex.raw(
|
||||
// `${quote(client, table)}.${quote(client, column)} as ${quote(
|
||||
// client,
|
||||
// field
|
||||
// )}`
|
||||
// )
|
||||
|
||||
// There's at least two edge cases being handled in the expression below.
|
||||
// 1. The column name could start/end with a space, and in that case we
|
||||
// want to preseve that space.
|
||||
// 2. Almost all column names are specified in the form table.column, except
|
||||
// in the case of relationships, where it's table.doc1.column. In that
|
||||
// case, we want to split it into `table`.`doc1.column` for reasons that
|
||||
// aren't actually clear to me, but `table`.`doc1` breaks things with the
|
||||
// sample data tests.
|
||||
return knex.raw(
|
||||
`${quote(client, table)}.${quote(
|
||||
client,
|
||||
[column, ...rest].join(".")
|
||||
)} as ${quote(client, field)}`
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -38,18 +38,18 @@ import { structures } from "@budibase/backend-core/tests"
|
|||
import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default"
|
||||
|
||||
describe.each([
|
||||
// ["in-memory", undefined],
|
||||
// ["lucene", undefined],
|
||||
["in-memory", undefined],
|
||||
["lucene", undefined],
|
||||
["sqs", undefined],
|
||||
// [DatabaseName.POSTGRES, getDatasource(DatabaseName.POSTGRES)],
|
||||
// [DatabaseName.MYSQL, getDatasource(DatabaseName.MYSQL)],
|
||||
// [DatabaseName.SQL_SERVER, getDatasource(DatabaseName.SQL_SERVER)],
|
||||
// [DatabaseName.MARIADB, getDatasource(DatabaseName.MARIADB)],
|
||||
[DatabaseName.POSTGRES, getDatasource(DatabaseName.POSTGRES)],
|
||||
[DatabaseName.MYSQL, getDatasource(DatabaseName.MYSQL)],
|
||||
[DatabaseName.SQL_SERVER, getDatasource(DatabaseName.SQL_SERVER)],
|
||||
[DatabaseName.MARIADB, getDatasource(DatabaseName.MARIADB)],
|
||||
])("search (%s)", (name, dsProvider) => {
|
||||
const isSqs = name === "sqs"
|
||||
const isLucene = name === "lucene"
|
||||
const isInMemory = name === "in-memory"
|
||||
const isInternal = isSqs || isLucene
|
||||
const isInternal = isSqs || isLucene || isInMemory
|
||||
const config = setup.getConfig()
|
||||
|
||||
let envCleanup: (() => void) | undefined
|
||||
|
@ -115,10 +115,7 @@ describe.each([
|
|||
if (isInMemory) {
|
||||
return dataFilters.search(_.cloneDeep(rows), this.query)
|
||||
} else {
|
||||
return config.api.row.search(table._id!, {
|
||||
...this.query,
|
||||
tableId: table._id!,
|
||||
})
|
||||
return config.api.row.search(this.query.tableId, this.query)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +184,15 @@ describe.each([
|
|||
return row
|
||||
}
|
||||
|
||||
// By default, the global `table` variable is used to search against. If you
|
||||
// need to, though, you can specify a different table to search against. You
|
||||
// may wish to do this in a nested describe block that defines a different
|
||||
// table.
|
||||
againstTable(table: Table) {
|
||||
this.query.tableId = table._id!
|
||||
return this
|
||||
}
|
||||
|
||||
// Asserts that the query returns rows matching exactly the set of rows
|
||||
// passed in. The order of the rows matters. Rows returned in an order
|
||||
// different to the one passed in will cause the assertion to fail. Extra
|
||||
|
@ -735,29 +741,6 @@ describe.each([
|
|||
query: {},
|
||||
}).toHaveLength(1)
|
||||
})
|
||||
|
||||
isInternal &&
|
||||
describe("space at end of column name", () => {
|
||||
beforeAll(async () => {
|
||||
table = await createTable({
|
||||
"name ": {
|
||||
name: "name ",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
})
|
||||
await createRows([{ ["name "]: "foo" }, { ["name "]: "bar" }])
|
||||
})
|
||||
|
||||
it("should be able to query a column that starts with a space", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
string: {
|
||||
"1:name ": "foo",
|
||||
},
|
||||
},
|
||||
}).toContainExactly([{ ["name "]: "foo" }])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("equal", () => {
|
||||
|
@ -2205,8 +2188,7 @@ describe.each([
|
|||
}).toContainExactly([{ name: "baz", productCat: undefined }])
|
||||
})
|
||||
})
|
||||
|
||||
isInternal &&
|
||||
;(isSqs || isLucene) &&
|
||||
describe("relations to same table", () => {
|
||||
let relatedTable: Table, relatedRows: Row[]
|
||||
|
||||
|
@ -2394,6 +2376,7 @@ describe.each([
|
|||
beforeAll(async () => {
|
||||
await config.api.application.addSampleData(config.appId!)
|
||||
table = DEFAULT_EMPLOYEE_TABLE_SCHEMA
|
||||
rows = await config.api.row.fetch(table._id!)
|
||||
})
|
||||
|
||||
it("should be able to search sample data", async () => {
|
||||
|
@ -2478,4 +2461,76 @@ describe.each([
|
|||
}).toContainExactly([{ [name]: "a" }])
|
||||
})
|
||||
})
|
||||
|
||||
// This is currently not supported in external datasources, it produces SQL
|
||||
// errors at time of writing. We supported it (potentially by accident) in
|
||||
// Lucene, though, so we need to make sure it's supported in SQS as well. We
|
||||
// found real cases in production of column names ending in a space.
|
||||
isInternal &&
|
||||
describe("space at end of column name", () => {
|
||||
beforeAll(async () => {
|
||||
table = await createTable({
|
||||
"name ": {
|
||||
name: "name ",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
})
|
||||
await createRows([{ ["name "]: "foo" }, { ["name "]: "bar" }])
|
||||
})
|
||||
|
||||
it("should be able to query a column that ends with a space", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
string: {
|
||||
"name ": "foo",
|
||||
},
|
||||
},
|
||||
}).toContainExactly([{ ["name "]: "foo" }])
|
||||
})
|
||||
|
||||
it("should be able to query a column that ends with a space using numeric notation", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
string: {
|
||||
"1:name ": "foo",
|
||||
},
|
||||
},
|
||||
}).toContainExactly([{ ["name "]: "foo" }])
|
||||
})
|
||||
})
|
||||
|
||||
// This was never actually supported in Lucene but SQS does support it, so may
|
||||
// as well have a test for it.
|
||||
;(isSqs || isInMemory) &&
|
||||
describe("space at start of column name", () => {
|
||||
beforeAll(async () => {
|
||||
table = await createTable({
|
||||
" name": {
|
||||
name: " name",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
})
|
||||
await createRows([{ [" name"]: "foo" }, { [" name"]: "bar" }])
|
||||
})
|
||||
|
||||
it("should be able to query a column that starts with a space", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
string: {
|
||||
" name": "foo",
|
||||
},
|
||||
},
|
||||
}).toContainExactly([{ [" name"]: "foo" }])
|
||||
})
|
||||
|
||||
it("should be able to query a column that starts with a space using numeric notation", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
string: {
|
||||
"1: name": "foo",
|
||||
},
|
||||
},
|
||||
}).toContainExactly([{ [" name"]: "foo" }])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -210,7 +210,6 @@ async function runSqlQuery(
|
|||
let bindings = query.bindings
|
||||
|
||||
// quick hack for docIds
|
||||
|
||||
const fixJunctionDocs = (field: string) =>
|
||||
["doc1", "doc2"].forEach(doc => {
|
||||
sql = sql.replaceAll(`\`${doc}\`.\`${field}\``, `\`${doc}.${field}\``)
|
||||
|
|
Loading…
Reference in New Issue