From 5e6ed0fd670f762fb5b4ec4f084697baa1264135 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Mon, 23 Oct 2023 11:54:27 +0100 Subject: [PATCH] Implement many-to-one user column migration. --- .../server/src/api/routes/tests/table.spec.ts | 61 +++++++++++++++++++ .../server/src/sdk/app/tables/migration.ts | 21 ++++--- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index 907b020246..420717f7f0 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -510,6 +510,67 @@ describe("/tables", () => { "user relationship": [users[0], users[1]], }) + const row2 = await config.api.row.save(table._id!, { + "user relationship": [users[1], users[2]], + }) + + await config.api.table.migrate(table._id!, { + oldColumn: table.schema["user relationship"], + newColumn: { + name: "user column", + type: FieldType.BB_REFERENCE, + subtype: FieldSubtype.USERS, + }, + }) + + const migratedTable = await config.api.table.get(table._id!) + expect(migratedTable.schema["user column"]).toBeDefined() + expect(migratedTable.schema["user relationship"]).not.toBeDefined() + + const row1Migrated = (await config.api.row.get(table._id!, row1._id!)) + .body as Row + expect(row1Migrated["user relationship"]).not.toBeDefined() + expect(row1Migrated["user column"].map((r: Row) => r._id)).toEqual( + expect.arrayContaining([users[0]._id, users[1]._id]) + ) + + const row2Migrated = (await config.api.row.get(table._id!, row2._id!)) + .body as Row + expect(row2Migrated["user relationship"]).not.toBeDefined() + expect(row2Migrated["user column"].map((r: Row) => r._id)).toEqual( + expect.arrayContaining([users[1]._id, users[2]._id]) + ) + }) + + it("should successfully migrate a many-to-one user relationship to a users column", async () => { + const users = await Promise.all([ + config.createUser({ email: "1@example.com" }), + config.createUser({ email: "2@example.com" }), + config.createUser({ email: "3@example.com" }), + ]) + + const table = await config.api.table.create({ + name: "table", + type: "table", + schema: { + "user relationship": { + type: FieldType.LINK, + fieldName: "test", + name: "user relationship", + constraints: { + type: "array", + presence: false, + }, + relationshipType: RelationshipType.MANY_TO_ONE, + tableId: InternalTable.USER_METADATA, + }, + }, + }) + + const row1 = await config.api.row.save(table._id!, { + "user relationship": [users[0], users[1]], + }) + const row2 = await config.api.row.save(table._id!, { "user relationship": [users[2]], }) diff --git a/packages/server/src/sdk/app/tables/migration.ts b/packages/server/src/sdk/app/tables/migration.ts index 94b8841136..08c06b28b9 100644 --- a/packages/server/src/sdk/app/tables/migration.ts +++ b/packages/server/src/sdk/app/tables/migration.ts @@ -5,8 +5,8 @@ import { FieldSubtype, InternalTable, ManyToManyRelationshipFieldMetadata, + ManyToOneRelationshipFieldMetadata, OneToManyRelationshipFieldMetadata, - RelationshipFieldMetadata, RelationshipType, Row, Table, @@ -88,21 +88,24 @@ function getColumnMigrator( `Column "${oldColumn.name}" is a one-to-many column but "${newColumn.name}" is not a single user column` ) } - return new OneToManyUserColumnMigrator(table, oldColumn, newColumn) + return new SingleUserColumnMigrator(table, oldColumn, newColumn) } - if (oldColumn.relationshipType === RelationshipType.MANY_TO_MANY) { + if ( + oldColumn.relationshipType === RelationshipType.MANY_TO_MANY || + oldColumn.relationshipType === RelationshipType.MANY_TO_ONE + ) { if (newColumn.subtype !== FieldSubtype.USERS) { throw new BadRequestError( - `Column "${oldColumn.name}" is a many-to-many column but "${newColumn.name}" is not a multi user column` + `Column "${oldColumn.name}" is a ${oldColumn.relationshipType} column but "${newColumn.name}" is not a multi user column` ) } - return new ManyToManyUserColumnMigrator(table, oldColumn, newColumn) + return new MultiUserColumnMigrator(table, oldColumn, newColumn) } throw new BadRequestError(`Unknown migration type`) } -class OneToManyUserColumnMigrator implements ColumnMigrator { +class SingleUserColumnMigrator implements ColumnMigrator { constructor( private table: Table, private oldColumn: OneToManyRelationshipFieldMetadata, @@ -138,10 +141,12 @@ class OneToManyUserColumnMigrator implements ColumnMigrator { } } -class ManyToManyUserColumnMigrator implements ColumnMigrator { +class MultiUserColumnMigrator implements ColumnMigrator { constructor( private table: Table, - private oldColumn: ManyToManyRelationshipFieldMetadata, + private oldColumn: + | ManyToManyRelationshipFieldMetadata + | ManyToOneRelationshipFieldMetadata, private newColumn: BBReferenceFieldMetadata ) {}