@@ -19,29 +19,36 @@ const VIRTUAL_SCHEMA_DB_ID = "\0virtual:void-db-schema";
1919const DRIZZLE_OPERATORS =
2020 "sql, eq, ne, gt, gte, lt, lte, and, or, not, desc, asc, like, ilike, notLike, inArray, notInArray, isNull, isNotNull, between, notBetween, exists, notExists, count, sum, avg, min, max" ;
2121
22+ interface DrizzlePluginOptions {
23+ forceVirtualDb ?: boolean ;
24+ }
25+
2226/**
2327 * Vite plugin for Drizzle integration.
2428 *
2529 * - Intercepts `void/db` imports in SSR/worker environments and serves
26- * a virtual module that creates a Drizzle D1 instance with the user's schema.
30+ * a virtual module that creates a Drizzle DB instance, using the user's
31+ * schema when present.
2732 * - Generates `.void/db.d.ts` with proper Drizzle types.
28- * - Sets up `@schema` Vite alias for convenient imports.
33+ * - Sets up `@schema` Vite alias for convenient imports when a schema exists .
2934 * - Updates `.void/tsconfig.json` with TypeScript paths.
3035 */
3136export function drizzlePlugin (
3237 root : string ,
3338 hasRouteTypes : boolean ,
3439 dialect : "sqlite" | "postgresql" = "sqlite" ,
40+ options : DrizzlePluginOptions = { } ,
3541) : Plugin {
3642 const outDir = join ( root , ".void" ) ;
3743 const schema = discoverSchema ( root ) ;
44+ const hasDbRuntime = schema != null || options . forceVirtualDb === true ;
3845
3946 // Always write tsconfig (for routes.d.ts, queues.d.ts, etc.)
40- ensureProjectTsconfig ( root , hasRouteTypes , schema != null ) ;
47+ ensureProjectTsconfig ( root , hasRouteTypes , hasDbRuntime , schema != null ) ;
4148
42- // Generate db.d.ts if schema exists
43- if ( schema ) {
44- generateDbDts ( outDir , schema , dialect ) ;
49+ // Generate db.d.ts when void/db is available, even without a user schema.
50+ if ( hasDbRuntime ) {
51+ generateDbDts ( outDir , schema ?? null , dialect ) ;
4552 }
4653
4754 let isBuild = false ;
@@ -74,11 +81,11 @@ export function drizzlePlugin(
7481
7582 // Only intercept void/db in server/worker environments (not client)
7683 if ( id === "void/db" && this . environment ?. name !== "client" ) {
77- if ( ! schema ) return ; // Fall through to the real module (stub)
84+ if ( ! hasDbRuntime ) return ; // Fall through to the real module (stub)
7885 // Don't redirect schema files to avoid circular dependency
7986 // (virtual:void-db imports the schema, which imports void/db).
8087 // Schema files only need SQL helpers, not the runtime DB instance.
81- if ( importer ) {
88+ if ( schema && importer ) {
8289 if ( schema . type === "file" && importer === schema . path ) return VIRTUAL_SCHEMA_DB_ID ;
8390 if ( schema . type === "directory" && importer . startsWith ( schema . path ) ) {
8491 return VIRTUAL_SCHEMA_DB_ID ;
@@ -112,14 +119,17 @@ export function createDb() {
112119 }
113120
114121 // void/db virtual module
115- const schemaImport = JSON . stringify ( schema ! . path ) ;
122+ const schemaImport = schema
123+ ? `import * as schema from ${ JSON . stringify ( schema . path ) } ;`
124+ : "" ;
125+ const drizzleConfig = schema ? ", { schema }" : "" ;
116126
117127 if ( dialect === "postgresql" ) {
118128 return `
119129import { drizzle } from ${ JSON . stringify ( drizzleNodePgResolved ) } ;
120130import pg from "pg";
121131import { getRuntimeBinding } from ${ JSON . stringify ( envModuleResolved ) } ;
122- import * as schema from ${ schemaImport } ;
132+ ${ schemaImport }
123133export { ${ DRIZZLE_OPERATORS } } from ${ JSON . stringify ( drizzleOrmResolved ) } ;
124134
125135let _prodInstance;
@@ -137,10 +147,10 @@ function getInstance() {
137147 // workerd kills TCP sockets between requests, so pg.Pool's cached
138148 // connections go stale and hang. Fresh Pool = fresh connection every time.
139149 if (getRuntimeBinding("DATABASE_URL")) {
140- return drizzle(new pg.Pool({ connectionString: getRuntimeBinding("DATABASE_URL"), max: 1 }), { schema });
150+ return drizzle(new pg.Pool({ connectionString: getRuntimeBinding("DATABASE_URL"), max: 1 })${ drizzleConfig } );
141151 }
142152 // Production (Hyperdrive): cache the instance — Hyperdrive handles pooling.
143- _prodInstance ??= drizzle(getConnectionString(), { schema });
153+ _prodInstance ??= drizzle(getConnectionString()${ drizzleConfig } );
144154 return _prodInstance;
145155}
146156
@@ -151,7 +161,7 @@ export const db = new Proxy({}, {
151161});
152162
153163export function createDb(connectionString) {
154- return drizzle(connectionString, { schema });
164+ return drizzle(connectionString${ drizzleConfig } );
155165}
156166` ;
157167 }
@@ -160,20 +170,20 @@ export function createDb(connectionString) {
160170 return `
161171import { drizzle } from ${ JSON . stringify ( drizzleD1Resolved ) } ;
162172import { requireRuntimeBinding } from ${ JSON . stringify ( envModuleResolved ) } ;
163- import * as schema from ${ schemaImport } ;
173+ ${ schemaImport }
164174export { ${ DRIZZLE_OPERATORS } } from ${ JSON . stringify ( drizzleOrmResolved ) } ;
165175
166176let _instance;
167177
168178export const db = new Proxy({}, {
169179 get(_, prop) {
170- _instance ??= drizzle(requireRuntimeBinding("DB"), { schema });
180+ _instance ??= drizzle(requireRuntimeBinding("DB")${ drizzleConfig } );
171181 return Reflect.get(_instance, prop);
172182 },
173183});
174184
175185export function createDb(d1) {
176- return drizzle(d1, { schema });
186+ return drizzle(d1${ drizzleConfig } );
177187}
178188` ;
179189 } ,
@@ -221,36 +231,57 @@ export function createDb(d1) {
221231 */
222232function generateDbDts (
223233 outDir : string ,
224- _schema : SchemaLocation ,
234+ schema : SchemaLocation | null ,
225235 dialect : "sqlite" | "postgresql" ,
226236) : void {
227237 mkdirSync ( outDir , { recursive : true } ) ;
228238
229239 const lines =
230240 dialect === "postgresql"
231- ? [
232- "// Auto-generated by void — do not edit" ,
233- `import type { NodePgDatabase } from "void/_db-pg";` ,
234- `import type * as schema from "@schema";` ,
235- "type Schema = typeof schema;" ,
236- "export declare const db: NodePgDatabase<Schema>;" ,
237- "export declare function createDb(connectionString: string): NodePgDatabase<Schema>;" ,
238- `export { ${ DRIZZLE_OPERATORS } } from "void/_db";` ,
239- `export type { NodePgDatabase } from "void/_db-pg";` ,
240- "" ,
241- ]
242- : [
243- "// Auto-generated by void — do not edit" ,
244- '/// <reference types="@cloudflare/workers-types" />' ,
245- `import type { DrizzleD1Database } from "void/_db";` ,
246- `import type * as schema from "@schema";` ,
247- "type Schema = typeof schema;" ,
248- "export declare const db: DrizzleD1Database<Schema>;" ,
249- "export declare function createDb(d1: D1Database): DrizzleD1Database<Schema>;" ,
250- `export { ${ DRIZZLE_OPERATORS } } from "void/_db";` ,
251- `export type { DrizzleD1Database } from "void/_db";` ,
252- "" ,
253- ] ;
241+ ? schema
242+ ? [
243+ "// Auto-generated by void — do not edit" ,
244+ `import type { NodePgDatabase } from "void/_db-pg";` ,
245+ `import type * as schema from "@schema";` ,
246+ "type Schema = typeof schema;" ,
247+ "export declare const db: NodePgDatabase<Schema>;" ,
248+ "export declare function createDb(connectionString: string): NodePgDatabase<Schema>;" ,
249+ `export { ${ DRIZZLE_OPERATORS } } from "void/_db";` ,
250+ `export type { NodePgDatabase } from "void/_db-pg";` ,
251+ "" ,
252+ ]
253+ : [
254+ "// Auto-generated by void — do not edit" ,
255+ `import type { NodePgDatabase } from "void/_db-pg";` ,
256+ "export declare const db: NodePgDatabase<Record<string, never>>;" ,
257+ "export declare function createDb(connectionString: string): NodePgDatabase<Record<string, never>>;" ,
258+ `export { ${ DRIZZLE_OPERATORS } } from "void/_db";` ,
259+ `export type { NodePgDatabase } from "void/_db-pg";` ,
260+ "" ,
261+ ]
262+ : schema
263+ ? [
264+ "// Auto-generated by void — do not edit" ,
265+ '/// <reference types="@cloudflare/workers-types" />' ,
266+ `import type { DrizzleD1Database } from "void/_db";` ,
267+ `import type * as schema from "@schema";` ,
268+ "type Schema = typeof schema;" ,
269+ "export declare const db: DrizzleD1Database<Schema>;" ,
270+ "export declare function createDb(d1: D1Database): DrizzleD1Database<Schema>;" ,
271+ `export { ${ DRIZZLE_OPERATORS } } from "void/_db";` ,
272+ `export type { DrizzleD1Database } from "void/_db";` ,
273+ "" ,
274+ ]
275+ : [
276+ "// Auto-generated by void — do not edit" ,
277+ '/// <reference types="@cloudflare/workers-types" />' ,
278+ `import type { DrizzleD1Database } from "void/_db";` ,
279+ "export declare const db: DrizzleD1Database<Record<string, never>>;" ,
280+ "export declare function createDb(d1: D1Database): DrizzleD1Database<Record<string, never>>;" ,
281+ `export { ${ DRIZZLE_OPERATORS } } from "void/_db";` ,
282+ `export type { DrizzleD1Database } from "void/_db";` ,
283+ "" ,
284+ ] ;
254285
255286 writeFileSync ( join ( outDir , "db.d.ts" ) , lines . join ( "\n" ) ) ;
256287}
0 commit comments