Skip to content

Commit 5375b75

Browse files
committed
v0feat: added ability to type return of useClientDb based on db name
1 parent 59a3b18 commit 5375b75

5 files changed

Lines changed: 50 additions & 12 deletions

File tree

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ export {}
8989

9090

9191
export default defineNitroPlugin((nitroApp) => {
92-
93-
// the module auto types the $postgres key (you can change the key name with the eventContextKeyName option)
9492
nitroApp.hooks.hook("request", event => {
9593
event.context.$postgres = postgres
9694
})
@@ -195,6 +193,22 @@ if (import.meta.client) {
195193
const db = useClientDb("client")
196194
```
197195

196+
The local database is not completely typed (with a schema). To properly type it you will need to add in some global type file:
197+
198+
```ts
199+
import * as schema from "~~/db/client-schema.ts"
200+
declare module "#witchcraft/nuxt-postgres/types.js" {
201+
export interface Register {
202+
ExtendedLocalPgDbTypes: {
203+
"client": typeof schema
204+
}
205+
}
206+
}
207+
export {}
208+
209+
210+
```
211+
198212
There are several things to keep in mind when using the client side db:
199213

200214
- While the resolved migrationJson location is added to the public runtime config, it cannot be used to import it dynamically since dynamic imports don't work with variables.

src/module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { PGliteOptions } from "@electric-sql/pglite"
33
import {
44
addImportsDir,
55
addServerScanDir,
6-
addTypeTemplate,
76
createResolver,
87
defineNuxtModule,
98
resolveAlias,
@@ -302,6 +301,7 @@ export default defineNuxtModule<ModuleOptions>({
302301
if (options.aliasServerImport) {
303302
nuxt.options.alias["#postgres"] = resolveAlias(options.aliasServerImport, nuxt.options.alias)
304303
}
304+
nuxt.options.alias["#witchcraft-nuxt-postgres"] = resolve("runtime")
305305

306306
nuxt.hook("vite:extendConfig", config => {
307307
// https:// pglite.dev/docs/bundler-support#vite

src/runtime/composables/useClientDb.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,18 @@ import type { PgliteDatabase } from "drizzle-orm/pglite"
33

44
import { useGlobalClientDatabaseManager } from "./useGlobalClientDatabaseManager.js"
55

6-
import type { ClientDatabaseManager } from "../utils/clientDatabaseManager.js"
6+
import type { LocalPgDbTypes } from "../types.js"
7+
import type { AllOptions, InitOptions } from "../utils/clientDatabaseManager.js"
78

8-
export async function useClientDb(...args: Parameters<ClientDatabaseManager["useClientDb"]>): Promise<PgliteDatabase | PgRemoteDatabase> {
9-
return useGlobalClientDatabaseManager().useClientDb(...args)
9+
export async function useClientDb<
10+
TName extends keyof LocalPgDbTypes | string,
11+
TDb extends TName extends keyof LocalPgDbTypes ? LocalPgDbTypes[TName] : (PgliteDatabase | PgRemoteDatabase)
12+
>(
13+
name: TName | undefined,
14+
opts?: AllOptions, // do not define this or init will break
15+
initOpts: InitOptions = {}
16+
):
17+
Promise<TDb> {
18+
return useGlobalClientDatabaseManager().useClientDb(name, opts, initOpts) as any
1019
}
20+

src/runtime/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface Register {
2+
}
3+
4+
export type LocalPgDbTypes = Register extends {
5+
// eslint-disable-next-line @typescript-eslint/naming-convention
6+
ExtendedLocalPgDbTypes: infer T extends Record<string, Record<string, any>>
7+
} ? T : unknown
8+

src/runtime/utils/clientDatabaseManager.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import localStorageDriver from "unstorage/drivers/localstorage"
1111
import { z } from "zod"
1212

1313
import type { ClientPostgresOptions } from "../../module.js"
14+
import type { LocalPgDbTypes } from "../types.js"
15+
1416

1517
export const zMigrationJson = z.array(z.object({
1618
sql: z.array(z.string()),
@@ -56,7 +58,7 @@ export type ClientMigrationState = {
5658
skip: boolean
5759
storage?: Storage<any>
5860
}
59-
type AllOptions = Partial<Omit<ClientPostgresOptions, "clientMigrationConfig"> & {
61+
export type AllOptions = Partial<Omit<ClientPostgresOptions, "clientMigrationConfig"> & {
6062
clientMigrationOptions: MigrationOptions
6163
clientPgliteOptions: ClientPostgresOptions["clientPgliteOptions"] & {
6264
extensions?: PGliteOptions["extensions"]
@@ -72,7 +74,7 @@ type AllOptions = Partial<Omit<ClientPostgresOptions, "clientMigrationConfig"> &
7274
/** The schema to use for the client side database. This must be defined unless a proxy is being used. */
7375
schema?: any
7476
}>
75-
type InitOptions = {
77+
export type InitOptions = {
7678
bypassEnvCheck?: boolean
7779
addToWindowInDev?: boolean
7880
logger?: BaseLogger
@@ -213,15 +215,19 @@ export class ClientDatabaseManager {
213215
await this.useClientDb(name, entry.options, entry.initOptions)
214216
}
215217

216-
async useClientDb(
217-
name: string = this.defaultDatabaseName,
218+
async useClientDb<
219+
TName extends keyof LocalPgDbTypes | string,
220+
TDb extends TName extends keyof LocalPgDbTypes ? LocalPgDbTypes[TName] : (PgliteDatabase | PgRemoteDatabase)
221+
>(
222+
name: TName = this.defaultDatabaseName as TName,
218223
opts?: AllOptions, // do not define this or init will break
219224
{
220225
bypassEnvCheck = false,
221226
addToWindowInDev = true,
222227
logger = typeof console !== "undefined" ? console as any : {}
223228
}: InitOptions = {}
224-
): Promise<PgliteDatabase | PgRemoteDatabase> {
229+
):
230+
Promise<TDb> {
225231
if (!bypassEnvCheck && !import.meta.client) {
226232
return {} as any
227233
}
@@ -255,7 +261,7 @@ export class ClientDatabaseManager {
255261
})
256262
entry.migrationState.skip = true
257263
}
258-
return entry.db
264+
return entry.db as any
259265
}
260266

261267
static useDefaultStorage(): Storage<any> | undefined {

0 commit comments

Comments
 (0)