Skip to content

Commit 6957c1c

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

5 files changed

Lines changed: 53 additions & 11 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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ export default defineNuxtModule<ModuleOptions>({
302302
if (options.aliasServerImport) {
303303
nuxt.options.alias["#postgres"] = resolveAlias(options.aliasServerImport, nuxt.options.alias)
304304
}
305+
nuxt.options.alias["#witchcraft-nuxt-postgres"] = resolve("runtime")
305306

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

src/runtime/composables/useClientDb.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,19 @@ 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 { AllOptions, InitOptions } from "../utils/clientDatabaseManager.js"
7+
import type { LocalPgDbTypes } from "../types.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+
{
19+
return useGlobalClientDatabaseManager().useClientDb(name, opts, initOpts) as any
1020
}
21+

src/runtime/types.ts

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

src/runtime/utils/clientDatabaseManager.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ 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+
16+
17+
1418

1519
export const zMigrationJson = z.array(z.object({
1620
sql: z.array(z.string()),
@@ -56,7 +60,7 @@ export type ClientMigrationState = {
5660
skip: boolean
5761
storage?: Storage<any>
5862
}
59-
type AllOptions = Partial<Omit<ClientPostgresOptions, "clientMigrationConfig"> & {
63+
export type AllOptions = Partial<Omit<ClientPostgresOptions, "clientMigrationConfig"> & {
6064
clientMigrationOptions: MigrationOptions
6165
clientPgliteOptions: ClientPostgresOptions["clientPgliteOptions"] & {
6266
extensions?: PGliteOptions["extensions"]
@@ -72,7 +76,7 @@ type AllOptions = Partial<Omit<ClientPostgresOptions, "clientMigrationConfig"> &
7276
/** The schema to use for the client side database. This must be defined unless a proxy is being used. */
7377
schema?: any
7478
}>
75-
type InitOptions = {
79+
export type InitOptions = {
7680
bypassEnvCheck?: boolean
7781
addToWindowInDev?: boolean
7882
logger?: BaseLogger
@@ -213,15 +217,20 @@ export class ClientDatabaseManager {
213217
await this.useClientDb(name, entry.options, entry.initOptions)
214218
}
215219

216-
async useClientDb(
217-
name: string = this.defaultDatabaseName,
220+
async useClientDb<
221+
TName extends keyof LocalPgDbTypes | string,
222+
TDb extends TName extends keyof LocalPgDbTypes ? LocalPgDbTypes[TName] : (PgliteDatabase | PgRemoteDatabase)
223+
>(
224+
name: TName = this.defaultDatabaseName as TName,
218225
opts?: AllOptions, // do not define this or init will break
219226
{
220227
bypassEnvCheck = false,
221228
addToWindowInDev = true,
222229
logger = typeof console !== "undefined" ? console as any : {}
223230
}: InitOptions = {}
224-
): Promise<PgliteDatabase | PgRemoteDatabase> {
231+
):
232+
Promise<TDb>
233+
{
225234
if (!bypassEnvCheck && !import.meta.client) {
226235
return {} as any
227236
}
@@ -255,7 +264,7 @@ export class ClientDatabaseManager {
255264
})
256265
entry.migrationState.skip = true
257266
}
258-
return entry.db
267+
return entry.db as any
259268
}
260269

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

0 commit comments

Comments
 (0)