This commit is contained in:
Sam Rose 2024-11-06 10:42:50 +00:00
parent 85d42002f9
commit a344f2216c
No known key found for this signature in database
2 changed files with 3558 additions and 3467 deletions

View File

@ -1,8 +1,7 @@
import { tableForDatasource } from "../../../tests/utilities/structures" import { tableForDatasource } from "../../../tests/utilities/structures"
import { import {
DatabaseName, DatabaseName,
getDatasource, datasourceDescribe,
knexClient,
} from "../../../integrations/tests/utils" } from "../../../integrations/tests/utils"
import { import {
context, context,
@ -15,7 +14,6 @@ import {
withEnv as withCoreEnv, withEnv as withCoreEnv,
} from "@budibase/backend-core" } from "@budibase/backend-core"
import * as setup from "./utilities"
import { import {
AIOperationEnum, AIOperationEnum,
AutoFieldSubType, AutoFieldSubType,
@ -60,21 +58,13 @@ jest.mock("@budibase/pro", () => ({
}, },
})) }))
describe.each([ datasourceDescribe(
["in-memory", undefined], {
["sqs", undefined], name: "search (%s)",
[DatabaseName.POSTGRES, getDatasource(DatabaseName.POSTGRES)], // exclude: [DatabaseName.MONGODB],
[DatabaseName.MYSQL, getDatasource(DatabaseName.MYSQL)], only: [DatabaseName.SQS],
[DatabaseName.SQL_SERVER, getDatasource(DatabaseName.SQL_SERVER)], },
[DatabaseName.MARIADB, getDatasource(DatabaseName.MARIADB)], ({ config, dsProvider, isInternal, isOracle, isSql }) => {
[DatabaseName.ORACLE, getDatasource(DatabaseName.ORACLE)],
])("search (%s)", (name, dsProvider) => {
const isInMemory = name === "in-memory"
const isInternal = !dsProvider
const isOracle = name === DatabaseName.ORACLE
const isSql = !isInMemory
const config = setup.getConfig()
let datasource: Datasource | undefined let datasource: Datasource | undefined
let client: Knex | undefined let client: Knex | undefined
let tableOrViewId: string let tableOrViewId: string
@ -105,8 +95,6 @@ describe.each([
} }
beforeAll(async () => { beforeAll(async () => {
await config.init()
if (config.app?.appId) { if (config.app?.appId) {
config.app = await config.api.application.update(config.app?.appId, { config.app = await config.api.application.update(config.app?.appId, {
snippets: [ snippets: [
@ -118,17 +106,9 @@ describe.each([
}) })
} }
if (dsProvider) { const ds = await dsProvider
const rawDatasource = await dsProvider datasource = ds.datasource
client = await knexClient(rawDatasource) client = ds.client
datasource = await config.createDatasource({
datasource: rawDatasource,
})
}
})
afterAll(async () => {
setup.afterAll()
}) })
async function createTable(schema?: TableSchema) { async function createTable(schema?: TableSchema) {
@ -181,9 +161,17 @@ describe.each([
expect(count).toEqual(numRows) expect(count).toEqual(numRows)
} }
describe.each([ describe.each([true, false])("in-memory: %s", isInMemory => {
["table", createTable], // We only run the in-memory tests during the SQS (isInternal) run
[ if (isInMemory && !isInternal) {
return
}
type CreateFn = (schema?: TableSchema) => Promise<string>
let tableOrView: [string, CreateFn][] = [["table", createTable]]
if (!isInMemory) {
tableOrView.push([
"view", "view",
async (schema?: TableSchema) => { async (schema?: TableSchema) => {
const tableId = await createTable(schema) const tableId = await createTable(schema)
@ -203,8 +191,10 @@ describe.each([
) )
return viewId return viewId
}, },
], ])
])("from %s", (sourceType, createTableOrView) => { }
describe.each(tableOrView)("from %s", (sourceType, createTableOrView) => {
const isView = sourceType === "view" const isView = sourceType === "view"
class SearchAssertion { class SearchAssertion {
@ -227,7 +217,10 @@ describe.each([
// the source array is an exact match of the target. // the source array is an exact match of the target.
// //
// _.isMatch("100", "1") also returns true which is not what we want. // _.isMatch("100", "1") also returns true which is not what we want.
private isMatch<T extends Record<string, any>>(expected: T, found: T) { private isMatch<T extends Record<string, any>>(
expected: T,
found: T
) {
if (!expected) { if (!expected) {
throw new Error("Expected is undefined") throw new Error("Expected is undefined")
} }
@ -332,7 +325,9 @@ describe.each([
async toMatch(properties: Record<string, any>) { async toMatch(properties: Record<string, any>) {
const response = await this.performSearch() const response = await this.performSearch()
const cloned = cloneDeep(response) const cloned = cloneDeep(response)
const keys = Object.keys(properties) as Array<keyof SearchResponse<Row>> const keys = Object.keys(properties) as Array<
keyof SearchResponse<Row>
>
for (let key of keys) { for (let key of keys) {
// eslint-disable-next-line jest/no-standalone-expect // eslint-disable-next-line jest/no-standalone-expect
expect(response[key]).toBeDefined() expect(response[key]).toBeDefined()
@ -418,29 +413,29 @@ describe.each([
describe("notEqual", () => { describe("notEqual", () => {
it("successfully finds false row", async () => { it("successfully finds false row", async () => {
await expectQuery({ notEqual: { isTrue: true } }).toContainExactly([ await expectQuery({
{ isTrue: false }, notEqual: { isTrue: true },
]) }).toContainExactly([{ isTrue: false }])
}) })
it("successfully finds true row", async () => { it("successfully finds true row", async () => {
await expectQuery({ notEqual: { isTrue: false } }).toContainExactly([ await expectQuery({
{ isTrue: true }, notEqual: { isTrue: false },
]) }).toContainExactly([{ isTrue: true }])
}) })
}) })
describe("oneOf", () => { describe("oneOf", () => {
it("successfully finds true row", async () => { it("successfully finds true row", async () => {
await expectQuery({ oneOf: { isTrue: [true] } }).toContainExactly([ await expectQuery({ oneOf: { isTrue: [true] } }).toContainExactly(
{ isTrue: true }, [{ isTrue: true }]
]) )
}) })
it("successfully finds false row", async () => { it("successfully finds false row", async () => {
await expectQuery({ oneOf: { isTrue: [false] } }).toContainExactly([ await expectQuery({
{ isTrue: false }, oneOf: { isTrue: [false] },
]) }).toContainExactly([{ isTrue: false }])
}) })
}) })
@ -474,13 +469,18 @@ describe.each([
// expected. // expected.
serverTime.setMilliseconds(0) serverTime.setMilliseconds(0)
const future = new Date(serverTime.getTime() + 1000 * 60 * 60 * 24 * 30) const future = new Date(
serverTime.getTime() + 1000 * 60 * 60 * 24 * 30
)
const rows = (currentUser: User) => { const rows = (currentUser: User) => {
return [ return [
{ name: "foo", appointment: "1982-01-05T00:00:00.000Z" }, { name: "foo", appointment: "1982-01-05T00:00:00.000Z" },
{ name: "bar", appointment: "1995-05-06T00:00:00.000Z" }, { name: "bar", appointment: "1995-05-06T00:00:00.000Z" },
{ name: currentUser.firstName, appointment: future.toISOString() }, {
name: currentUser.firstName,
appointment: future.toISOString(),
},
{ name: "serverDate", appointment: serverTime.toISOString() }, { name: "serverDate", appointment: serverTime.toISOString() },
{ {
name: "single user, session user", name: "single user, session user",
@ -893,15 +893,15 @@ describe.each([
describe("notEqual", () => { describe("notEqual", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ notEqual: { name: "foo" } }).toContainExactly([ await expectQuery({ notEqual: { name: "foo" } }).toContainExactly(
{ name: "bar" }, [{ name: "bar" }]
]) )
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
await expectQuery({ notEqual: { name: "bar" } }).toContainExactly([ await expectQuery({ notEqual: { name: "bar" } }).toContainExactly(
{ name: "foo" }, [{ name: "foo" }]
]) )
}) })
}) })
@ -1325,23 +1325,23 @@ describe.each([
describe("notEqual", () => { describe("notEqual", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ notEqual: { dob: JAN_1ST } }).toContainExactly([ await expectQuery({
{ dob: JAN_10TH }, notEqual: { dob: JAN_1ST },
]) }).toContainExactly([{ dob: JAN_10TH }])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
await expectQuery({ notEqual: { dob: JAN_10TH } }).toContainExactly([ await expectQuery({
{ dob: JAN_1ST }, notEqual: { dob: JAN_10TH },
]) }).toContainExactly([{ dob: JAN_1ST }])
}) })
}) })
describe("oneOf", () => { describe("oneOf", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ oneOf: { dob: [JAN_1ST] } }).toContainExactly([ await expectQuery({ oneOf: { dob: [JAN_1ST] } }).toContainExactly(
{ dob: JAN_1ST }, [{ dob: JAN_1ST }]
]) )
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
@ -1461,7 +1461,11 @@ describe.each([
beforeAll(async () => { beforeAll(async () => {
tableOrViewId = await createTableOrView({ tableOrViewId = await createTableOrView({
timeid: { name: "timeid", type: FieldType.STRING }, timeid: { name: "timeid", type: FieldType.STRING },
time: { name: "time", type: FieldType.DATETIME, timeOnly: true }, time: {
name: "time",
type: FieldType.DATETIME,
timeOnly: true,
},
}) })
await createRows([ await createRows([
@ -1476,9 +1480,9 @@ describe.each([
describe("equal", () => { describe("equal", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ equal: { time: T_1000 } }).toContainExactly([ await expectQuery({ equal: { time: T_1000 } }).toContainExactly(
{ time: "10:00:00" }, [{ time: "10:00:00" }]
]) )
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
@ -1490,7 +1494,9 @@ describe.each([
describe("notEqual", () => { describe("notEqual", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ notEqual: { time: T_1000 } }).toContainExactly([ await expectQuery({
notEqual: { time: T_1000 },
}).toContainExactly([
{ timeid: NULL_TIME__ID }, { timeid: NULL_TIME__ID },
{ time: "10:45:00" }, { time: "10:45:00" },
{ time: "12:00:00" }, { time: "12:00:00" },
@ -1515,9 +1521,9 @@ describe.each([
describe("oneOf", () => { describe("oneOf", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ oneOf: { time: [T_1000] } }).toContainExactly([ await expectQuery({
{ time: "10:00:00" }, oneOf: { time: [T_1000] },
]) }).toContainExactly([{ time: "10:00:00" }])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
@ -1546,7 +1552,9 @@ describe.each([
it("successfully finds no rows", async () => { it("successfully finds no rows", async () => {
await expectQuery({ await expectQuery({
range: { time: { low: UNEXISTING_TIME, high: UNEXISTING_TIME } }, range: {
time: { low: UNEXISTING_TIME, high: UNEXISTING_TIME },
},
}).toFindNothing() }).toFindNothing()
}) })
}) })
@ -1637,7 +1645,10 @@ describe.each([
}, },
}) })
await createRows([{ product: "Big Mac" }, { product: "McCrispy" }]) await createRows([
{ product: "Big Mac" },
{ product: "McCrispy" },
])
}) })
describe("equal", () => { describe("equal", () => {
@ -1704,7 +1715,10 @@ describe.each([
}, },
}, },
}) })
await createRows([{ numbers: ["one", "two"] }, { numbers: ["three"] }]) await createRows([
{ numbers: ["one", "two"] },
{ numbers: ["three"] },
])
}) })
describe("contains", () => { describe("contains", () => {
@ -1715,7 +1729,9 @@ describe.each([
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
await expectQuery({ contains: { numbers: ["none"] } }).toFindNothing() await expectQuery({
contains: { numbers: ["none"] },
}).toFindNothing()
}) })
it("fails to find row containing all", async () => { it("fails to find row containing all", async () => {
@ -1725,10 +1741,9 @@ describe.each([
}) })
it("finds all with empty list", async () => { it("finds all with empty list", async () => {
await expectQuery({ contains: { numbers: [] } }).toContainExactly([ await expectQuery({ contains: { numbers: [] } }).toContainExactly(
{ numbers: ["one", "two"] }, [{ numbers: ["one", "two"] }, { numbers: ["three"] }]
{ numbers: ["three"] }, )
])
}) })
}) })
@ -1751,7 +1766,9 @@ describe.each([
// Not sure if this is correct behaviour but changing it would be a // Not sure if this is correct behaviour but changing it would be a
// breaking change. // breaking change.
it("finds all with empty list", async () => { it("finds all with empty list", async () => {
await expectQuery({ notContains: { numbers: [] } }).toContainExactly([ await expectQuery({
notContains: { numbers: [] },
}).toContainExactly([
{ numbers: ["one", "two"] }, { numbers: ["one", "two"] },
{ numbers: ["three"] }, { numbers: ["three"] },
]) ])
@ -1775,7 +1792,9 @@ describe.each([
}) })
it("finds all with empty list", async () => { it("finds all with empty list", async () => {
await expectQuery({ containsAny: { numbers: [] } }).toContainExactly([ await expectQuery({
containsAny: { numbers: [] },
}).toContainExactly([
{ numbers: ["one", "two"] }, { numbers: ["one", "two"] },
{ numbers: ["three"] }, { numbers: ["three"] },
]) ])
@ -1842,7 +1861,11 @@ describe.each([
it("successfully finds all rows", async () => { it("successfully finds all rows", async () => {
await expectQuery({ await expectQuery({
oneOf: { num: [SMALL, MEDIUM, BIG] }, oneOf: { num: [SMALL, MEDIUM, BIG] },
}).toContainExactly([{ num: SMALL }, { num: MEDIUM }, { num: BIG }]) }).toContainExactly([
{ num: SMALL },
{ num: MEDIUM },
{ num: BIG },
])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
@ -2094,7 +2117,9 @@ describe.each([
bookmark = response.bookmark bookmark = response.bookmark
} }
const autoValues = rows.map(row => row.auto).sort((a, b) => a - b) const autoValues = rows
.map(row => row.auto)
.sort((a, b) => a - b)
expect(autoValues).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) expect(autoValues).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
}) })
}) })
@ -2109,9 +2134,9 @@ describe.each([
}) })
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ equal: { "1:1:name": "bar" } }).toContainExactly([ await expectQuery({
{ "1:name": "bar" }, equal: { "1:1:name": "bar" },
]) }).toContainExactly([{ "1:name": "bar" }])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
@ -2170,7 +2195,9 @@ describe.each([
}) })
it("formula is correct with relationship arrays", async () => { it("formula is correct with relationship arrays", async () => {
await expectQuery({}).toContain([{ formula: "option 1,option 2" }]) await expectQuery({}).toContain([
{ formula: "option 1,option 2" },
])
}) })
}) })
@ -2195,9 +2222,9 @@ describe.each([
describe("equal", () => { describe("equal", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ equal: { user: user1._id } }).toContainExactly([ await expectQuery({
{ user: { _id: user1._id } }, equal: { user: user1._id },
]) }).toContainExactly([{ user: { _id: user1._id } }])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
@ -2207,33 +2234,41 @@ describe.each([
describe("notEqual", () => { describe("notEqual", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ notEqual: { user: user1._id } }).toContainExactly( await expectQuery({
[{ user: { _id: user2._id } }, {}] notEqual: { user: user1._id },
) }).toContainExactly([{ user: { _id: user2._id } }, {}])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
await expectQuery({ notEqual: { user: "us_none" } }).toContainExactly( await expectQuery({
[{ user: { _id: user1._id } }, { user: { _id: user2._id } }, {}] notEqual: { user: "us_none" },
) }).toContainExactly([
{ user: { _id: user1._id } },
{ user: { _id: user2._id } },
{},
])
}) })
}) })
describe("oneOf", () => { describe("oneOf", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ oneOf: { user: [user1._id] } }).toContainExactly([ await expectQuery({
{ user: { _id: user1._id } }, oneOf: { user: [user1._id] },
]) }).toContainExactly([{ user: { _id: user1._id } }])
}) })
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
await expectQuery({ oneOf: { user: ["us_none"] } }).toFindNothing() await expectQuery({
oneOf: { user: ["us_none"] },
}).toFindNothing()
}) })
}) })
describe("empty", () => { describe("empty", () => {
it("finds empty rows", async () => { it("finds empty rows", async () => {
await expectQuery({ empty: { user: null } }).toContainExactly([{}]) await expectQuery({ empty: { user: null } }).toContainExactly([
{},
])
}) })
}) })
@ -2432,7 +2467,10 @@ describe.each([
], ],
}, },
}).toContainExactly([ }).toContainExactly([
{ name: "foo", productCat: [{ _id: productCatRows[0]._id }] }, {
name: "foo",
productCat: [{ _id: productCatRows[0]._id }],
},
]) ])
}) })
@ -2531,7 +2569,10 @@ describe.each([
], ],
}, },
}).toContainExactly([ }).toContainExactly([
{ name: "foo", productCat: [{ _id: productCatRows[0]._id }] }, {
name: "foo",
productCat: [{ _id: productCatRows[0]._id }],
},
]) ])
}) })
@ -2546,8 +2587,14 @@ describe.each([
], ],
}, },
}).toContainExactly([ }).toContainExactly([
{ name: "foo", productCat: [{ _id: productCatRows[0]._id }] }, {
{ name: "bar", productCat: [{ _id: productCatRows[1]._id }] }, name: "foo",
productCat: [{ _id: productCatRows[0]._id }],
},
{
name: "bar",
productCat: [{ _id: productCatRows[1]._id }],
},
{ name: "baz", productCat: undefined }, { name: "baz", productCat: undefined },
]) ])
}) })
@ -2627,8 +2674,14 @@ describe.each([
], ],
}, },
}).toContainExactly([ }).toContainExactly([
{ name: "foo", productCat: [{ _id: productCatRows[0]._id }] }, {
{ name: "bar", productCat: [{ _id: productCatRows[1]._id }] }, name: "foo",
productCat: [{ _id: productCatRows[0]._id }],
},
{
name: "bar",
productCat: [{ _id: productCatRows[1]._id }],
},
{ name: "baz", productCat: undefined }, { name: "baz", productCat: undefined },
]) ])
}) })
@ -2659,13 +2712,17 @@ describe.each([
it("can only pull 10 related rows", async () => { it("can only pull 10 related rows", async () => {
await withCoreEnv({ SQL_MAX_RELATED_ROWS: "10" }, async () => { await withCoreEnv({ SQL_MAX_RELATED_ROWS: "10" }, async () => {
const response = await expectQuery({}).toContain([{ name: "foo" }]) const response = await expectQuery({}).toContain([
{ name: "foo" },
])
expect(response.rows[0].productCat).toBeArrayOfSize(10) expect(response.rows[0].productCat).toBeArrayOfSize(10)
}) })
}) })
it("can pull max rows when env not set (defaults to 500)", async () => { it("can pull max rows when env not set (defaults to 500)", async () => {
const response = await expectQuery({}).toContain([{ name: "foo" }]) const response = await expectQuery({}).toContain([
{ name: "foo" },
])
expect(response.rows[0].productCat).toBeArrayOfSize(11) expect(response.rows[0].productCat).toBeArrayOfSize(11)
}) })
}) })
@ -3239,7 +3296,10 @@ describe.each([
it("successfully finds a row for one level condition", async () => { it("successfully finds a row for one level condition", async () => {
await expectQuery({ await expectQuery({
$and: { $and: {
conditions: [{ equal: { age: 10 } }, { equal: { name: "Jack" } }], conditions: [
{ equal: { age: 10 } },
{ equal: { name: "Jack" } },
],
}, },
}).toContainExactly([{ age: 10, name: "Jack" }]) }).toContainExactly([{ age: 10, name: "Jack" }])
}) })
@ -3247,7 +3307,10 @@ describe.each([
it("successfully finds a row for one level with multiple conditions", async () => { it("successfully finds a row for one level with multiple conditions", async () => {
await expectQuery({ await expectQuery({
$and: { $and: {
conditions: [{ equal: { age: 10 } }, { equal: { name: "Jack" } }], conditions: [
{ equal: { age: 10 } },
{ equal: { name: "Jack" } },
],
}, },
}).toContainExactly([{ age: 10, name: "Jack" }]) }).toContainExactly([{ age: 10, name: "Jack" }])
}) })
@ -3289,7 +3352,10 @@ describe.each([
it("returns nothing when filtering out all data", async () => { it("returns nothing when filtering out all data", async () => {
await expectQuery({ await expectQuery({
$and: { $and: {
conditions: [{ equal: { age: 7 } }, { equal: { name: "Jack" } }], conditions: [
{ equal: { age: 7 } },
{ equal: { name: "Jack" } },
],
}, },
}).toFindNothing() }).toFindNothing()
}) })
@ -3299,7 +3365,10 @@ describe.each([
await expect( await expect(
expectQuery({ expectQuery({
$and: { $and: {
conditions: [{ equal: { age: 10 } }, "invalidCondition" as any], conditions: [
{ equal: { age: 10 } },
"invalidCondition" as any,
],
}, },
}).toFindNothing() }).toFindNothing()
).rejects.toThrow( ).rejects.toThrow(
@ -3369,7 +3438,10 @@ describe.each([
it("successfully finds a row for one level condition", async () => { it("successfully finds a row for one level condition", async () => {
await expectQuery({ await expectQuery({
$or: { $or: {
conditions: [{ equal: { age: 7 } }, { equal: { name: "Jack" } }], conditions: [
{ equal: { age: 7 } },
{ equal: { name: "Jack" } },
],
}, },
}).toContainExactly([ }).toContainExactly([
{ age: 10, name: "Jack" }, { age: 10, name: "Jack" },
@ -3380,7 +3452,10 @@ describe.each([
it("successfully finds a row for one level with multiple conditions", async () => { it("successfully finds a row for one level with multiple conditions", async () => {
await expectQuery({ await expectQuery({
$or: { $or: {
conditions: [{ equal: { age: 7 } }, { equal: { name: "Jack" } }], conditions: [
{ equal: { age: 7 } },
{ equal: { name: "Jack" } },
],
}, },
}).toContainExactly([ }).toContainExactly([
{ age: 10, name: "Jack" }, { age: 10, name: "Jack" },
@ -3430,7 +3505,10 @@ describe.each([
it("returns nothing when filtering out all data", async () => { it("returns nothing when filtering out all data", async () => {
await expectQuery({ await expectQuery({
$or: { $or: {
conditions: [{ equal: { age: 6 } }, { equal: { name: "John" } }], conditions: [
{ equal: { age: 6 } },
{ equal: { name: "John" } },
],
}, },
}).toFindNothing() }).toFindNothing()
}) })
@ -3567,7 +3645,8 @@ describe.each([
// The SQL that knex generates when you try to use a double quote in a // The SQL that knex generates when you try to use a double quote in a
// field name is always invalid and never works, so we skip it for these // field name is always invalid and never works, so we skip it for these
// tests. // tests.
const skipFieldNameCheck = isOracle && badStringTemplate.includes('"') const skipFieldNameCheck =
isOracle && badStringTemplate.includes('"')
!skipFieldNameCheck && !skipFieldNameCheck &&
it("should not allow SQL injection as a field name", async () => { it("should not allow SQL injection as a field name", async () => {
@ -3596,7 +3675,9 @@ describe.each([
}) })
} }
await config.api.row.save(tableOrViewId, { [badString]: "foo" }) await config.api.row.save(tableOrViewId, {
[badString]: "foo",
})
await assertTableExists(table) await assertTableExists(table)
await assertTableNumRows(table, 1) await assertTableNumRows(table, 1)
@ -3644,4 +3725,6 @@ describe.each([
}) })
}) })
}) })
}) })
}
)

View File

@ -52,6 +52,7 @@ export interface DatasourceDescribeReturn {
dsProvider: Promise<DatasourceDescribeReturnPromise> dsProvider: Promise<DatasourceDescribeReturnPromise>
isInternal: boolean isInternal: boolean
isExternal: boolean isExternal: boolean
isSql: boolean
isMySQL: boolean isMySQL: boolean
isPostgres: boolean isPostgres: boolean
isMongodb: boolean isMongodb: boolean
@ -118,6 +119,13 @@ export function datasourceDescribe(
dsProvider: createDatasources(config, name), dsProvider: createDatasources(config, name),
isInternal: name === DatabaseName.SQS, isInternal: name === DatabaseName.SQS,
isExternal: name !== DatabaseName.SQS, isExternal: name !== DatabaseName.SQS,
isSql: [
DatabaseName.MARIADB,
DatabaseName.MYSQL,
DatabaseName.POSTGRES,
DatabaseName.SQL_SERVER,
DatabaseName.ORACLE,
].includes(name),
isMySQL: name === DatabaseName.MYSQL, isMySQL: name === DatabaseName.MYSQL,
isPostgres: name === DatabaseName.POSTGRES, isPostgres: name === DatabaseName.POSTGRES,
isMongodb: name === DatabaseName.MONGODB, isMongodb: name === DatabaseName.MONGODB,