From 21e2d7ddbeea047402f2643f78c7ba2f616280ee Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 5 Oct 2023 14:25:25 +0200 Subject: [PATCH] Fix relationship types --- .../api/controllers/row/ExternalRequest.ts | 51 +++++++++++++------ packages/server/src/integrations/oracle.ts | 3 +- .../src/utilities/rowProcessor/index.ts | 18 +++++-- .../types/src/documents/app/table/schema.ts | 31 +++++++---- 4 files changed, 73 insertions(+), 30 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 2ad1afe202..0fea102f7b 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -5,8 +5,11 @@ import { FieldType, FilterType, IncludeRelationship, + ManyToManyRelationshipFieldMetadata, + OneToManyRelationshipFieldMetadata, Operation, PaginationJson, + RelationshipFieldMetadata, RelationshipsJson, RelationshipType, Row, @@ -254,12 +257,20 @@ function fixArrayTypes(row: Row, table: Table) { return row } -function isOneSide(field: FieldSchema) { +function isOneSide( + field: RelationshipFieldMetadata +): field is OneToManyRelationshipFieldMetadata { return ( field.relationshipType && field.relationshipType.split("-")[0] === "one" ) } +function isManyToMany( + field: RelationshipFieldMetadata +): field is ManyToManyRelationshipFieldMetadata { + return !!(field as ManyToManyRelationshipFieldMetadata).through +} + function isEditableColumn(column: FieldSchema) { const isExternalAutoColumn = column.autocolumn && @@ -352,11 +363,11 @@ export class ExternalRequest { } } // many to many - else if (field.through) { + else if (isManyToMany(field)) { // we're not inserting a doc, will be a bunch of update calls const otherKey: string = field.throughFrom || linkTablePrimary const thisKey: string = field.throughTo || tablePrimary - row[key].forEach((relationship: any) => { + for (const relationship of row[key]) { manyRelationships.push({ tableId: field.through || field.tableId, isUpdate: false, @@ -365,14 +376,14 @@ export class ExternalRequest { // leave the ID for enrichment later [thisKey]: `{{ literal ${tablePrimary} }}`, }) - }) + } } // many to one else { const thisKey: string = "id" // @ts-ignore const otherKey: string = field.fieldName - row[key].forEach((relationship: any) => { + for (const relationship of row[key]) { manyRelationships.push({ tableId: field.tableId, isUpdate: true, @@ -381,7 +392,7 @@ export class ExternalRequest { // leave the ID for enrichment later [otherKey]: `{{ literal ${tablePrimary} }}`, }) - }) + } } } // we return the relationships that may need to be created in the through table @@ -551,20 +562,24 @@ export class ExternalRequest { } const definition: any = { // if no foreign key specified then use the name of the field in other table - from: field.foreignKey || table.primary[0], + from: (field as any).foreignKey || table.primary[0], to: field.fieldName, tableName: linkTableName, // need to specify where to put this back into column: fieldName, } - if (field.through) { + if ((field as ManyToManyRelationshipFieldMetadata).through) { const { tableName: throughTableName } = breakExternalTableId( - field.through + (field as ManyToManyRelationshipFieldMetadata).through ) definition.through = throughTableName // don't support composite keys for relationships - definition.from = field.throughTo || table.primary[0] - definition.to = field.throughFrom || linkTable.primary[0] + definition.from = + (field as ManyToManyRelationshipFieldMetadata).throughTo || + table.primary[0] + definition.to = + (field as ManyToManyRelationshipFieldMetadata).throughFrom || + linkTable.primary[0] definition.fromPrimary = table.primary[0] definition.toPrimary = linkTable.primary[0] } @@ -597,12 +612,15 @@ export class ExternalRequest { continue } const isMany = field.relationshipType === RelationshipType.MANY_TO_MANY - const tableId = isMany ? field.through : field.tableId + const tableId = isMany + ? (field as ManyToManyRelationshipFieldMetadata).through + : field.tableId const { tableName: relatedTableName } = breakExternalTableId(tableId) // @ts-ignore const linkPrimaryKey = this.tables[relatedTableName].primary[0] - const manyKey = field.throughTo || primaryKey - const lookupField = isMany ? primaryKey : field.foreignKey + const manyKey = + (field as ManyToManyRelationshipFieldMetadata).throughTo || primaryKey + const lookupField = isMany ? primaryKey : (field as any).foreignKey const fieldName = isMany ? manyKey : field.fieldName if (!lookupField || !row[lookupField]) { continue @@ -617,7 +635,10 @@ export class ExternalRequest { }) // this is the response from knex if no rows found const rows = !response[0].read ? response : [] - const storeTo = isMany ? field.throughFrom || linkPrimaryKey : fieldName + const storeTo = isMany + ? (field as ManyToManyRelationshipFieldMetadata).throughFrom || + linkPrimaryKey + : fieldName related[storeTo] = { rows, isMany, tableId } } return related diff --git a/packages/server/src/integrations/oracle.ts b/packages/server/src/integrations/oracle.ts index 3e8ec15423..0ad1fdb698 100644 --- a/packages/server/src/integrations/oracle.ts +++ b/packages/server/src/integrations/oracle.ts @@ -306,7 +306,8 @@ class OracleIntegration extends Sql implements DatasourcePlus { presence: false, }, ...this.internalConvertType(oracleColumn), - } + } as any // TODO + table.schema[columnName] = fieldSchema } diff --git a/packages/server/src/utilities/rowProcessor/index.ts b/packages/server/src/utilities/rowProcessor/index.ts index 0bdaaa393e..0a7e774fc9 100644 --- a/packages/server/src/utilities/rowProcessor/index.ts +++ b/packages/server/src/utilities/rowProcessor/index.ts @@ -5,7 +5,13 @@ import { ObjectStoreBuckets } from "../../constants" import { context, db as dbCore, objectStore } from "@budibase/backend-core" import { InternalTables } from "../../db/utils" import { TYPE_TRANSFORM_MAP } from "./map" -import { FieldSubtype, Row, RowAttachment, Table } from "@budibase/types" +import { + AutoColumnFieldMetadata, + FieldSubtype, + Row, + RowAttachment, + Table, +} from "@budibase/types" import { cloneDeep } from "lodash/fp" import { processInputBBReferences, @@ -71,7 +77,7 @@ export function processAutoColumn( continue } if (!schema.subtype) { - schema = fixAutoColumnSubType(schema) + schema = fixAutoColumnSubType(schema as AutoColumnFieldMetadata) } switch (schema.subtype) { case AutoFieldSubTypes.CREATED_BY: @@ -94,8 +100,12 @@ export function processAutoColumn( break case AutoFieldSubTypes.AUTO_ID: if (creating) { - schema.lastID = !schema.lastID ? BASE_AUTO_ID : schema.lastID + 1 - row[key] = schema.lastID + const safeSchema = schema as AutoColumnFieldMetadata + + safeSchema.lastID = !safeSchema.lastID + ? BASE_AUTO_ID + : safeSchema.lastID + 1 + row[key] = safeSchema.lastID } break } diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index 1cdbb75303..53ad39ac96 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -15,22 +15,33 @@ export interface UIFieldMetadata { icon?: string } -interface ManyToManyRelationshipFieldMetadata { +interface BaseRelationshipFieldMetadata extends BaseFieldSchema { + type: FieldType.LINK + main?: boolean + fieldName?: string + tableId: string +} +export interface ManyToManyRelationshipFieldMetadata + extends BaseRelationshipFieldMetadata { relationshipType: RelationshipType.MANY_TO_MANY through: string throughFrom: string throughTo: string } -interface OneSidedRelationshipFieldMetadata { - relationshipType: RelationshipType.ONE_TO_MANY | RelationshipType.MANY_TO_ONE +export interface OneToManyRelationshipFieldMetadata + extends BaseRelationshipFieldMetadata { + relationshipType: RelationshipType.ONE_TO_MANY foreignKey: string } -export type RelationshipFieldMetadata = BaseFieldSchema & { - type: FieldType.LINK - main?: boolean - fieldName?: string - tableId: string -} & (ManyToManyRelationshipFieldMetadata | OneSidedRelationshipFieldMetadata) +export interface ManyToOneRelationshipFieldMetadata + extends BaseRelationshipFieldMetadata { + relationshipType: RelationshipType.MANY_TO_ONE + foreignKey: string +} +export type RelationshipFieldMetadata = + | ManyToManyRelationshipFieldMetadata + | OneToManyRelationshipFieldMetadata + | ManyToOneRelationshipFieldMetadata export interface AutoColumnFieldMetadata extends BaseFieldSchema { type: FieldType.AUTO @@ -106,6 +117,7 @@ interface BaseFieldSchema extends UIFieldMetadata { externalType?: string constraints?: FieldConstraints autocolumn?: boolean + autoReason?: AutoReason subtype?: string } @@ -113,7 +125,6 @@ interface OtherFieldMetadata extends BaseFieldSchema { type: Exclude< FieldType, | FieldType.DATETIME - | FieldType.DATETIME | FieldType.LINK | FieldType.AUTO | FieldType.STRING