Create sql tests for sqs

This commit is contained in:
Adria Navarro 2024-12-19 14:31:45 +01:00
parent 5a9ed4ff52
commit 7cc03b1724
1 changed files with 674 additions and 0 deletions

View File

@ -0,0 +1,674 @@
import {
AIOperationEnum,
CalculationType,
FieldType,
RelationshipType,
SourceName,
Table,
ViewV2,
ViewV2Type,
} from "@budibase/types"
import { buildInternalFieldList } from "../sqs"
import { structures } from "../../../../../../api/routes/tests/utilities"
import { sql } from "@budibase/backend-core"
import { generator } from "@budibase/backend-core/tests"
import {
generateJunctionTableID,
generateViewID,
} from "../../../../../../db/utils"
import sdk from "../../../../../../sdk"
import { cloneDeep } from "lodash"
import { utils } from "@budibase/shared-core"
jest.mock("../../../../../../sdk/app/views", () => ({
...jest.requireActual("../../../../../../sdk/app/views"),
getTable: jest.fn(),
}))
const getTableMock = sdk.views.getTable as jest.MockedFunction<
typeof sdk.views.getTable
>
describe("buildInternalFieldList", () => {
let allTables: Table[]
class TableConfig {
private _table: Table & { _id: string }
constructor() {
const name = generator.word()
this._table = {
...structures.tableForDatasource({
type: "datasource",
source: SourceName.POSTGRES,
}),
name,
_id: sql.utils.buildExternalTableId("ds_id", name),
schema: {
name: {
name: "name",
type: FieldType.STRING,
},
description: {
name: "description",
type: FieldType.STRING,
},
amount: {
name: "amount",
type: FieldType.NUMBER,
},
},
}
allTables.push(this._table)
}
withHiddenField(field: string) {
this._table.schema[field].visible = false
return this
}
withField(
name: string,
type:
| FieldType.STRING
| FieldType.NUMBER
| FieldType.FORMULA
| FieldType.AI,
options?: { visible: boolean }
) {
switch (type) {
case FieldType.NUMBER:
case FieldType.STRING:
this._table.schema[name] = {
name,
type,
...options,
}
break
case FieldType.FORMULA:
this._table.schema[name] = {
name,
type,
formula: "any",
...options,
}
break
case FieldType.AI:
this._table.schema[name] = {
name,
type,
operation: AIOperationEnum.PROMPT,
...options,
}
break
default:
utils.unreachable(type)
}
return this
}
withRelation(name: string, toTableId: string) {
this._table.schema[name] = {
name,
type: FieldType.LINK,
relationshipType: RelationshipType.ONE_TO_MANY,
fieldName: "link",
tableId: toTableId,
}
return this
}
withEmptySchema() {
this._table.schema = {}
return this
}
create() {
return cloneDeep(this._table)
}
}
class ViewConfig {
private _table: Table
private _view: ViewV2
constructor(table: Table) {
this._table = table
this._view = {
version: 2,
id: generateViewID(table._id!),
name: generator.word(),
tableId: table._id!,
}
}
withVisible(field: string) {
this._view.schema ??= {}
this._view.schema[field] ??= {}
this._view.schema[field].visible = true
return this
}
withHidden(field: string) {
this._view.schema ??= {}
this._view.schema[field] ??= {}
this._view.schema[field].visible = false
return this
}
withRelationshipColumns(
field: string,
columns: Record<string, { visible: boolean }>
) {
this._view.schema ??= {}
this._view.schema[field] ??= {}
this._view.schema[field].columns = columns
return this
}
withCalculation(
name: string,
field: string,
calculationType: CalculationType
) {
this._view.type = ViewV2Type.CALCULATION
this._view.schema ??= {}
this._view.schema[name] = {
field,
calculationType,
visible: true,
}
return this
}
create() {
getTableMock.mockResolvedValueOnce(this._table)
return cloneDeep(this._view)
}
}
beforeEach(() => {
jest.clearAllMocks()
allTables = []
})
describe("table", () => {
it("includes internal columns by default", async () => {
const table = new TableConfig().withEmptySchema().create()
const result = await buildInternalFieldList(table, [])
expect(result).toEqual([
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("extracts fields from table schema", async () => {
const table = new TableConfig().create()
const result = await buildInternalFieldList(table, [])
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${table._id}.data_amount`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("excludes hidden fields", async () => {
const table = new TableConfig().withHiddenField("description").create()
const result = await buildInternalFieldList(table, [])
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_amount`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("excludes non-sql fields fields", async () => {
const table = new TableConfig()
.withField("formula", FieldType.FORMULA)
.withField("ai", FieldType.AI)
.withRelation("link", "otherTableId")
.create()
const result = await buildInternalFieldList(table, [])
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${table._id}.data_amount`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("includes hidden fields if there is a formula column", async () => {
const table = new TableConfig()
.withHiddenField("description")
.withField("formula", FieldType.FORMULA)
.create()
const result = await buildInternalFieldList(table, [])
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${table._id}.data_amount`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("includes relationships fields when flagged", async () => {
const otherTable = new TableConfig()
.withHiddenField("description")
.create()
const table = new TableConfig()
.withHiddenField("amount")
.withRelation("link", otherTable._id)
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(table, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${otherTable._id}.data_name`,
`${otherTable._id}.data_amount`,
`${otherTable._id}._id`,
`${otherTable._id}._rev`,
`${otherTable._id}.type`,
`${otherTable._id}.createdAt`,
`${otherTable._id}.updatedAt`,
`${otherTable._id}.tableId`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc1.fieldName`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc2.fieldName`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("includes all relationship fields if there is a formula column", async () => {
const otherTable = new TableConfig()
.withField("hidden", FieldType.STRING, { visible: false })
.create()
const table = new TableConfig()
.withRelation("link", otherTable._id)
.withHiddenField("description")
.withField("formula", FieldType.FORMULA)
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(table, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${table._id}.data_amount`,
`${otherTable._id}.data_name`,
`${otherTable._id}.data_description`,
`${otherTable._id}.data_amount`,
`${otherTable._id}.data_hidden`,
`${otherTable._id}._id`,
`${otherTable._id}._rev`,
`${otherTable._id}.type`,
`${otherTable._id}.createdAt`,
`${otherTable._id}.updatedAt`,
`${otherTable._id}.tableId`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc1.fieldName`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc2.fieldName`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("never includes non-sql columns from relationships", async () => {
const otherTable = new TableConfig()
.withField("hidden", FieldType.STRING, { visible: false })
.withField("formula", FieldType.FORMULA)
.withField("ai", FieldType.AI)
.withRelation("link", "otherTableId")
.create()
const table = new TableConfig()
.withRelation("link", otherTable._id)
.withField("formula", FieldType.FORMULA)
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(table, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${table._id}.data_amount`,
`${otherTable._id}.data_name`,
`${otherTable._id}.data_description`,
`${otherTable._id}.data_amount`,
`${otherTable._id}.data_hidden`,
`${otherTable._id}._id`,
`${otherTable._id}._rev`,
`${otherTable._id}.type`,
`${otherTable._id}.createdAt`,
`${otherTable._id}.updatedAt`,
`${otherTable._id}.tableId`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc1.fieldName`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc2.fieldName`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
})
describe("view", () => {
it("includes internal columns by default", async () => {
const view = new ViewConfig(new TableConfig().create()).create()
const result = await buildInternalFieldList(view, [])
expect(result).toEqual([
`${view.tableId}._id`,
`${view.tableId}._rev`,
`${view.tableId}.type`,
`${view.tableId}.createdAt`,
`${view.tableId}.updatedAt`,
`${view.tableId}.tableId`,
])
})
it("extracts fields from table schema", async () => {
const view = new ViewConfig(new TableConfig().create())
.withVisible("amount")
.withHidden("name")
.create()
const result = await buildInternalFieldList(view, [])
expect(result).toEqual([
`${view.tableId}.data_amount`,
`${view.tableId}._id`,
`${view.tableId}._rev`,
`${view.tableId}.type`,
`${view.tableId}.createdAt`,
`${view.tableId}.updatedAt`,
`${view.tableId}.tableId`,
])
})
it("includes all fields if there is a formula column", async () => {
const table = new TableConfig()
.withField("formula", FieldType.FORMULA)
.create()
const view = new ViewConfig(table)
.withHidden("name")
.withVisible("amount")
.withVisible("formula")
.create()
const result = await buildInternalFieldList(view, [])
expect(result).toEqual([
`${view.tableId}.data_name`,
`${view.tableId}.data_description`,
`${view.tableId}.data_amount`,
`${view.tableId}._id`,
`${view.tableId}._rev`,
`${view.tableId}.type`,
`${view.tableId}.createdAt`,
`${view.tableId}.updatedAt`,
`${view.tableId}.tableId`,
])
})
it("does not includes all fields if the formula column is not included", async () => {
const table = new TableConfig()
.withField("formula", FieldType.FORMULA)
.create()
const view = new ViewConfig(table)
.withHidden("name")
.withVisible("amount")
.withHidden("formula")
.create()
const result = await buildInternalFieldList(view, [])
expect(result).toEqual([
`${view.tableId}.data_amount`,
`${view.tableId}._id`,
`${view.tableId}._rev`,
`${view.tableId}.type`,
`${view.tableId}.createdAt`,
`${view.tableId}.updatedAt`,
`${view.tableId}.tableId`,
])
})
it("includes relationships fields", async () => {
const otherTable = new TableConfig().create()
const table = new TableConfig()
.withRelation("link", otherTable._id)
.withField("formula", FieldType.FORMULA)
.create()
const view = new ViewConfig(table)
.withVisible("name")
.withVisible("link")
.withHidden("amount")
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(view, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${otherTable._id}.data_name`,
`${otherTable._id}.data_description`,
`${otherTable._id}.data_amount`,
`${otherTable._id}._id`,
`${otherTable._id}._rev`,
`${otherTable._id}.type`,
`${otherTable._id}.createdAt`,
`${otherTable._id}.updatedAt`,
`${otherTable._id}.tableId`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc1.fieldName`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc2.fieldName`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("includes relationships columns", async () => {
const otherTable = new TableConfig()
.withField("formula", FieldType.FORMULA)
.create()
const table = new TableConfig()
.withRelation("link", otherTable._id)
.create()
const view = new ViewConfig(table)
.withVisible("name")
.withVisible("link")
.withRelationshipColumns("link", {
name: { visible: false },
amount: { visible: true },
formula: { visible: false },
})
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(view, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${otherTable._id}.data_name`,
`${otherTable._id}.data_description`,
`${otherTable._id}.data_amount`,
`${otherTable._id}._id`,
`${otherTable._id}._rev`,
`${otherTable._id}.type`,
`${otherTable._id}.createdAt`,
`${otherTable._id}.updatedAt`,
`${otherTable._id}.tableId`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc1.fieldName`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc2.fieldName`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("does not include relationships columns for hidden links", async () => {
const otherTable = new TableConfig()
.withField("formula", FieldType.FORMULA)
.create()
const table = new TableConfig()
.withRelation("link", otherTable._id)
.create()
const view = new ViewConfig(table)
.withVisible("name")
.withHidden("link")
.withRelationshipColumns("link", {
name: { visible: false },
amount: { visible: true },
formula: { visible: false },
})
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(view, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
it("includes all relationship fields if there is a formula column", async () => {
const otherTable = new TableConfig()
.withField("hidden", FieldType.STRING, { visible: false })
.withField("formula", FieldType.FORMULA)
.withField("ai", FieldType.AI)
.withRelation("link", "otherTableId")
.create()
const table = new TableConfig()
.withRelation("link", otherTable._id)
.withField("formula", FieldType.FORMULA)
.create()
const view = new ViewConfig(table)
.withVisible("name")
.withVisible("formula")
.withHidden("link")
.withRelationshipColumns("link", {
name: { visible: false },
amount: { visible: true },
formula: { visible: false },
})
.create()
const relationships = [{ tableName: otherTable.name, column: "link" }]
const result = await buildInternalFieldList(view, allTables, {
relationships,
})
expect(result).toEqual([
`${table._id}.data_name`,
`${table._id}.data_description`,
`${table._id}.data_amount`,
`${otherTable._id}.data_name`,
`${otherTable._id}.data_description`,
`${otherTable._id}.data_amount`,
`${otherTable._id}.data_hidden`,
`${otherTable._id}._id`,
`${otherTable._id}._rev`,
`${otherTable._id}.type`,
`${otherTable._id}.createdAt`,
`${otherTable._id}.updatedAt`,
`${otherTable._id}.tableId`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc1.fieldName`,
`${generateJunctionTableID(table._id, otherTable._id)}.doc2.fieldName`,
`${table._id}._id`,
`${table._id}._rev`,
`${table._id}.type`,
`${table._id}.createdAt`,
`${table._id}.updatedAt`,
`${table._id}.tableId`,
])
})
})
describe("calculation view", () => {
it("does not include calculation fields", async () => {
const view = new ViewConfig(new TableConfig().create())
.withCalculation("average", "amount", CalculationType.AVG)
.create()
const result = await buildInternalFieldList(view, [])
expect(result).toEqual([])
})
it("includes visible fields calculation fields", async () => {
const view = new ViewConfig(new TableConfig().create())
.withCalculation("average", "amount", CalculationType.AVG)
.withHidden("name")
.withVisible("amount")
.create()
const result = await buildInternalFieldList(view, [])
expect(result).toEqual([`${view.tableId}.data_amount`])
})
})
})