Skip to content

Commit

Permalink
feat(db): drop built-in database adapters in favor of db0 connectors (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz authored Jan 22, 2025
1 parent c11f90a commit 1a7371a
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 374 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"c12": "^2.0.1",
"chokidar": "^4.0.3",
"consola": "^3.4.0",
"db0": "^0.2.1",
"defu": "^6.1.4",
"destr": "^2.0.3",
"fast-glob": "^3.3.3",
Expand Down Expand Up @@ -84,7 +85,6 @@
"slugify": "^1.6.6",
"socket.io-client": "^4.8.1",
"tar": "^7.4.3",
"typescript": "5.7.3",
"ufo": "^1.5.4",
"unified": "^11.0.5",
"unist-util-stringify-position": "^4.0.0",
Expand All @@ -96,7 +96,7 @@
},
"peerDependencies": {
"@libsql/client": "*",
"pg": "*"
"@electric-sql/pglite": "*"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250121.0",
Expand All @@ -121,6 +121,7 @@
"micromark-util-types": "^2.0.1",
"nuxt": "^3.15.2",
"release-it": "^18.1.1",
"typescript": "5.7.3",
"vitest": "^3.0.3",
"vue-tsc": "^2.2.0",
"wrangler": "^3.103.2"
Expand Down
200 changes: 57 additions & 143 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { findPreset } from './presets'
import type { Manifest } from './types/manifest'
import { setupPreview } from './utils/preview/module'
import { parseSourceBase } from './utils/source'
import { getLocalDatabase } from './utils/sqlite'
import { getLocalDatabase, resolveDatabaseAdapter } from './utils/sqlite'

// Export public utils
export * from './utils'
Expand Down Expand Up @@ -165,9 +165,9 @@ export default defineNuxtModule<ModuleOptions>({
const preset = findPreset(nuxt)
await preset.setupNitro(config, { manifest, resolver })

const adapter = config.runtimeConfig!.content!.database?.type || options.database.type || 'sqlite'
config.alias ||= {}
config.alias['#content/adapter'] = resolver.resolve(`./runtime/adapters/${adapter}`)
config.alias['#content/adapter'] = resolveDatabaseAdapter(config.runtimeConfig!.content!.database?.type || options.database.type, resolver)
config.alias['#content/local-adapter'] = resolveDatabaseAdapter(options._localDatabase!.type || 'sqlite', resolver)

config.handlers ||= []
config.handlers.push({
Expand Down
24 changes: 0 additions & 24 deletions src/runtime/adapters/d1.ts

This file was deleted.

26 changes: 0 additions & 26 deletions src/runtime/adapters/libsql.ts

This file was deleted.

43 changes: 0 additions & 43 deletions src/runtime/adapters/postgres.ts

This file was deleted.

11 changes: 0 additions & 11 deletions src/runtime/adapters/sqlite.ts

This file was deleted.

31 changes: 1 addition & 30 deletions src/runtime/internal/bunsqlite.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import * as zlib from 'node:zlib'
import { isAbsolute } from 'pathe'
import type { Database as BunDatabaseType } from 'bun:sqlite'

/**
* CompressionStream and DecompressionStream polyfill for Bun
Expand Down Expand Up @@ -42,31 +40,4 @@ if (!globalThis.CompressionStream) {
} as unknown as typeof DecompressionStream
}

function getBunDatabaseSync() {
// A top level import will make Nuxt complain about a missing module
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('bun:sqlite').Database
}

let db: BunDatabaseType
export const getBunSqliteDatabaseAdapter = (opts: { filename: string }) => {
const Database = getBunDatabaseSync()
if (!db) {
const filename = !opts || isAbsolute(opts?.filename || '') || opts?.filename === ':memory:'
? opts?.filename
: new URL(opts.filename, (globalThis as unknown as { _importMeta_: { url: string } })._importMeta_.url).pathname
db = new Database(process.platform === 'win32' && filename.startsWith('/') ? filename.slice(1) : filename, { create: true })
}

return {
async all<T>(sql: string, params?: Array<number | string | boolean>): Promise<T[]> {
return params ? db.prepare(sql).all(...params) as T[] : db.prepare(sql).all() as T[]
},
async first<T>(sql: string, params?: Array<number | string | boolean>): Promise<T | null> {
return params ? db.prepare(sql).get(...params) as T : db.prepare(sql).get() as T
},
async exec(sql: string): Promise<unknown> {
return db.prepare(sql).run()
},
}
}
export { default as default } from 'db0/connectors/bun-sqlite'
31 changes: 0 additions & 31 deletions src/runtime/internal/database-adapter.ts

This file was deleted.

5 changes: 2 additions & 3 deletions src/runtime/internal/database.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@ import { fetchDatabase } from './api'
import { checksums, tables } from '#content/manifest'

let db: Database

export function loadDatabaseAdapter<T>(collection: T): DatabaseAdapter {
return {
all: async <T>(sql: string, params: DatabaseBindParams) => {
all: async <T>(sql: string, params?: DatabaseBindParams) => {
await loadAdapter(collection)

return db
.exec({ sql, bind: params, rowMode: 'object', returnValue: 'resultRows' })
.map(row => refineContentFields(sql, row) as T)
},
first: async <T>(sql: string, params: DatabaseBindParams) => {
first: async <T>(sql: string, params?: DatabaseBindParams) => {
await loadAdapter(collection)

return refineContentFields(
Expand Down
46 changes: 35 additions & 11 deletions src/runtime/internal/database.server.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
import type { SqliteDatabaseConfig, DatabaseAdapter, RuntimeConfig } from '@nuxt/content'
import type { DatabaseAdapter, RuntimeConfig } from '@nuxt/content'
import type { H3Event } from 'h3'
import { isAbsolute } from 'pathe'
import type { Connector } from 'db0'
import { decompressSQLDump } from './dump'
import { fetchDatabase } from './api'
import { refineContentFields } from './collection'
import { tables, checksums } from '#content/manifest'
import adapter from '#content/adapter'
import localAdapter from '#content/local-adapter'

export default function loadDatabaseAdapter(config: RuntimeConfig['content']) {
const { database, localDatabase } = config

let _adapter: DatabaseAdapter
let _adapter: Connector
async function loadAdapter() {
if (!_adapter) {
if (import.meta.dev || ['nitro-prerender', 'nitro-dev'].includes(import.meta.preset as string)) {
_adapter = await loadSqliteAdapter(localDatabase)
_adapter = await localAdapter(refineDatabaseConfig(localDatabase))
}
else {
_adapter = adapter(database)
_adapter = adapter(refineDatabaseConfig(database as unknown))
}
}

return _adapter
}

return <DatabaseAdapter>{
all: async (sql, params) => {
all: async (sql, params = []) => {
const db = await loadAdapter()
return await db.all<Record<string, unknown>>(sql, params)
const result = await db.prepare(sql).all(...params)

if (!result) {
return []
}

return result.map((item: unknown) => refineContentFields(sql, item))
},
first: async (sql, params) => {
first: async (sql, params = []) => {
const db = await loadAdapter()
return await db.first<Record<string, unknown>>(sql, params)
const item = await db.prepare(sql).get(...params)

if (!item) {
return item
}

return refineContentFields(sql, item)
},
exec: async (sql) => {
const db = await loadAdapter()
Expand Down Expand Up @@ -93,6 +108,15 @@ async function loadDatabaseDump(event: H3Event, collection: string): Promise<str
})
}

function loadSqliteAdapter(config: SqliteDatabaseConfig) {
return import('../adapters/sqlite').then(m => m.default(config))
function refineDatabaseConfig(config: { filename?: string }) {
config = { ...config }
if ('filename' in config) {
const filename = isAbsolute(config?.filename || '') || config?.filename === ':memory:'
? config?.filename
: new URL(config.filename, (globalThis as unknown as { _importMeta_: { url: string } })._importMeta_.url).pathname

config.filename = process.platform === 'win32' && filename.startsWith('/') ? filename.slice(1) : filename
}

return config
}
24 changes: 0 additions & 24 deletions src/runtime/internal/sqlite.ts

This file was deleted.

12 changes: 8 additions & 4 deletions src/types/database.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export type DatabaseBindParams = Array<DatabaseBindable>
import type { Primitive, Connector } from 'db0'

export type CacheEntry = { id: string, checksum: string, parsedContent: string }

export type DatabaseBindParams = Primitive[]

export type DatabaseBindable = number | string | boolean | null | undefined

Expand All @@ -11,12 +15,12 @@ export interface DatabaseAdapter {
export type DatabaseAdapterFactory<Options> = (otps?: Options) => DatabaseAdapter

export interface LocalDevelopmentDatabase {
fetchDevelopmentCache(): Promise<Record<string, { checksum: string, parsedContent: string }>>
fetchDevelopmentCacheForKey(key: string): Promise<{ id: string, checksum: string, parsedContent: string } | undefined>
fetchDevelopmentCache(): Promise<Record<string, CacheEntry>>
fetchDevelopmentCacheForKey(key: string): Promise<CacheEntry | undefined>
insertDevelopmentCache(id: string, checksum: string, parsedContent: string): void
deleteDevelopmentCache(id: string): void
dropContentTables(): void
exec(sql: string): void
close(): void
database?: DatabaseAdapter
database?: Connector
}
8 changes: 8 additions & 0 deletions src/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ declare module '#content/adapter' {
export { adapter as default }
}

declare module '#content/local-adapter' {
import type { DatabaseAdapter } from './database'

const adapter: DatabaseAdapter

export { adapter as default }
}

declare module '#content/collections' {
export const collections: Record<string, unknown>
}
Expand Down
Loading

0 comments on commit 1a7371a

Please sign in to comment.