From 338a1afb5cdf4e4a6f04715eace84a743d371cf9 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 1 Feb 2024 17:01:35 -0500 Subject: [PATCH] feat: add foreignkeys to create table --- packages/db/src/core/queries.ts | 35 ++++++++++++++++++- .../db/test/fixtures/recipes/astro.config.ts | 3 +- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/db/src/core/queries.ts b/packages/db/src/core/queries.ts index dbcd2eab62..28e155206d 100644 --- a/packages/db/src/core/queries.ts +++ b/packages/db/src/core/queries.ts @@ -87,6 +87,8 @@ export function getCreateTableQuery(collectionName: string, collection: DBCollec colQueries.push(colQuery); } + colQueries.push(...getCreateForeignKeyQueries(collectionName, collection)); + query += colQueries.join(', ') + ')'; return query; } @@ -97,7 +99,7 @@ export function getCreateIndexQueries( ) { let queries: string[] = []; for (const [indexName, indexProps] of Object.entries(collection.indexes ?? {})) { - const onColNames = Array.isArray(indexProps.on) ? indexProps.on : [indexProps.on]; + const onColNames = asArray(indexProps.on); const onCols = onColNames.map((colName) => sqlite.escapeName(colName)); const unique = indexProps.unique ? 'UNIQUE ' : ''; @@ -109,6 +111,37 @@ export function getCreateIndexQueries( return queries; } +export function getCreateForeignKeyQueries(collectionName: string, collection: DBCollection) { + let queries: string[] = []; + for (const foreignKey of collection.foreignKeys ?? []) { + const fields = asArray(foreignKey.fields); + const references = asArray(foreignKey.references()); + + if (fields.length !== references.length) { + throw new Error( + `Foreign key on ${collectionName} is misconfigured. \`fields\` and \`references\` must be the same length.` + ); + } + const referencedCollection = references[0]?.collection; + if (!referencedCollection) { + throw new Error( + `Foreign key on ${collectionName} is misconfigured. \`references\` cannot be empty.` + ); + } + const query = `FOREIGN KEY (${fields + .map((f) => sqlite.escapeName(f)) + .join(', ')}) REFERENCES ${sqlite.escapeName(referencedCollection)}(${references + .map((r) => sqlite.escapeName(r.name!)) + .join(', ')})`; + queries.push(query); + } + return queries; +} + +function asArray(value: T | T[]) { + return Array.isArray(value) ? value : [value]; +} + export function schemaTypeToSqlType(type: FieldType): 'text' | 'integer' { switch (type) { case 'date': diff --git a/packages/db/test/fixtures/recipes/astro.config.ts b/packages/db/test/fixtures/recipes/astro.config.ts index ab131f9528..e0d1a1489b 100644 --- a/packages/db/test/fixtures/recipes/astro.config.ts +++ b/packages/db/test/fixtures/recipes/astro.config.ts @@ -14,11 +14,12 @@ const Ingredient = defineCollection({ id: field.number({ primaryKey: true }), name: field.text(), quantity: field.number(), - recipeId: field.text({ references: () => Recipe.fields.id }), + recipeId: field.number(), }, indexes: { recipeIdx: { on: 'recipeId' }, }, + foreignKeys: [{ fields: 'recipeId', references: () => [Recipe.fields.id] }], }); export default defineConfig({