1
0
Fork 0
mirror of synced 2024-08-23 14:01:34 +12:00

All tests passing.

This commit is contained in:
Sam Rose 2024-05-20 17:01:52 +01:00
parent 402afa1df6
commit e2a1ab7eaf
No known key found for this signature in database
2 changed files with 78 additions and 25 deletions

View file

@ -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())
})
})
})

View file

@ -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) {