diff --git a/packages/server/src/api/controllers/table/index.ts b/packages/server/src/api/controllers/table/index.ts index 2780185ed7..36dee4811e 100644 --- a/packages/server/src/api/controllers/table/index.ts +++ b/packages/server/src/api/controllers/table/index.ts @@ -11,11 +11,16 @@ import { BulkImportRequest, BulkImportResponse, FetchTablesResponse, + InternalTable, + MigrateRequest, + MigrateResponse, SaveTableRequest, SaveTableResponse, Table, TableResponse, UserCtx, + isBBReferenceField, + isRelationshipField, } from "@budibase/types" import sdk from "../../../sdk" import { jsonFromCsvString } from "../../../utilities/csv" @@ -159,4 +164,53 @@ export async function validateExistingTableImport(ctx: UserCtx) { } } -export async function migrate(ctx: UserCtx) {} +function error(ctx: UserCtx, message: string, status = 400) { + ctx.status = status + ctx.body = { message } +} + +export async function migrate(ctx: UserCtx) { + const { tableId, oldColumn, newColumn } = ctx.request.body + + // For now we're only supporting migrations of user relationships to user + // columns in internal tables. In future we may want to support other + // migrations but for now return an error if we aren't migrating a user + // relationship. + if (isExternalTable(tableId)) { + return error(ctx, "External tables cannot be migrated") + } + + const table = await sdk.tables.getTable(tableId) + + if (!(oldColumn.name in table.schema)) { + return error( + ctx, + `Column "${oldColumn.name}" does not exist on table "${table.name}"` + ) + } + + if (newColumn.name in table.schema) { + return error( + ctx, + `Column "${newColumn.name}" already exists on table "${table.name}"` + ) + } + + if (!isBBReferenceField(newColumn)) { + return error(ctx, `Column "${newColumn.name}" is not a user column`) + } + + if (newColumn.subtype !== "user" && newColumn.subtype !== "users") { + return error(ctx, `Column "${newColumn.name}" is not a user column`) + } + + if (!isRelationshipField(oldColumn)) { + return error(ctx, `Column "${oldColumn.name}" is not a user relationship`) + } + + if (oldColumn.tableId !== InternalTable.USER_METADATA) { + return error(ctx, `Column "${oldColumn.name}" is not a user relationship`) + } + + let rows = await sdk.rows.fetch(tableId) +} diff --git a/packages/types/src/api/web/app/table.ts b/packages/types/src/api/web/app/table.ts index cb5faaa9ea..61da12d041 100644 --- a/packages/types/src/api/web/app/table.ts +++ b/packages/types/src/api/web/app/table.ts @@ -1,4 +1,5 @@ import { + FieldSchema, Row, Table, TableRequest, @@ -33,3 +34,13 @@ export interface BulkImportRequest { export interface BulkImportResponse { message: string } + +export interface MigrateRequest { + tableId: string + oldColumn: FieldSchema + newColumn: FieldSchema +} + +export interface MigrateResponse { + message: string +} diff --git a/packages/types/src/documents/app/table/schema.ts b/packages/types/src/documents/app/table/schema.ts index e529a8e8b7..755ccf61e7 100644 --- a/packages/types/src/documents/app/table/schema.ts +++ b/packages/types/src/documents/app/table/schema.ts @@ -164,3 +164,33 @@ export type FieldSchema = export interface TableSchema { [key: string]: FieldSchema } + +export function isRelationshipField( + field: FieldSchema +): field is RelationshipFieldMetadata { + return field.type === FieldType.LINK +} + +export function isManyToMany( + field: RelationshipFieldMetadata +): field is ManyToManyRelationshipFieldMetadata { + return field.relationshipType === RelationshipType.MANY_TO_MANY +} + +export function isOneToMany( + field: RelationshipFieldMetadata +): field is OneToManyRelationshipFieldMetadata { + return field.relationshipType === RelationshipType.ONE_TO_MANY +} + +export function isManyToOne( + field: RelationshipFieldMetadata +): field is ManyToOneRelationshipFieldMetadata { + return field.relationshipType === RelationshipType.MANY_TO_ONE +} + +export function isBBReferenceField( + field: FieldSchema +): field is BBReferenceFieldMetadata { + return field.type === FieldType.BB_REFERENCE +}