From 6c328109b69f548d46bc65e016c67b828a12f2c5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 5 Oct 2023 19:47:00 +0200 Subject: [PATCH] Fixes --- .../src/api/controllers/table/external.ts | 37 +++++++++++-------- .../server/src/api/routes/tests/table.spec.ts | 2 +- .../db/defaultData/datasource_bb_default.ts | 10 ++--- .../src/db/linkedRows/LinkController.ts | 16 +++++--- .../server/src/integrations/base/sqlTable.ts | 14 +++++-- packages/server/src/sdk/app/rows/utils.ts | 9 +++-- .../rowProcessor/tests/utils.spec.ts | 2 +- .../types/src/documents/app/table/schema.ts | 24 ++++++------ 8 files changed, 69 insertions(+), 45 deletions(-) diff --git a/packages/server/src/api/controllers/table/external.ts b/packages/server/src/api/controllers/table/external.ts index 327904666d..dac39a4a99 100644 --- a/packages/server/src/api/controllers/table/external.ts +++ b/packages/server/src/api/controllers/table/external.ts @@ -15,11 +15,14 @@ import { handleRequest } from "../row/external" import { context, events } from "@budibase/backend-core" import { isRows, isSchema, parse } from "../../../utilities/schema" import { - AutoReason, Datasource, FieldSchema, + ManyToManyRelationshipFieldMetadata, + ManyToOneRelationshipFieldMetadata, + OneToManyRelationshipFieldMetadata, Operation, QueryJson, + RelationshipFieldMetadata, RelationshipType, RenameColumn, SaveTableRequest, @@ -74,10 +77,11 @@ function cleanupRelationships( schema.type === FieldTypes.LINK && (!oldTable || table.schema[key] == null) ) { + const schemaTableId = schema.tableId const relatedTable = Object.values(tables).find( - table => table._id === schema.tableId + table => table._id === schemaTableId ) - const foreignKey = schema.foreignKey + const foreignKey = (schema as any).foreignKey if (!relatedTable || !foreignKey) { continue } @@ -116,7 +120,7 @@ function otherRelationshipType(type?: string) { function generateManyLinkSchema( datasource: Datasource, - column: FieldSchema, + column: ManyToManyRelationshipFieldMetadata, table: Table, relatedTable: Table ): Table { @@ -151,10 +155,12 @@ function generateManyLinkSchema( } function generateLinkSchema( - column: FieldSchema, + column: + | OneToManyRelationshipFieldMetadata + | ManyToOneRelationshipFieldMetadata, table: Table, relatedTable: Table, - type: RelationshipType + type: RelationshipType.ONE_TO_MANY | RelationshipType.MANY_TO_ONE ) { if (!table.primary || !relatedTable.primary) { throw new Error("Unable to generate link schema, no primary keys") @@ -170,7 +176,7 @@ function generateLinkSchema( } function generateRelatedSchema( - linkColumn: FieldSchema, + linkColumn: RelationshipFieldMetadata, table: Table, relatedTable: Table, columnName: string @@ -178,16 +184,16 @@ function generateRelatedSchema( // generate column for other table const relatedSchema = cloneDeep(linkColumn) // swap them from the main link - if (linkColumn.foreignKey) { - relatedSchema.fieldName = linkColumn.foreignKey + if ((linkColumn as any).foreignKey) { + relatedSchema.fieldName = (linkColumn as any).foreignKey relatedSchema.foreignKey = linkColumn.fieldName } // is many to many else { // don't need to copy through, already got it - relatedSchema.fieldName = linkColumn.throughTo - relatedSchema.throughTo = linkColumn.throughFrom - relatedSchema.throughFrom = linkColumn.throughTo + relatedSchema.fieldName = (linkColumn as any).throughTo + relatedSchema.throughTo = (linkColumn as any).throughFrom + relatedSchema.throughFrom = (linkColumn as any).throughTo } relatedSchema.relationshipType = otherRelationshipType( linkColumn.relationshipType @@ -198,7 +204,7 @@ function generateRelatedSchema( } function isRelationshipSetup(column: FieldSchema) { - return column.foreignKey || column.through + return (column as any).foreignKey || (column as any).through } export async function save(ctx: UserCtx) { @@ -257,14 +263,15 @@ export async function save(ctx: UserCtx) { if (schema.type !== FieldTypes.LINK || isRelationshipSetup(schema)) { continue } + const schemaTableId = schema.tableId const relatedTable = Object.values(tables).find( - table => table._id === schema.tableId + table => table._id === schemaTableId ) if (!relatedTable) { continue } const relatedColumnName = schema.fieldName! - const relationType = schema.relationshipType! + const relationType = schema.relationshipType if (relationType === RelationshipType.MANY_TO_MANY) { const junctionTable = generateManyLinkSchema( datasource, diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index f56c6e4e44..fc49335fc7 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -354,7 +354,7 @@ describe("/tables", () => { type: FieldType.LINK, name: "TestTable", fieldName: "TestTable", - tableId: testTable._id, + tableId: testTable._id!, constraints: { type: "array", }, diff --git a/packages/server/src/db/defaultData/datasource_bb_default.ts b/packages/server/src/db/defaultData/datasource_bb_default.ts index a4821667ff..d99c8132bc 100644 --- a/packages/server/src/db/defaultData/datasource_bb_default.ts +++ b/packages/server/src/db/defaultData/datasource_bb_default.ts @@ -29,7 +29,7 @@ function syncLastIds(table: Table, rowCount: number) { Object.keys(table.schema).forEach(key => { const entry = table.schema[key] if (entry.autocolumn && entry.subtype == "autoID") { - entry.lastID = rowCount + ;(entry as any).lastID = rowCount } }) } @@ -184,7 +184,7 @@ export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = { }, ...AUTO_COLUMNS, }, -} +} as any export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = { _id: DEFAULT_EMPLOYEE_TABLE_ID, @@ -332,7 +332,7 @@ export const DEFAULT_EMPLOYEE_TABLE_SCHEMA: Table = { }, ...AUTO_COLUMNS, }, -} +} as any export const DEFAULT_JOBS_TABLE_SCHEMA: Table = { _id: DEFAULT_JOBS_TABLE_ID, @@ -489,7 +489,7 @@ export const DEFAULT_JOBS_TABLE_SCHEMA: Table = { }, ...AUTO_COLUMNS, }, -} +} as any export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = { _id: DEFAULT_EXPENSES_TABLE_ID, @@ -599,7 +599,7 @@ export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = { }, ...AUTO_COLUMNS, }, -} +} as any export async function buildDefaultDocs() { const inventoryData = await tableImport( diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index 457819251a..34dd0c6f80 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -8,6 +8,7 @@ import { Database, FieldSchema, LinkDocumentValue, + RelationshipFieldMetadata, RelationshipType, Row, Table, @@ -133,7 +134,10 @@ class LinkController { * Given the link field of this table, and the link field of the linked table, this makes sure * the state of relationship type is accurate on both. */ - handleRelationshipType(linkerField: FieldSchema, linkedField: FieldSchema) { + handleRelationshipType( + linkerField: RelationshipFieldMetadata, + linkedField: RelationshipFieldMetadata + ) { if ( !linkerField.relationshipType || linkerField.relationshipType === RelationshipType.MANY_TO_MANY @@ -183,7 +187,9 @@ class LinkController { // if 1:N, ensure that this ID is not already attached to another record const linkedTable = await this._db.get(field.tableId) - const linkedSchema = linkedTable.schema[field.fieldName!] + const linkedSchema = linkedTable.schema[ + field.fieldName! + ] as RelationshipFieldMetadata // We need to map the global users to metadata in each app for relationships if (field.tableId === InternalTables.USER_METADATA) { @@ -291,7 +297,7 @@ class LinkController { */ async removeFieldFromTable(fieldName: string) { let oldTable = this._oldTable - let field = oldTable?.schema[fieldName] as FieldSchema + let field = oldTable?.schema[fieldName] as RelationshipFieldMetadata const linkDocs = await this.getTableLinkDocs() let toDelete = linkDocs.filter(linkDoc => { let correctFieldName = @@ -351,9 +357,9 @@ class LinkController { name: field.fieldName, type: FieldTypes.LINK, // these are the props of the table that initiated the link - tableId: table._id, + tableId: table._id!, fieldName: fieldName, - }) + } as any) // update table schema after checking relationship types schema[fieldName] = fields.linkerField diff --git a/packages/server/src/integrations/base/sqlTable.ts b/packages/server/src/integrations/base/sqlTable.ts index 4383167f4a..5915a6e868 100644 --- a/packages/server/src/integrations/base/sqlTable.ts +++ b/packages/server/src/integrations/base/sqlTable.ts @@ -1,5 +1,11 @@ import { Knex, knex } from "knex" -import { Operation, QueryJson, RenameColumn, Table } from "@budibase/types" +import { + NumberFieldMetadata, + Operation, + QueryJson, + RenameColumn, + Table, +} from "@budibase/types" import { breakExternalTableId } from "../utils" import SchemaBuilder = Knex.SchemaBuilder import CreateTableBuilder = Knex.CreateTableBuilder @@ -15,7 +21,7 @@ function generateSchema( let primaryKey = table && table.primary ? table.primary[0] : null const columns = Object.values(table.schema) // all columns in a junction table will be meta - let metaCols = columns.filter(col => col.meta) + let metaCols = columns.filter(col => (col as NumberFieldMetadata).meta) let isJunction = metaCols.length === columns.length // can't change primary once its set for now if (primaryKey && !oldTable && !isJunction) { @@ -25,7 +31,9 @@ function generateSchema( } // check if any columns need added - const foreignKeys = Object.values(table.schema).map(col => col.foreignKey) + const foreignKeys = Object.values(table.schema).map( + col => (col as any).foreignKey + ) for (let [key, column] of Object.entries(table.schema)) { // skip things that are already correct const oldColumn = oldTable ? oldTable.schema[key] : null diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index 51e418c324..4049d898fb 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -1,10 +1,11 @@ import cloneDeep from "lodash/cloneDeep" import validateJs from "validate.js" -import { FieldType, Row, Table, TableSchema } from "@budibase/types" +import { Row, Table, TableSchema } from "@budibase/types" import { FieldTypes } from "../../../constants" import { makeExternalQuery } from "../../../integrations/base/query" import { Format } from "../../../api/controllers/view/exporters" import sdk from "../.." +import { isRelationshipColumn } from "../../../db/utils" export async function getDatasourceAndQuery(json: any) { const datasourceId = json.endpoint.datasourceId @@ -50,10 +51,10 @@ export function cleanExportRows( } function isForeignKey(key: string, table: Table) { - const relationships = Object.values(table.schema).filter( - column => column.type === FieldType.LINK + const relationships = Object.values(table.schema).filter(isRelationshipColumn) + return relationships.some( + relationship => (relationship as any).foreignKey === key ) - return relationships.some(relationship => relationship.foreignKey === key) } export async function validate({ diff --git a/packages/server/src/utilities/rowProcessor/tests/utils.spec.ts b/packages/server/src/utilities/rowProcessor/tests/utils.spec.ts index 68b62a3291..4a943ddd67 100644 --- a/packages/server/src/utilities/rowProcessor/tests/utils.spec.ts +++ b/packages/server/src/utilities/rowProcessor/tests/utils.spec.ts @@ -4,7 +4,7 @@ import { FieldSchema, FieldType, RelationshipType } from "@budibase/types" describe("rowProcessor utility", () => { describe("fixAutoColumnSubType", () => { - let schema: FieldSchema = { + const schema: FieldSchema = { name: "", type: FieldType.LINK, subtype: "", // missing subtype diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index 343aa16699..3cfddea770 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -36,7 +36,7 @@ export interface OneToManyRelationshipFieldMetadata export interface ManyToOneRelationshipFieldMetadata extends BaseRelationshipFieldMetadata { relationshipType: RelationshipType.MANY_TO_ONE - foreignKey: string + foreignKey?: string } export type RelationshipFieldMetadata = | ManyToManyRelationshipFieldMetadata @@ -52,10 +52,11 @@ export interface AutoColumnFieldMetadata extends BaseFieldSchema { autoReason?: AutoReason } -interface NumberForeignKeyMetadata { - subtype: AutoFieldSubTypes.AUTO_ID - autoReason: AutoReason.FOREIGN_KEY - autocolumn: true +export interface NumberFieldMetadata extends BaseFieldSchema { + type: FieldType.NUMBER + autocolumn?: boolean + subtype?: AutoFieldSubTypes.AUTO_ID + autoReason?: AutoReason.FOREIGN_KEY // used specifically when Budibase generates external tables, this denotes if a number field // is a foreign key used for a many-to-many relationship meta?: { @@ -64,11 +65,6 @@ interface NumberForeignKeyMetadata { } } -export type NumberFieldMetadata = BaseFieldSchema & { - type: FieldType.NUMBER - autocolumn?: boolean -} & (NumberForeignKeyMetadata | {}) - export interface DateFieldMetadata extends BaseFieldSchema { type: FieldType.DATETIME ignoreTimezones?: boolean @@ -77,6 +73,10 @@ export interface DateFieldMetadata extends BaseFieldSchema { export interface StringFieldMetadata extends BaseFieldSchema { type: FieldType.STRING +} + +export interface LongFormFieldMetadata extends BaseFieldSchema { + type: FieldType.LONGFORM useRichText?: boolean | null } @@ -117,7 +117,7 @@ interface BaseFieldSchema extends UIFieldMetadata { externalType?: string constraints?: FieldConstraints autocolumn?: boolean - autoReason?: AutoReason + autoReason?: AutoReason.FOREIGN_KEY subtype?: string } @@ -130,6 +130,7 @@ interface OtherFieldMetadata extends BaseFieldSchema { | FieldType.STRING | FieldType.FORMULA | FieldType.NUMBER + | FieldType.LONGFORM > } @@ -141,6 +142,7 @@ export type FieldSchema = | StringFieldMetadata | FormulaFieldMetadata | NumberFieldMetadata + | LongFormFieldMetadata export interface TableSchema { [key: string]: FieldSchema