diff --git a/src/presets/nuxthub.ts b/src/presets/nuxthub.ts index 77bd3055d..8c228b891 100644 --- a/src/presets/nuxthub.ts +++ b/src/presets/nuxthub.ts @@ -91,8 +91,16 @@ export default definePreset({ } } + const database = nitroConfig.runtimeConfig?.content?.database + // Only a remote database migrated during build is the database the runtime will use, + // a local file database is discarded with the build machine + const isRemoteDatabase = database?.type === 'd1' + || database?.type === 'postgresql' + || database?.type === 'postgres' + || (database?.type === 'libsql' && !!database.url && !database.url.startsWith('file:')) + // apply migrations during build if enabled - if (!nuxt.options.dev && hubConfig.db?.applyMigrationsDuringBuild) { + if (!nuxt.options.dev && hubConfig.db?.applyMigrationsDuringBuild && isRemoteDatabase) { // Write SQL dump to database queries when not in dev mode await mkdir(resolve(nitroConfig.rootDir!, hubConfig.dir, 'db/queries'), { recursive: true }) let i = 1 @@ -122,10 +130,11 @@ export default definePreset({ nitroConfig.runtimeConfig!.content.integrityCheck = false } // Handle local database (cannot be populated during build) - const database = nitroConfig.runtimeConfig?.content?.database - if (!nuxt.options.dev && database?.type === 'libsql' && database?.url?.startsWith('file:') && !database?.url?.startsWith('file:/tmp/')) { - logger.warn('Deploying local libsql database with Nuxthub is possible only in `/tmp` directory. Using `/tmp/sqlite.db` instead.') - database.url = 'file:/tmp/sqlite.db' + if (!nuxt.options.dev && database?.type === 'libsql' && database.url?.startsWith('file:')) { + if (!database.url.startsWith('file:/tmp/')) { + logger.warn('Deploying local libsql database with Nuxthub is possible only in `/tmp` directory. Using `/tmp/sqlite.db` instead.') + database.url = 'file:/tmp/sqlite.db' + } // Enable integrity check in production as local database cannot be re-used after build nitroConfig.runtimeConfig!.content ||= {} nitroConfig.runtimeConfig!.content.integrityCheck = true diff --git a/test/unit/nuxthubPreset.test.ts b/test/unit/nuxthubPreset.test.ts index dbed9f862..9b7aa4a65 100644 --- a/test/unit/nuxthubPreset.test.ts +++ b/test/unit/nuxthubPreset.test.ts @@ -1,3 +1,7 @@ +import { existsSync } from 'node:fs' +import { mkdtemp, readFile, readdir } from 'node:fs/promises' +import { tmpdir } from 'node:os' +import { join } from 'pathe' import { describe, expect, test, vi } from 'vitest' import type { Nuxt } from '@nuxt/schema' import type { Resolver } from '@nuxt/kit' @@ -148,3 +152,43 @@ describe('nuxthub preset setupNitro', () => { expect(nitroConfig.runtimeConfig!.content!.integrityCheck).toBe(true) }) }) + +describe('nuxthub preset setupNitro dump handoff', () => { + const dumpManifest = { collections: [], dump: { posts: ['INSERT INTO posts VALUES (1);'] } } as unknown as Manifest + + async function runSetupNitro(runtimeDb: Record) { + const nuxt = createNuxt( + { db: { dialect: 'sqlite' } }, + { db: runtimeDb, dir: '.data/hub' }, + ) + const rootDir = await mkdtemp(join(tmpdir(), 'nuxthub-preset-')) + const nitroConfig = { runtimeConfig: { content: {} }, rootDir } as unknown as NitroConfig + await nuxthubPreset.setupNitro(nitroConfig, { ...opts, manifest: dumpManifest, moduleOptions: {} as ModuleOptions, nuxt }) + return { nitroConfig, queriesDir: join(rootDir, '.data/hub/db/queries') } + } + + test('skips the handoff for a local file database and keeps the integrity check', async () => { + const { nitroConfig, queriesDir } = await runSetupNitro({ driver: 'libsql', connection: { url: 'file:.data/hub/db/sqlite.db' }, applyMigrationsDuringBuild: true }) + + expect(existsSync(queriesDir)).toBe(false) + expect(nitroConfig.runtimeConfig!.content!.database).toEqual({ type: 'libsql', url: 'file:/tmp/sqlite.db' }) + expect(nitroConfig.runtimeConfig!.content!.integrityCheck).toBe(true) + }) + + test('keeps the integrity check when the local database is already in /tmp', async () => { + const { nitroConfig, queriesDir } = await runSetupNitro({ driver: 'libsql', connection: { url: 'file:/tmp/sqlite.db' }, applyMigrationsDuringBuild: true }) + + expect(existsSync(queriesDir)).toBe(false) + expect(nitroConfig.runtimeConfig!.content!.database).toEqual({ type: 'libsql', url: 'file:/tmp/sqlite.db' }) + expect(nitroConfig.runtimeConfig!.content!.integrityCheck).toBe(true) + }) + + test('hands off the dump for a remote database and disables the integrity check', async () => { + const { nitroConfig, queriesDir } = await runSetupNitro({ driver: 'libsql', connection: { url: 'libsql://content.turso.io' }, applyMigrationsDuringBuild: true }) + + expect(await readdir(queriesDir)).toEqual(['content-database-001.sql']) + expect(await readFile(join(queriesDir, 'content-database-001.sql'), 'utf8')).toContain('INSERT INTO posts VALUES (1);') + expect(nitroConfig.runtimeConfig!.content!.database).toEqual({ type: 'libsql', url: 'libsql://content.turso.io' }) + expect(nitroConfig.runtimeConfig!.content!.integrityCheck).toBe(false) + }) +})