From 48dca901bcb44df2b8868abc543e6ef826ead659 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 1 Mar 2024 09:09:42 -0500 Subject: [PATCH] refactor: seed within create local db client --- .../db/src/core/integration/vite-plugin-db.ts | 24 +++---- packages/db/src/runtime/db-client.ts | 67 ++++++++++++++++++- 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/packages/db/src/core/integration/vite-plugin-db.ts b/packages/db/src/core/integration/vite-plugin-db.ts index 5c53cda688..f917adf940 100644 --- a/packages/db/src/core/integration/vite-plugin-db.ts +++ b/packages/db/src/core/integration/vite-plugin-db.ts @@ -96,29 +96,29 @@ export function getLocalVirtualModContents({ ); return ` -import { asDrizzleTable, createLocalDatabaseClient, seedLocal } from ${RUNTIME_IMPORT}; +import { asDrizzleTable, createLocalDatabaseClient } from ${RUNTIME_IMPORT}; ${ useBundledDbUrl ? `import dbUrl from ${JSON.stringify(`${dbUrl}?fileurl`)};` : `const dbUrl = ${JSON.stringify(dbUrl)};` } -export const db = createLocalDatabaseClient({ dbUrl }); +export const db = await createLocalDatabaseClient({ + dbUrl, + seedProps: ${ + shouldSeed + ? `{ + tables: ${JSON.stringify(tables)}, + fileGlob: import.meta.glob(${JSON.stringify(seedFilePaths)}), + }` + : 'undefined' + }, +}); export * from ${RUNTIME_DRIZZLE_IMPORT}; export * from ${RUNTIME_CONFIG_IMPORT}; ${getStringifiedCollectionExports(tables)} - -${ - shouldSeed - ? `await seedLocal({ - db, - tables: ${JSON.stringify(tables)}, - fileGlob: import.meta.glob(${JSON.stringify(seedFilePaths)}), -});` - : '' -} `; } diff --git a/packages/db/src/runtime/db-client.ts b/packages/db/src/runtime/db-client.ts index 56d1c9b97a..7a6d2c0301 100644 --- a/packages/db/src/runtime/db-client.ts +++ b/packages/db/src/runtime/db-client.ts @@ -1,15 +1,28 @@ import type { InStatement } from '@libsql/client'; -import { createClient } from '@libsql/client'; +import { LibsqlError, createClient } from '@libsql/client'; import type { LibSQLDatabase } from 'drizzle-orm/libsql'; import { drizzle as drizzleLibsql } from 'drizzle-orm/libsql'; import { drizzle as drizzleProxy } from 'drizzle-orm/sqlite-proxy'; import { z } from 'zod'; +import type { SqliteDB } from './index.js'; +import { SEED_ERROR } from '../core/errors.js'; +import type { DBTables } from '../core/types.js'; +import { recreateTables } from './queries.js'; const isWebContainer = !!process.versions?.webcontainer; interface LocalDatabaseClient extends LibSQLDatabase, Disposable {} -export function createLocalDatabaseClient({ dbUrl }: { dbUrl: string }): LocalDatabaseClient { +export async function createLocalDatabaseClient({ + dbUrl, + seedProps, +}: { + dbUrl: string; + seedProps?: { + tables: DBTables; + fileGlob: Record Promise>; + }; +}): Promise { const url = isWebContainer ? 'file:content.db' : dbUrl; const client = createClient({ url }); const db = Object.assign(drizzleLibsql(client), { @@ -18,9 +31,59 @@ export function createLocalDatabaseClient({ dbUrl }: { dbUrl: string }): LocalDa }, }); + if (seedProps) { + await seedLocal({ db, ...seedProps }); + console.log('seed finished'); + } + return db; } +/** + * Sorted by precedence. + * Ex. If both "seed.dev.ts" and "seed.ts" are present, + * "seed.dev.ts" will be used. + */ +export const SEED_DEV_FILE_NAMES_SORTED = [ + 'seed.development.ts', + 'seed.development.js', + 'seed.development.mjs', + 'seed.development.mts', + 'seed.dev.ts', + 'seed.dev.js', + 'seed.dev.mjs', + 'seed.dev.mts', + 'seed.ts', + 'seed.js', + 'seed.mjs', + 'seed.mts', +]; + +async function seedLocal({ + db, + tables, + // Glob all potential seed files to catch renames and deletions. + fileGlob, +}: { + db: SqliteDB; + tables: DBTables; + fileGlob: Record Promise>; +}) { + await recreateTables({ db, tables }); + for (const fileName of SEED_DEV_FILE_NAMES_SORTED) { + const key = Object.keys(fileGlob).find((f) => f.endsWith(fileName)); + if (key) { + await fileGlob[key]().catch((e) => { + if (e instanceof LibsqlError) { + throw new Error(SEED_ERROR(e.message)); + } + throw e; + }); + return; + } + } +} + export function createRemoteDatabaseClient(appToken: string, remoteDbURL: string) { const url = new URL('/db/query', remoteDbURL);