diff --git a/bun.lockb b/bun.lockb index beb7558..99b364c 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 28057ab..b0995bd 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "resolve-from": "5.0.0" }, "devDependencies": { - "ronin": "6.0.25", + "ronin": "6.0.27", "@biomejs/biome": "1.9.4", "@types/bun": "1.2.1", "@types/ini": "4.1.1", diff --git a/src/utils/field.ts b/src/utils/field.ts index f7c3a4f..21104f1 100644 --- a/src/utils/field.ts +++ b/src/utils/field.ts @@ -73,8 +73,8 @@ export const diffFields = async ( } } - diff.push(...createFields(fieldsToAdd, modelSlug)); - diff.push(...deleteFields(fieldsToDelete, modelSlug)); + diff.push(...createFields(fieldsToAdd, modelSlug, definedFields)); + diff.push(...deleteFields(fieldsToDelete, modelSlug, definedFields)); for (const field of queriesForAdjustment || []) { // SQLite's ALTER TABLE is limited - adding UNIQUE or NOT NULL to an existing column @@ -212,10 +212,24 @@ export const fieldsToCreate = ( export const createFields = ( fields: Array, modelSlug: string, + definedFields?: Array, ): Array => { const diff: Array = []; for (const fieldToAdd of fields) { + if (fieldToAdd.unique) { + const existingFields = definedFields?.filter( + (f) => !fields.find((f2) => f2.slug === f.slug), + ); + return createTempModelQuery( + modelSlug, + definedFields || [], + [], + [], + [], + existingFields, + ); + } diff.push(createFieldQuery(modelSlug, fieldToAdd)); } @@ -247,10 +261,16 @@ export const fieldsToDrop = ( * * @returns An array of SQL queries for deleting fields. */ -const deleteFields = (fields: Array, modelSlug: string): Array => { +const deleteFields = ( + fieldsToDrop: Array, + modelSlug: string, + fields: Array, +): Array => { const diff: Array = []; - - for (const fieldToDrop of fields) { + for (const fieldToDrop of fieldsToDrop) { + if (fieldToDrop.unique) { + return createTempModelQuery(modelSlug, fields, [], [], [], fields); + } diff.push(dropFieldQuery(modelSlug, fieldToDrop.slug)); } diff --git a/src/utils/queries.ts b/src/utils/queries.ts index e6cc011..fdad6e4 100644 --- a/src/utils/queries.ts +++ b/src/utils/queries.ts @@ -131,6 +131,7 @@ export const createTempModelQuery = ( _indexes: Array, triggers: Array, customQueries?: Array, + includeFields?: Array, ): Array => { const queries: Array = []; @@ -140,7 +141,13 @@ export const createTempModelQuery = ( queries.push(createModelQuery(tempModelSlug, { fields })); // Move all the data to the copied model - queries.push(`add.${tempModelSlug}.with(() => get.${modelSlug}())`); + queries.push( + `add.${tempModelSlug}.with(() => get.${modelSlug}(${ + includeFields + ? JSON.stringify({ selecting: includeFields.map((field) => field.slug) }) + : '' + }))`, + ); if (customQueries) { queries.push(...customQueries); diff --git a/tests/fixtures/index.ts b/tests/fixtures/index.ts index 8ed0cd8..8407ee4 100644 --- a/tests/fixtures/index.ts +++ b/tests/fixtures/index.ts @@ -282,3 +282,10 @@ export const TestM = model({ name: string(), }, }) as unknown as Model; + +export const TestN = model({ + slug: 'test', + fields: { + name: string(), + }, +}) as unknown as Model; diff --git a/tests/utils/apply.test.ts b/tests/utils/apply.test.ts index fb88177..3b2a5b1 100644 --- a/tests/utils/apply.test.ts +++ b/tests/utils/apply.test.ts @@ -15,6 +15,7 @@ import { TestK, TestL, TestM, + TestN, } from '@/fixtures/index'; import { describe, expect, test } from 'bun:test'; @@ -457,4 +458,47 @@ describe('apply', () => { // @ts-expect-error This is defined! expect(newModels[0]?.fields[1]?.type).toBe('json'); }); + + test('adding a unique field', async () => { + const definedModels: Array = [TestG]; + const existingModels: Array = [TestN]; + + const db = await queryEphemeralDatabase(existingModels); + const packages = await getLocalPackages(); + const models = await getModels(packages, db); + + const modelDiff = await diffModels(definedModels, models); + + const protocol = new Protocol(packages, modelDiff); + await protocol.convertToQueryObjects(); + + const statements = protocol.getSQLStatements(models); + await db.query(statements); + + const newModels = await getModels(packages, db); + expect(newModels).toHaveLength(1); + // @ts-expect-error This is defined! + expect(newModels[0]?.fields[0]?.unique).toBe(true); + }); + + test('removing a unique field', async () => { + const definedModels: Array = [TestN]; + const existingModels: Array = [TestG]; + + const db = await queryEphemeralDatabase(existingModels); + const packages = await getLocalPackages(); + const models = await getModels(packages, db); + + const modelDiff = await diffModels(definedModels, models); + const protocol = new Protocol(packages, modelDiff); + await protocol.convertToQueryObjects(); + + const statements = protocol.getSQLStatements(models); + await db.query(statements); + + const newModels = await getModels(packages, db); + expect(newModels).toHaveLength(1); + // @ts-expect-error This is defined! + expect(newModels[0]?.fields[0]?.type).toBe('string'); + }); });