Adding test case.

This commit is contained in:
mike12345567 2024-09-23 18:41:23 +01:00
parent 676058bbbd
commit 680c68a35b
3 changed files with 78 additions and 28 deletions

View File

@ -42,6 +42,7 @@ import { Knex } from "knex"
import { structures } from "@budibase/backend-core/tests" import { structures } from "@budibase/backend-core/tests"
import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default" import { DEFAULT_EMPLOYEE_TABLE_SCHEMA } from "../../../db/defaultData/datasource_bb_default"
import { generateRowIdField } from "../../../integrations/utils" import { generateRowIdField } from "../../../integrations/utils"
import { cloneDeep } from "lodash/fp"
describe.each([ describe.each([
["in-memory", undefined], ["in-memory", undefined],
@ -66,6 +67,35 @@ describe.each([
let table: Table let table: Table
let rows: Row[] let rows: Row[]
async function basicRelationshipTables(type: RelationshipType) {
const relatedTable = await createTable(
{
name: { name: "name", type: FieldType.STRING },
},
"productCategory"
)
table = await createTable(
{
name: { name: "name", type: FieldType.STRING },
productCat: {
type: FieldType.LINK,
relationshipType: type,
name: "productCat",
fieldName: "product",
tableId: relatedTable._id!,
constraints: {
type: "array",
},
},
},
"product"
)
return {
relatedTable: await config.api.table.get(relatedTable._id!),
table,
}
}
beforeAll(async () => { beforeAll(async () => {
await withCoreEnv({ TENANT_FEATURE_FLAGS: "*:SQS" }, () => config.init()) await withCoreEnv({ TENANT_FEATURE_FLAGS: "*:SQS" }, () => config.init())
if (isLucene) { if (isLucene) {
@ -201,6 +231,7 @@ describe.each([
// rows returned by the query will also cause the assertion to fail. // rows returned by the query will also cause the assertion to fail.
async toMatchExactly(expectedRows: any[]) { async toMatchExactly(expectedRows: any[]) {
const response = await this.performSearch() const response = await this.performSearch()
const cloned = cloneDeep(response)
const foundRows = response.rows const foundRows = response.rows
// eslint-disable-next-line jest/no-standalone-expect // eslint-disable-next-line jest/no-standalone-expect
@ -211,7 +242,7 @@ describe.each([
expect.objectContaining(this.popRow(expectedRow, foundRows)) expect.objectContaining(this.popRow(expectedRow, foundRows))
) )
) )
return response return cloned
} }
// Asserts that the query returns rows matching exactly the set of rows // Asserts that the query returns rows matching exactly the set of rows
@ -219,6 +250,7 @@ describe.each([
// cause the assertion to fail. // cause the assertion to fail.
async toContainExactly(expectedRows: any[]) { async toContainExactly(expectedRows: any[]) {
const response = await this.performSearch() const response = await this.performSearch()
const cloned = cloneDeep(response)
const foundRows = response.rows const foundRows = response.rows
// eslint-disable-next-line jest/no-standalone-expect // eslint-disable-next-line jest/no-standalone-expect
@ -231,7 +263,7 @@ describe.each([
) )
) )
) )
return response return cloned
} }
// Asserts that the query returns some property values - this cannot be used // Asserts that the query returns some property values - this cannot be used
@ -239,6 +271,7 @@ describe.each([
// typing for this has to be any, Jest doesn't expose types for matchers like expect.any(...) // typing for this has to be any, Jest doesn't expose types for matchers like expect.any(...)
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 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
@ -248,17 +281,18 @@ describe.each([
expect(response[key]).toEqual(properties[key]) expect(response[key]).toEqual(properties[key])
} }
} }
return response return cloned
} }
// Asserts that the query doesn't return a property, e.g. pagination parameters. // Asserts that the query doesn't return a property, e.g. pagination parameters.
async toNotHaveProperty(properties: (keyof SearchResponse<Row>)[]) { async toNotHaveProperty(properties: (keyof SearchResponse<Row>)[]) {
const response = await this.performSearch() const response = await this.performSearch()
const cloned = cloneDeep(response)
for (let property of properties) { for (let property of properties) {
// eslint-disable-next-line jest/no-standalone-expect // eslint-disable-next-line jest/no-standalone-expect
expect(response[property]).toBeUndefined() expect(response[property]).toBeUndefined()
} }
return response return cloned
} }
// Asserts that the query returns rows matching the set of rows passed in. // Asserts that the query returns rows matching the set of rows passed in.
@ -266,6 +300,7 @@ describe.each([
// assertion to fail. // assertion to fail.
async toContain(expectedRows: any[]) { async toContain(expectedRows: any[]) {
const response = await this.performSearch() const response = await this.performSearch()
const cloned = cloneDeep(response)
const foundRows = response.rows const foundRows = response.rows
// eslint-disable-next-line jest/no-standalone-expect // eslint-disable-next-line jest/no-standalone-expect
@ -276,7 +311,7 @@ describe.each([
) )
) )
) )
return response return cloned
} }
async toFindNothing() { async toFindNothing() {
@ -2196,28 +2231,10 @@ describe.each([
let productCategoryTable: Table, productCatRows: Row[] let productCategoryTable: Table, productCatRows: Row[]
beforeAll(async () => { beforeAll(async () => {
productCategoryTable = await createTable( const { relatedTable } = await basicRelationshipTables(
{ RelationshipType.ONE_TO_MANY
name: { name: "name", type: FieldType.STRING },
},
"productCategory"
)
table = await createTable(
{
name: { name: "name", type: FieldType.STRING },
productCat: {
type: FieldType.LINK,
relationshipType: RelationshipType.ONE_TO_MANY,
name: "productCat",
fieldName: "product",
tableId: productCategoryTable._id!,
constraints: {
type: "array",
},
},
},
"product"
) )
productCategoryTable = relatedTable
productCatRows = await Promise.all([ productCatRows = await Promise.all([
config.api.row.save(productCategoryTable._id!, { name: "foo" }), config.api.row.save(productCategoryTable._id!, { name: "foo" }),
@ -2262,6 +2279,31 @@ describe.each([
}).toContainExactly([{ name: "baz", productCat: undefined }]) }).toContainExactly([{ name: "baz", productCat: undefined }])
}) })
}) })
isSql &&
describe("big relations", () => {
beforeAll(async () => {
const { relatedTable } = await basicRelationshipTables(
RelationshipType.MANY_TO_ONE
)
const mainRow = await config.api.row.save(table._id!, {
name: "foo",
})
for (let i = 0; i < 11; i++) {
await config.api.row.save(relatedTable._id!, {
name: i,
product: [mainRow._id!],
})
}
})
it("can only pull 500 related rows", async () => {
await withCoreEnv({ SQL_MAX_RELATED_ROWS: "10" }, async () => {
const response = await expectQuery({}).toContain([{ name: "foo" }])
expect(response.rows[0].productCat).toBeArrayOfSize(10)
})
})
})
;(isSqs || isLucene) && ;(isSqs || isLucene) &&
describe("relations to same table", () => { describe("relations to same table", () => {
let relatedTable: Table, relatedRows: Row[] let relatedTable: Table, relatedRows: Row[]

View File

@ -198,6 +198,7 @@ export async function save(
} }
} }
generateRelatedSchema(schema, relatedTable, tableToSave, relatedColumnName) generateRelatedSchema(schema, relatedTable, tableToSave, relatedColumnName)
tables[relatedTable.name] = relatedTable
schema.main = true schema.main = true
} }
@ -231,7 +232,10 @@ export async function save(
// remove the rename prop // remove the rename prop
delete tableToSave._rename delete tableToSave._rename
datasource.entities[tableToSave.name] = tableToSave datasource.entities = {
...datasource.entities,
...tables,
}
// store it into couch now for budibase reference // store it into couch now for budibase reference
await db.put(populateExternalTableSchemas(datasource)) await db.put(populateExternalTableSchemas(datasource))

View File

@ -22,12 +22,16 @@ export function cleanupRelationships(
tables: Record<string, Table>, tables: Record<string, Table>,
oldTable?: Table oldTable?: Table
) { ) {
if (!oldTable) {
return
}
const tableToIterate = oldTable ? oldTable : table const tableToIterate = oldTable ? oldTable : table
// clean up relationships in couch table schemas // clean up relationships in couch table schemas
for (let [key, schema] of Object.entries(tableToIterate.schema)) { for (let [key, schema] of Object.entries(tableToIterate.schema)) {
if ( if (
schema.type === FieldType.LINK && schema.type === FieldType.LINK &&
(!oldTable || table.schema[key] == null) oldTable.schema[key] != null &&
table.schema[key] == null
) { ) {
const schemaTableId = schema.tableId const schemaTableId = schema.tableId
const relatedTable = Object.values(tables).find( const relatedTable = Object.values(tables).find(