All tests passing.
This commit is contained in:
parent
402afa1df6
commit
e2a1ab7eaf
2 changed files with 78 additions and 25 deletions
|
@ -22,12 +22,12 @@ import tk from "timekeeper"
|
|||
import { encodeJSBinding } from "@budibase/string-templates"
|
||||
|
||||
describe.each([
|
||||
//["lucene", 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)],
|
||||
])("/api/:sourceId/search (%s)", (name, dsProvider) => {
|
||||
const isSqs = name === "sqs"
|
||||
const isLucene = name === "lucene"
|
||||
|
@ -1288,6 +1288,7 @@ describe.each([
|
|||
await createRows([
|
||||
{ user: JSON.stringify(user1) },
|
||||
{ user: JSON.stringify(user2) },
|
||||
{ user: null },
|
||||
])
|
||||
})
|
||||
|
||||
|
@ -1305,12 +1306,14 @@ describe.each([
|
|||
it("successfully finds a row", () =>
|
||||
expectQuery({ notEqual: { user: user1._id } }).toContainExactly([
|
||||
{ user: { _id: user2._id } },
|
||||
{},
|
||||
]))
|
||||
|
||||
it("fails to find nonexistent row", () =>
|
||||
expectQuery({ notEqual: { user: "us_none" } }).toContainExactly([
|
||||
{ user: { _id: user1._id } },
|
||||
{ user: { _id: user2._id } },
|
||||
{ user: {} },
|
||||
]))
|
||||
})
|
||||
|
||||
|
@ -1323,6 +1326,19 @@ describe.each([
|
|||
it("fails to find nonexistent row", () =>
|
||||
expectQuery({ oneOf: { user: ["us_none"] } }).toFindNothing())
|
||||
})
|
||||
|
||||
describe("empty", () => {
|
||||
it("finds empty rows", () =>
|
||||
expectQuery({ empty: { user: null } }).toContainExactly([{}]))
|
||||
})
|
||||
|
||||
describe("notEmpty", () => {
|
||||
it("finds non-empty rows", () =>
|
||||
expectQuery({ notEmpty: { user: null } }).toContainExactly([
|
||||
{ user: { _id: user1._id } },
|
||||
{ user: { _id: user2._id } },
|
||||
]))
|
||||
})
|
||||
})
|
||||
|
||||
describe("multi user", () => {
|
||||
|
@ -1338,14 +1354,19 @@ describe.each([
|
|||
name: "users",
|
||||
type: FieldType.BB_REFERENCE,
|
||||
subtype: BBReferenceFieldSubType.USER,
|
||||
constraints: { type: "array" },
|
||||
},
|
||||
number: {
|
||||
name: "number",
|
||||
type: FieldType.NUMBER,
|
||||
},
|
||||
})
|
||||
|
||||
await createRows([
|
||||
{ users: JSON.stringify([user1]) },
|
||||
{ users: JSON.stringify([user2]) },
|
||||
{ users: JSON.stringify([user1, user2]) },
|
||||
{ users: JSON.stringify([]) },
|
||||
{ number: 1, users: JSON.stringify([user1]) },
|
||||
{ number: 2, users: JSON.stringify([user2]) },
|
||||
{ number: 3, users: JSON.stringify([user1, user2]) },
|
||||
{ number: 4, users: JSON.stringify([]) },
|
||||
])
|
||||
})
|
||||
|
||||
|
@ -1389,5 +1410,19 @@ describe.each([
|
|||
it("fails to find nonexistent row", () =>
|
||||
expectQuery({ containsAny: { users: ["us_none"] } }).toFindNothing())
|
||||
})
|
||||
|
||||
describe("multi-column equals", () => {
|
||||
it("successfully finds a row", () =>
|
||||
expectQuery({
|
||||
equal: { number: 1 },
|
||||
contains: { users: [user1._id] },
|
||||
}).toContainExactly([{ users: [{ _id: user1._id }], number: 1 }]))
|
||||
|
||||
it("fails to find nonexistent row", () =>
|
||||
expectQuery({
|
||||
equal: { number: 2 },
|
||||
contains: { users: [user1._id] },
|
||||
}).toFindNothing())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -226,8 +226,7 @@ class InternalBuilder {
|
|||
}
|
||||
|
||||
const contains = (mode: object, any: boolean = false) => {
|
||||
const fnc = allOr ? "orWhere" : "where"
|
||||
const rawFnc = `${fnc}Raw`
|
||||
const rawFnc = allOr ? "orWhereRaw" : "whereRaw"
|
||||
const not = mode === filters?.notContains ? "NOT " : ""
|
||||
function stringifyArray(value: Array<any>, quoteStyle = '"'): string {
|
||||
for (let i in value) {
|
||||
|
@ -240,24 +239,24 @@ class InternalBuilder {
|
|||
if (this.client === SqlClient.POSTGRES) {
|
||||
iterate(mode, (key: string, value: Array<any>) => {
|
||||
const wrap = any ? "" : "'"
|
||||
const containsOp = any ? "\\?| array" : "@>"
|
||||
const op = any ? "\\?| array" : "@>"
|
||||
const fieldNames = key.split(/\./g)
|
||||
const tableName = fieldNames[0]
|
||||
const columnName = fieldNames[1]
|
||||
// @ts-ignore
|
||||
const table = fieldNames[0]
|
||||
const col = fieldNames[1]
|
||||
query = query[rawFnc](
|
||||
`${not}"${tableName}"."${columnName}"::jsonb ${containsOp} ${wrap}${stringifyArray(
|
||||
`${not}COALESCE("${table}"."${col}"::jsonb ${op} ${wrap}${stringifyArray(
|
||||
value,
|
||||
any ? "'" : '"'
|
||||
)}${wrap}`
|
||||
)}${wrap}, FALSE)`
|
||||
)
|
||||
})
|
||||
} else if (this.client === SqlClient.MY_SQL) {
|
||||
const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS"
|
||||
iterate(mode, (key: string, value: Array<any>) => {
|
||||
// @ts-ignore
|
||||
query = query[rawFnc](
|
||||
`${not}${jsonFnc}(${key}, '${stringifyArray(value)}')`
|
||||
`${not}COALESCE(${jsonFnc}(${key}, '${stringifyArray(
|
||||
value
|
||||
)}'), FALSE)`
|
||||
)
|
||||
})
|
||||
} else {
|
||||
|
@ -272,8 +271,7 @@ class InternalBuilder {
|
|||
}
|
||||
statement +=
|
||||
(statement ? andOr : "") +
|
||||
// `COALESCE(LOWER(${likeKey(this.client, key)}) LIKE ?, FALSE)`
|
||||
`LOWER(${likeKey(this.client, key)}) LIKE ?`
|
||||
`COALESCE(LOWER(${likeKey(this.client, key)}), '') LIKE ?`
|
||||
}
|
||||
|
||||
if (statement === "") {
|
||||
|
@ -338,14 +336,34 @@ class InternalBuilder {
|
|||
}
|
||||
if (filters.equal) {
|
||||
iterate(filters.equal, (key, value) => {
|
||||
const fnc = allOr ? "orWhere" : "where"
|
||||
query = query[fnc]({ [key]: value })
|
||||
const fnc = allOr ? "orWhereRaw" : "whereRaw"
|
||||
if (this.client === SqlClient.MS_SQL) {
|
||||
query = query[fnc](
|
||||
`CASE WHEN ${likeKey(this.client, key)} = ? THEN 1 ELSE 0 END = 1`,
|
||||
[value]
|
||||
)
|
||||
} else {
|
||||
query = query[fnc](
|
||||
`COALESCE(${likeKey(this.client, key)} = ?, FALSE)`,
|
||||
[value]
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (filters.notEqual) {
|
||||
iterate(filters.notEqual, (key, value) => {
|
||||
const fnc = allOr ? "orWhereNot" : "whereNot"
|
||||
query = query[fnc]({ [key]: value })
|
||||
const fnc = allOr ? "orWhereRaw" : "whereRaw"
|
||||
if (this.client === SqlClient.MS_SQL) {
|
||||
query = query[fnc](
|
||||
`CASE WHEN ${likeKey(this.client, key)} = ? THEN 1 ELSE 0 END = 0`,
|
||||
[value]
|
||||
)
|
||||
} else {
|
||||
query = query[fnc](
|
||||
`COALESCE(${likeKey(this.client, key)} != ?, TRUE)`,
|
||||
[value]
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (filters.empty) {
|
||||
|
|
Loading…
Reference in a new issue