@agentuity/drizzle 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/postgres.d.ts +22 -1
- package/dist/postgres.d.ts.map +1 -1
- package/dist/postgres.js +210 -2
- package/dist/postgres.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +9 -1
- package/src/postgres.ts +285 -3
package/dist/index.d.ts
CHANGED
|
@@ -30,10 +30,11 @@
|
|
|
30
30
|
*
|
|
31
31
|
* @packageDocumentation
|
|
32
32
|
*/
|
|
33
|
-
export { createPostgresDrizzle } from './postgres';
|
|
33
|
+
export { createPostgresDrizzle, drizzle } from './postgres';
|
|
34
34
|
export type { PostgresDrizzleConfig, PostgresDrizzle } from './types';
|
|
35
35
|
export { postgres, PostgresClient, type CallablePostgresClient, type PostgresConfig, type ReconnectConfig, type ConnectionStats, type TLSConfig, type TransactionOptions, type ReserveOptions, } from '@agentuity/postgres';
|
|
36
36
|
export { sql, eq, and, or, not, desc, asc, gt, gte, lt, lte, ne, isNull, isNotNull, inArray, notInArray, between, like, ilike, relations, } from 'drizzle-orm';
|
|
37
|
+
export { BunSQLDatabase, BunSQLPreparedQuery, BunSQLSession, BunSQLTransaction, } from 'drizzle-orm/bun-sql';
|
|
37
38
|
export { pgTable, pgSchema, pgEnum, pgView, bigint, bigserial, boolean, vector, char, cidr, customType, date, doublePrecision, inet, integer, interval, json, jsonb, macaddr, macaddr8, numeric, real, serial, smallint, smallserial, text, time, timestamp, uuid, varchar, primaryKey, foreignKey, unique, uniqueIndex, index, check, } from 'drizzle-orm/pg-core';
|
|
38
39
|
export { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
|
39
40
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5D,YAAY,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGtE,OAAO,EACN,QAAQ,EACR,cAAc,EACd,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACnB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACN,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,IAAI,EACJ,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,MAAM,EACN,SAAS,EACT,OAAO,EACP,UAAU,EACV,OAAO,EACP,IAAI,EACJ,KAAK,EACL,SAAS,GACT,MAAM,aAAa,CAAC;AAGrB,OAAO,EACN,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACN,OAAO,EACP,QAAQ,EACR,MAAM,EACN,MAAM,EAEN,MAAM,EACN,SAAS,EACT,OAAO,EACP,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,IAAI,EACJ,eAAe,EACf,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,OAAO,EACP,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,OAAO,EAEP,UAAU,EACV,UAAU,EACV,MAAM,EACN,WAAW,EACX,KAAK,EACL,KAAK,GACL,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -31,11 +31,13 @@
|
|
|
31
31
|
* @packageDocumentation
|
|
32
32
|
*/
|
|
33
33
|
// Main factory function
|
|
34
|
-
export { createPostgresDrizzle } from './postgres';
|
|
34
|
+
export { createPostgresDrizzle, drizzle } from './postgres';
|
|
35
35
|
// Re-export from @agentuity/postgres for convenience
|
|
36
36
|
export { postgres, PostgresClient, } from '@agentuity/postgres';
|
|
37
37
|
// Re-export common Drizzle utilities for convenience
|
|
38
38
|
export { sql, eq, and, or, not, desc, asc, gt, gte, lt, lte, ne, isNull, isNotNull, inArray, notInArray, between, like, ilike, relations, } from 'drizzle-orm';
|
|
39
|
+
// Re-export Bun SQL driver types for compatibility
|
|
40
|
+
export { BunSQLDatabase, BunSQLPreparedQuery, BunSQLSession, BunSQLTransaction, } from 'drizzle-orm/bun-sql';
|
|
39
41
|
// Re-export pg-core table and column definitions
|
|
40
42
|
export { pgTable, pgSchema, pgEnum, pgView,
|
|
41
43
|
// Column types
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,wBAAwB;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,wBAAwB;AACxB,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAK5D,qDAAqD;AACrD,OAAO,EACN,QAAQ,EACR,cAAc,GAQd,MAAM,qBAAqB,CAAC;AAE7B,qDAAqD;AACrD,OAAO,EACN,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,IAAI,EACJ,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,MAAM,EACN,SAAS,EACT,OAAO,EACP,UAAU,EACV,OAAO,EACP,IAAI,EACJ,KAAK,EACL,SAAS,GACT,MAAM,aAAa,CAAC;AAErB,mDAAmD;AACnD,OAAO,EACN,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,iBAAiB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,iDAAiD;AACjD,OAAO,EACN,OAAO,EACP,QAAQ,EACR,MAAM,EACN,MAAM;AACN,eAAe;AACf,MAAM,EACN,SAAS,EACT,OAAO,EACP,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,UAAU,EACV,IAAI,EACJ,eAAe,EACf,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,OAAO,EACP,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,OAAO;AACP,0BAA0B;AAC1B,UAAU,EACV,UAAU,EACV,MAAM,EACN,WAAW,EACX,KAAK,EACL,KAAK,GACL,MAAM,qBAAqB,CAAC;AAE7B,qEAAqE;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/postgres.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { SQL as BunSQL } from 'bun';
|
|
1
|
+
import { SQL as BunSQL, type SQL as BunSQLClient, type SQLOptions } from 'bun';
|
|
2
|
+
import { type BunSQLDatabase } from 'drizzle-orm/bun-sql';
|
|
3
|
+
import type { DrizzleConfig } from 'drizzle-orm';
|
|
2
4
|
import { type CallablePostgresClient, type PostgresConfig } from '@agentuity/postgres';
|
|
3
5
|
import type { PostgresDrizzleConfig, PostgresDrizzle } from './types';
|
|
4
6
|
/**
|
|
@@ -20,6 +22,24 @@ export declare function resolvePostgresClientConfig<TSchema extends Record<strin
|
|
|
20
22
|
* @internal Exported for testing — not part of the public package API.
|
|
21
23
|
*/
|
|
22
24
|
export declare function createResilientSQLProxy(client: CallablePostgresClient): InstanceType<typeof BunSQL>;
|
|
25
|
+
type DrizzleConnectionConfig = string | ({
|
|
26
|
+
url?: string;
|
|
27
|
+
} & SQLOptions);
|
|
28
|
+
declare function _drizzle<TSchema extends Record<string, unknown> = Record<string, never>, TClient extends BunSQLClient = BunSQLClient>(...params: [TClient | string] | [TClient | string, DrizzleConfig<TSchema>] | [DrizzleConfig<TSchema> & ({
|
|
29
|
+
connection: DrizzleConnectionConfig;
|
|
30
|
+
} | {
|
|
31
|
+
client: TClient;
|
|
32
|
+
})]): BunSQLDatabase<TSchema> & {
|
|
33
|
+
$client: TClient;
|
|
34
|
+
};
|
|
35
|
+
declare namespace _drizzle {
|
|
36
|
+
var mock: <TSchema extends Record<string, unknown> = Record<string, never>>(config?: DrizzleConfig<TSchema>) => BunSQLDatabase<TSchema> & {
|
|
37
|
+
$client: "$client is not available on drizzle.mock()";
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare const drizzle: typeof _drizzle & {
|
|
41
|
+
mock: typeof _drizzle.mock;
|
|
42
|
+
};
|
|
23
43
|
/**
|
|
24
44
|
* Creates a Drizzle ORM instance with a resilient PostgreSQL connection.
|
|
25
45
|
*
|
|
@@ -65,4 +85,5 @@ export declare function createResilientSQLProxy(client: CallablePostgresClient):
|
|
|
65
85
|
* ```
|
|
66
86
|
*/
|
|
67
87
|
export declare function createPostgresDrizzle<TSchema extends Record<string, unknown> = Record<string, never>>(config?: PostgresDrizzleConfig<TSchema>): PostgresDrizzle<TSchema>;
|
|
88
|
+
export {};
|
|
68
89
|
//# sourceMappingURL=postgres.d.ts.map
|
package/dist/postgres.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,MAAM,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,MAAM,EAAE,KAAK,GAAG,IAAI,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAC/E,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAY,KAAK,sBAAsB,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACjG,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEtE;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAC1C,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC9D,MAAM,CAAC,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,cAAc,CA0BzD;AA8FD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,sBAAsB,GAC5B,YAAY,CAAC,OAAO,MAAM,CAAC,CA4D7B;AAED,KAAK,uBAAuB,GAAG,MAAM,GAAG,CAAC;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAAC,CAAC;AAoHxE,iBAAS,QAAQ,CAChB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC/D,OAAO,SAAS,YAAY,GAAG,YAAY,EAE3C,GAAG,MAAM,EACN,CAAC,OAAO,GAAG,MAAM,CAAC,GAClB,CAAC,OAAO,GAAG,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,GAC1C,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC;IAAE,UAAU,EAAE,uBAAuB,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC,GAC3F,cAAc,CAAC,OAAO,CAAC,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAwBhD;kBAhCQ,QAAQ;eAkCA,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,mCAC9C,aAAa,CAAC,OAAO,CAAC,KAC7B,cAAc,CAAC,OAAO,CAAC,GAAG;QAAE,OAAO,EAAE,4CAA4C,CAAA;KAAE;;AAStF,eAAO,MAAM,OAAO,EAAe,OAAO,QAAQ,GAAG;IACpD,IAAI,EAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC9D,MAAM,CAAC,EAAE,qBAAqB,CAAC,OAAO,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC,CAoCnE"}
|
package/dist/postgres.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { drizzle } from 'drizzle-orm/bun-sql';
|
|
1
|
+
import { drizzle as upstreamDrizzle } from 'drizzle-orm/bun-sql';
|
|
2
|
+
import { isConfig } from 'drizzle-orm/utils';
|
|
2
3
|
import { postgres } from '@agentuity/postgres';
|
|
3
4
|
/**
|
|
4
5
|
* Resolves the PostgreSQL client configuration from Drizzle config options.
|
|
@@ -32,6 +33,85 @@ export function resolvePostgresClientConfig(config) {
|
|
|
32
33
|
}
|
|
33
34
|
return clientConfig;
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Strips leading whitespace and SQL comments (block and line) from a query string.
|
|
38
|
+
* Returns the remaining query text starting at the first non-comment token.
|
|
39
|
+
*/
|
|
40
|
+
const LEADING_COMMENTS_RE = /^(?:\s+|\/\*[\s\S]*?\*\/|--[^\n]*\n)*/;
|
|
41
|
+
/**
|
|
42
|
+
* Determines whether a SQL query is a non-retryable INSERT statement.
|
|
43
|
+
*
|
|
44
|
+
* Handles two patterns:
|
|
45
|
+
* 1. Direct INSERT: `INSERT INTO ...` (with optional leading comments/whitespace)
|
|
46
|
+
* 2. CTE INSERT: `WITH cte AS (...) INSERT INTO ...` — scans past the WITH clause
|
|
47
|
+
* by tracking parenthesis depth to skip CTE subexpressions, then checks
|
|
48
|
+
* if the first top-level DML keyword is INSERT.
|
|
49
|
+
*
|
|
50
|
+
* @see https://github.com/agentuity/sdk/issues/911
|
|
51
|
+
*/
|
|
52
|
+
function isNonRetryableInsert(query) {
|
|
53
|
+
// Strip leading whitespace and SQL comments
|
|
54
|
+
const stripped = query.replace(LEADING_COMMENTS_RE, '');
|
|
55
|
+
// Fast path: direct INSERT statement
|
|
56
|
+
if (/^INSERT\s/i.test(stripped)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
// Check for WITH (CTE) prefix
|
|
60
|
+
if (!/^WITH\s/i.test(stripped)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
// Scan past the CTE clause to find the first top-level DML keyword.
|
|
64
|
+
// We track parenthesis depth so we skip CTE subexpressions like
|
|
65
|
+
// "WITH cte AS (SELECT ... INSERT ...)" without false-matching the
|
|
66
|
+
// INSERT inside the parens.
|
|
67
|
+
let depth = 0;
|
|
68
|
+
let i = 4; // skip past "WITH"
|
|
69
|
+
const len = stripped.length;
|
|
70
|
+
while (i < len) {
|
|
71
|
+
const ch = stripped[i];
|
|
72
|
+
if (ch === '(') {
|
|
73
|
+
depth++;
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (ch === ')') {
|
|
78
|
+
depth--;
|
|
79
|
+
i++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
// Only inspect keywords at top level (depth === 0)
|
|
83
|
+
if (depth === 0) {
|
|
84
|
+
// Skip whitespace at top level
|
|
85
|
+
if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r') {
|
|
86
|
+
i++;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
// Skip commas between CTEs: WITH a AS (...), b AS (...)
|
|
90
|
+
if (ch === ',') {
|
|
91
|
+
i++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Check for DML keywords at this position.
|
|
95
|
+
// We look for INSERT, UPDATE, DELETE, or SELECT — the first one
|
|
96
|
+
// we find at top level determines whether this is retryable.
|
|
97
|
+
const rest = stripped.substring(i);
|
|
98
|
+
const dmlMatch = /^(INSERT|UPDATE|DELETE|SELECT)\s/i.exec(rest);
|
|
99
|
+
if (dmlMatch) {
|
|
100
|
+
return dmlMatch[1].toUpperCase() === 'INSERT';
|
|
101
|
+
}
|
|
102
|
+
// Skip over any other word (e.g., CTE names, AS keyword, RECURSIVE)
|
|
103
|
+
// by advancing past alphanumeric/underscore characters
|
|
104
|
+
if (/\w/.test(ch)) {
|
|
105
|
+
while (i < len && /\w/.test(stripped[i])) {
|
|
106
|
+
i++;
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
35
115
|
/**
|
|
36
116
|
* Creates a dynamic SQL proxy that always delegates to the PostgresClient's
|
|
37
117
|
* current raw connection. This ensures that after automatic reconnection,
|
|
@@ -47,6 +127,9 @@ export function createResilientSQLProxy(client) {
|
|
|
47
127
|
get(_target, prop, _receiver) {
|
|
48
128
|
// Always resolve from the CURRENT raw connection (changes after reconnect)
|
|
49
129
|
const raw = client.raw;
|
|
130
|
+
if (prop === 'close') {
|
|
131
|
+
return () => client.close();
|
|
132
|
+
}
|
|
50
133
|
if (prop === 'unsafe') {
|
|
51
134
|
// Wrap unsafe() with retry logic for resilient queries.
|
|
52
135
|
// Returns a thenable that also supports .values() chaining,
|
|
@@ -54,6 +137,23 @@ export function createResilientSQLProxy(client) {
|
|
|
54
137
|
// client.unsafe(query, params) → Promise<rows>
|
|
55
138
|
// client.unsafe(query, params).values() → Promise<rows>
|
|
56
139
|
return (query, params) => {
|
|
140
|
+
// INSERT statements (including CTE-based) are NOT retried to prevent
|
|
141
|
+
// duplicate rows. If an INSERT succeeds on the server but the connection
|
|
142
|
+
// drops before the response, retrying would re-execute it — creating a
|
|
143
|
+
// duplicate row when the primary key is server-generated.
|
|
144
|
+
// See: https://github.com/agentuity/sdk/issues/911
|
|
145
|
+
const isInsert = isNonRetryableInsert(query);
|
|
146
|
+
if (isInsert) {
|
|
147
|
+
const makeDirectExecutor = (useValues) => {
|
|
148
|
+
const currentRaw = client.raw;
|
|
149
|
+
const q = currentRaw.unsafe(query, params);
|
|
150
|
+
return useValues ? q.values() : q;
|
|
151
|
+
};
|
|
152
|
+
const result = makeDirectExecutor(false);
|
|
153
|
+
return Object.assign(result, {
|
|
154
|
+
values: () => makeDirectExecutor(true),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
57
157
|
const makeExecutor = (useValues) => client.executeWithRetry(async () => {
|
|
58
158
|
// Re-resolve raw inside retry to get post-reconnect instance
|
|
59
159
|
const currentRaw = client.raw;
|
|
@@ -76,6 +176,114 @@ export function createResilientSQLProxy(client) {
|
|
|
76
176
|
},
|
|
77
177
|
});
|
|
78
178
|
}
|
|
179
|
+
function isCallablePostgresClient(value) {
|
|
180
|
+
return (typeof value === 'function' &&
|
|
181
|
+
value !== null &&
|
|
182
|
+
'raw' in value &&
|
|
183
|
+
typeof value.executeWithRetry === 'function');
|
|
184
|
+
}
|
|
185
|
+
function createProxyClientFromSql(client) {
|
|
186
|
+
// Bun SQL instances are callable as tagged template literals.
|
|
187
|
+
// Create a function that forwards calls to the client.
|
|
188
|
+
const proxy = (async (strings, ...values) => {
|
|
189
|
+
// Forward tagged template to the Bun SQL client directly
|
|
190
|
+
return client(strings, ...values);
|
|
191
|
+
});
|
|
192
|
+
Object.defineProperties(proxy, {
|
|
193
|
+
raw: {
|
|
194
|
+
get: () => client,
|
|
195
|
+
enumerable: true,
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
proxy.executeWithRetry = async (operation) => operation();
|
|
199
|
+
proxy.close = async () => {
|
|
200
|
+
const close = client.close;
|
|
201
|
+
if (typeof close === 'function') {
|
|
202
|
+
await close.call(client);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
return proxy;
|
|
206
|
+
}
|
|
207
|
+
function extractPostgresConfigFromSql(client) {
|
|
208
|
+
const options = client.options;
|
|
209
|
+
if (!options || typeof options !== 'object') {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
const config = {};
|
|
213
|
+
const keys = [
|
|
214
|
+
'url',
|
|
215
|
+
'hostname',
|
|
216
|
+
'port',
|
|
217
|
+
'username',
|
|
218
|
+
'password',
|
|
219
|
+
'database',
|
|
220
|
+
'tls',
|
|
221
|
+
'max',
|
|
222
|
+
'idleTimeout',
|
|
223
|
+
'connectionTimeout',
|
|
224
|
+
];
|
|
225
|
+
for (const key of keys) {
|
|
226
|
+
if (key in options) {
|
|
227
|
+
config[key] = options[key];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return Object.keys(config).length > 0 ? config : undefined;
|
|
231
|
+
}
|
|
232
|
+
function resolvePostgresClient(client) {
|
|
233
|
+
if (isCallablePostgresClient(client)) {
|
|
234
|
+
return client;
|
|
235
|
+
}
|
|
236
|
+
const config = extractPostgresConfigFromSql(client);
|
|
237
|
+
if (config) {
|
|
238
|
+
return postgres(config);
|
|
239
|
+
}
|
|
240
|
+
return createProxyClientFromSql(client);
|
|
241
|
+
}
|
|
242
|
+
function resolvePostgresClientFromConnection(connection) {
|
|
243
|
+
if (!connection) {
|
|
244
|
+
return postgres();
|
|
245
|
+
}
|
|
246
|
+
if (typeof connection === 'string') {
|
|
247
|
+
return postgres(connection);
|
|
248
|
+
}
|
|
249
|
+
if (typeof connection === 'object' && connection.url !== undefined) {
|
|
250
|
+
const { url, ...config } = connection;
|
|
251
|
+
return postgres({ url, ...config });
|
|
252
|
+
}
|
|
253
|
+
return postgres(connection);
|
|
254
|
+
}
|
|
255
|
+
function createDrizzleDatabase(client, config) {
|
|
256
|
+
const resilientSQL = createResilientSQLProxy(client);
|
|
257
|
+
return upstreamDrizzle({
|
|
258
|
+
client: resilientSQL,
|
|
259
|
+
...(config ?? {}),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function _drizzle(...params) {
|
|
263
|
+
if (typeof params[0] === 'string') {
|
|
264
|
+
const client = resolvePostgresClientFromConnection(params[0]);
|
|
265
|
+
return createDrizzleDatabase(client, params[1]);
|
|
266
|
+
}
|
|
267
|
+
if (isConfig(params[0])) {
|
|
268
|
+
const config = params[0];
|
|
269
|
+
const { connection, client, ...drizzleConfig } = config;
|
|
270
|
+
if (client) {
|
|
271
|
+
const resolvedClient = resolvePostgresClient(client);
|
|
272
|
+
return createDrizzleDatabase(resolvedClient, drizzleConfig);
|
|
273
|
+
}
|
|
274
|
+
const resolvedClient = resolvePostgresClientFromConnection(connection);
|
|
275
|
+
return createDrizzleDatabase(resolvedClient, drizzleConfig);
|
|
276
|
+
}
|
|
277
|
+
const client = resolvePostgresClient(params[0]);
|
|
278
|
+
return createDrizzleDatabase(client, params[1]);
|
|
279
|
+
}
|
|
280
|
+
_drizzle.mock = (config) => {
|
|
281
|
+
const db = upstreamDrizzle.mock(config);
|
|
282
|
+
db.$client =
|
|
283
|
+
'$client is not available on drizzle.mock()';
|
|
284
|
+
return db;
|
|
285
|
+
};
|
|
286
|
+
export const drizzle = _drizzle;
|
|
79
287
|
/**
|
|
80
288
|
* Creates a Drizzle ORM instance with a resilient PostgreSQL connection.
|
|
81
289
|
*
|
|
@@ -138,7 +346,7 @@ export function createPostgresDrizzle(config) {
|
|
|
138
346
|
const resilientSQL = createResilientSQLProxy(client);
|
|
139
347
|
// Create Drizzle instance using the resilient proxy instead of a static
|
|
140
348
|
// reference to client.raw, which would become stale after reconnection.
|
|
141
|
-
const db =
|
|
349
|
+
const db = upstreamDrizzle({
|
|
142
350
|
client: resilientSQL,
|
|
143
351
|
schema: config?.schema,
|
|
144
352
|
logger: config?.logger,
|
package/dist/postgres.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../src/postgres.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentuity/drizzle",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Agentuity employees and contributors",
|
|
6
6
|
"type": "module",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"prepublishOnly": "bun run clean && bun run build"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@agentuity/postgres": "1.0.
|
|
44
|
+
"@agentuity/postgres": "1.0.8",
|
|
45
45
|
"drizzle-orm": "^0.45.0",
|
|
46
46
|
"better-auth": "^1.4.9"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@agentuity/test-utils": "1.0.
|
|
49
|
+
"@agentuity/test-utils": "1.0.8",
|
|
50
50
|
"@types/bun": "latest",
|
|
51
51
|
"bun-types": "latest",
|
|
52
52
|
"typescript": "^5.9.0"
|
package/src/index.ts
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
34
|
// Main factory function
|
|
35
|
-
export { createPostgresDrizzle } from './postgres';
|
|
35
|
+
export { createPostgresDrizzle, drizzle } from './postgres';
|
|
36
36
|
|
|
37
37
|
// Types
|
|
38
38
|
export type { PostgresDrizzleConfig, PostgresDrizzle } from './types';
|
|
@@ -74,6 +74,14 @@ export {
|
|
|
74
74
|
relations,
|
|
75
75
|
} from 'drizzle-orm';
|
|
76
76
|
|
|
77
|
+
// Re-export Bun SQL driver types for compatibility
|
|
78
|
+
export {
|
|
79
|
+
BunSQLDatabase,
|
|
80
|
+
BunSQLPreparedQuery,
|
|
81
|
+
BunSQLSession,
|
|
82
|
+
BunSQLTransaction,
|
|
83
|
+
} from 'drizzle-orm/bun-sql';
|
|
84
|
+
|
|
77
85
|
// Re-export pg-core table and column definitions
|
|
78
86
|
export {
|
|
79
87
|
pgTable,
|
package/src/postgres.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { SQL as BunSQL } from 'bun';
|
|
2
|
-
import { drizzle } from 'drizzle-orm/bun-sql';
|
|
1
|
+
import { SQL as BunSQL, type SQL as BunSQLClient, type SQLOptions } from 'bun';
|
|
2
|
+
import { drizzle as upstreamDrizzle, type BunSQLDatabase } from 'drizzle-orm/bun-sql';
|
|
3
|
+
import type { DrizzleConfig } from 'drizzle-orm';
|
|
4
|
+
import { isConfig } from 'drizzle-orm/utils';
|
|
3
5
|
import { postgres, type CallablePostgresClient, type PostgresConfig } from '@agentuity/postgres';
|
|
4
6
|
import type { PostgresDrizzleConfig, PostgresDrizzle } from './types';
|
|
5
7
|
|
|
@@ -40,6 +42,98 @@ export function resolvePostgresClientConfig<
|
|
|
40
42
|
return clientConfig;
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Strips leading whitespace and SQL comments (block and line) from a query string.
|
|
47
|
+
* Returns the remaining query text starting at the first non-comment token.
|
|
48
|
+
*/
|
|
49
|
+
const LEADING_COMMENTS_RE = /^(?:\s+|\/\*[\s\S]*?\*\/|--[^\n]*\n)*/;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Determines whether a SQL query is a non-retryable INSERT statement.
|
|
53
|
+
*
|
|
54
|
+
* Handles two patterns:
|
|
55
|
+
* 1. Direct INSERT: `INSERT INTO ...` (with optional leading comments/whitespace)
|
|
56
|
+
* 2. CTE INSERT: `WITH cte AS (...) INSERT INTO ...` — scans past the WITH clause
|
|
57
|
+
* by tracking parenthesis depth to skip CTE subexpressions, then checks
|
|
58
|
+
* if the first top-level DML keyword is INSERT.
|
|
59
|
+
*
|
|
60
|
+
* @see https://github.com/agentuity/sdk/issues/911
|
|
61
|
+
*/
|
|
62
|
+
function isNonRetryableInsert(query: string): boolean {
|
|
63
|
+
// Strip leading whitespace and SQL comments
|
|
64
|
+
const stripped = query.replace(LEADING_COMMENTS_RE, '');
|
|
65
|
+
|
|
66
|
+
// Fast path: direct INSERT statement
|
|
67
|
+
if (/^INSERT\s/i.test(stripped)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check for WITH (CTE) prefix
|
|
72
|
+
if (!/^WITH\s/i.test(stripped)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Scan past the CTE clause to find the first top-level DML keyword.
|
|
77
|
+
// We track parenthesis depth so we skip CTE subexpressions like
|
|
78
|
+
// "WITH cte AS (SELECT ... INSERT ...)" without false-matching the
|
|
79
|
+
// INSERT inside the parens.
|
|
80
|
+
let depth = 0;
|
|
81
|
+
let i = 4; // skip past "WITH"
|
|
82
|
+
const len = stripped.length;
|
|
83
|
+
|
|
84
|
+
while (i < len) {
|
|
85
|
+
const ch = stripped[i]!;
|
|
86
|
+
|
|
87
|
+
if (ch === '(') {
|
|
88
|
+
depth++;
|
|
89
|
+
i++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (ch === ')') {
|
|
93
|
+
depth--;
|
|
94
|
+
i++;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Only inspect keywords at top level (depth === 0)
|
|
99
|
+
if (depth === 0) {
|
|
100
|
+
// Skip whitespace at top level
|
|
101
|
+
if (ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r') {
|
|
102
|
+
i++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Skip commas between CTEs: WITH a AS (...), b AS (...)
|
|
107
|
+
if (ch === ',') {
|
|
108
|
+
i++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check for DML keywords at this position.
|
|
113
|
+
// We look for INSERT, UPDATE, DELETE, or SELECT — the first one
|
|
114
|
+
// we find at top level determines whether this is retryable.
|
|
115
|
+
const rest = stripped.substring(i);
|
|
116
|
+
const dmlMatch = /^(INSERT|UPDATE|DELETE|SELECT)\s/i.exec(rest);
|
|
117
|
+
if (dmlMatch) {
|
|
118
|
+
return dmlMatch[1]!.toUpperCase() === 'INSERT';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Skip over any other word (e.g., CTE names, AS keyword, RECURSIVE)
|
|
122
|
+
// by advancing past alphanumeric/underscore characters
|
|
123
|
+
if (/\w/.test(ch)) {
|
|
124
|
+
while (i < len && /\w/.test(stripped[i]!)) {
|
|
125
|
+
i++;
|
|
126
|
+
}
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
43
137
|
/**
|
|
44
138
|
* Creates a dynamic SQL proxy that always delegates to the PostgresClient's
|
|
45
139
|
* current raw connection. This ensures that after automatic reconnection,
|
|
@@ -58,6 +152,10 @@ export function createResilientSQLProxy(
|
|
|
58
152
|
// Always resolve from the CURRENT raw connection (changes after reconnect)
|
|
59
153
|
const raw = client.raw;
|
|
60
154
|
|
|
155
|
+
if (prop === 'close') {
|
|
156
|
+
return () => client.close();
|
|
157
|
+
}
|
|
158
|
+
|
|
61
159
|
if (prop === 'unsafe') {
|
|
62
160
|
// Wrap unsafe() with retry logic for resilient queries.
|
|
63
161
|
// Returns a thenable that also supports .values() chaining,
|
|
@@ -65,6 +163,25 @@ export function createResilientSQLProxy(
|
|
|
65
163
|
// client.unsafe(query, params) → Promise<rows>
|
|
66
164
|
// client.unsafe(query, params).values() → Promise<rows>
|
|
67
165
|
return (query: string, params?: unknown[]) => {
|
|
166
|
+
// INSERT statements (including CTE-based) are NOT retried to prevent
|
|
167
|
+
// duplicate rows. If an INSERT succeeds on the server but the connection
|
|
168
|
+
// drops before the response, retrying would re-execute it — creating a
|
|
169
|
+
// duplicate row when the primary key is server-generated.
|
|
170
|
+
// See: https://github.com/agentuity/sdk/issues/911
|
|
171
|
+
const isInsert = isNonRetryableInsert(query);
|
|
172
|
+
|
|
173
|
+
if (isInsert) {
|
|
174
|
+
const makeDirectExecutor = (useValues: boolean) => {
|
|
175
|
+
const currentRaw = client.raw;
|
|
176
|
+
const q = currentRaw.unsafe(query, params);
|
|
177
|
+
return useValues ? q.values() : q;
|
|
178
|
+
};
|
|
179
|
+
const result = makeDirectExecutor(false);
|
|
180
|
+
return Object.assign(result, {
|
|
181
|
+
values: () => makeDirectExecutor(true),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
68
185
|
const makeExecutor = (useValues: boolean) =>
|
|
69
186
|
client.executeWithRetry(async () => {
|
|
70
187
|
// Re-resolve raw inside retry to get post-reconnect instance
|
|
@@ -91,6 +208,171 @@ export function createResilientSQLProxy(
|
|
|
91
208
|
});
|
|
92
209
|
}
|
|
93
210
|
|
|
211
|
+
type DrizzleConnectionConfig = string | ({ url?: string } & SQLOptions);
|
|
212
|
+
|
|
213
|
+
function isCallablePostgresClient(value: unknown): value is CallablePostgresClient {
|
|
214
|
+
return (
|
|
215
|
+
typeof value === 'function' &&
|
|
216
|
+
value !== null &&
|
|
217
|
+
'raw' in (value as CallablePostgresClient) &&
|
|
218
|
+
typeof (value as CallablePostgresClient).executeWithRetry === 'function'
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function createProxyClientFromSql(client: BunSQLClient): CallablePostgresClient {
|
|
223
|
+
// Bun SQL instances are callable as tagged template literals.
|
|
224
|
+
// Create a function that forwards calls to the client.
|
|
225
|
+
const proxy = (async (strings: TemplateStringsArray, ...values: unknown[]) => {
|
|
226
|
+
// Forward tagged template to the Bun SQL client directly
|
|
227
|
+
return (client as unknown as CallablePostgresClient)(strings, ...values);
|
|
228
|
+
}) as unknown as CallablePostgresClient;
|
|
229
|
+
|
|
230
|
+
Object.defineProperties(proxy, {
|
|
231
|
+
raw: {
|
|
232
|
+
get: () => client as InstanceType<typeof BunSQL>,
|
|
233
|
+
enumerable: true,
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
proxy.executeWithRetry = async <T>(operation: () => T | Promise<T>) => operation();
|
|
238
|
+
proxy.close = async () => {
|
|
239
|
+
const close = (client as { close?: () => Promise<void> | void }).close;
|
|
240
|
+
if (typeof close === 'function') {
|
|
241
|
+
await close.call(client);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
return proxy;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function extractPostgresConfigFromSql(client: BunSQLClient): PostgresConfig | undefined {
|
|
249
|
+
const options = (client as { options?: Record<string, unknown> }).options;
|
|
250
|
+
if (!options || typeof options !== 'object') {
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const config: PostgresConfig = {};
|
|
255
|
+
const keys = [
|
|
256
|
+
'url',
|
|
257
|
+
'hostname',
|
|
258
|
+
'port',
|
|
259
|
+
'username',
|
|
260
|
+
'password',
|
|
261
|
+
'database',
|
|
262
|
+
'tls',
|
|
263
|
+
'max',
|
|
264
|
+
'idleTimeout',
|
|
265
|
+
'connectionTimeout',
|
|
266
|
+
] as const;
|
|
267
|
+
|
|
268
|
+
for (const key of keys) {
|
|
269
|
+
if (key in options) {
|
|
270
|
+
(config as Record<string, unknown>)[key] = options[key];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return Object.keys(config).length > 0 ? config : undefined;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function resolvePostgresClient<TClient extends BunSQLClient>(
|
|
278
|
+
client: TClient
|
|
279
|
+
): CallablePostgresClient {
|
|
280
|
+
if (isCallablePostgresClient(client)) {
|
|
281
|
+
return client;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const config = extractPostgresConfigFromSql(client);
|
|
285
|
+
if (config) {
|
|
286
|
+
return postgres(config);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return createProxyClientFromSql(client);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function resolvePostgresClientFromConnection(
|
|
293
|
+
connection?: DrizzleConnectionConfig
|
|
294
|
+
): CallablePostgresClient {
|
|
295
|
+
if (!connection) {
|
|
296
|
+
return postgres();
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (typeof connection === 'string') {
|
|
300
|
+
return postgres(connection);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (typeof connection === 'object' && connection.url !== undefined) {
|
|
304
|
+
const { url, ...config } = connection;
|
|
305
|
+
return postgres({ url, ...(config as PostgresConfig) });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return postgres(connection as PostgresConfig);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function createDrizzleDatabase<
|
|
312
|
+
TSchema extends Record<string, unknown> = Record<string, never>,
|
|
313
|
+
TClient extends BunSQLClient = BunSQLClient,
|
|
314
|
+
>(
|
|
315
|
+
client: CallablePostgresClient,
|
|
316
|
+
config?: DrizzleConfig<TSchema>
|
|
317
|
+
): BunSQLDatabase<TSchema> & {
|
|
318
|
+
$client: TClient;
|
|
319
|
+
} {
|
|
320
|
+
const resilientSQL = createResilientSQLProxy(client);
|
|
321
|
+
return upstreamDrizzle({
|
|
322
|
+
client: resilientSQL,
|
|
323
|
+
...(config ?? {}),
|
|
324
|
+
}) as BunSQLDatabase<TSchema> & { $client: TClient };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function _drizzle<
|
|
328
|
+
TSchema extends Record<string, unknown> = Record<string, never>,
|
|
329
|
+
TClient extends BunSQLClient = BunSQLClient,
|
|
330
|
+
>(
|
|
331
|
+
...params:
|
|
332
|
+
| [TClient | string]
|
|
333
|
+
| [TClient | string, DrizzleConfig<TSchema>]
|
|
334
|
+
| [DrizzleConfig<TSchema> & ({ connection: DrizzleConnectionConfig } | { client: TClient })]
|
|
335
|
+
): BunSQLDatabase<TSchema> & { $client: TClient } {
|
|
336
|
+
if (typeof params[0] === 'string') {
|
|
337
|
+
const client = resolvePostgresClientFromConnection(params[0]);
|
|
338
|
+
return createDrizzleDatabase(client, params[1]);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (isConfig(params[0])) {
|
|
342
|
+
const config = params[0] as DrizzleConfig<TSchema> & {
|
|
343
|
+
connection?: DrizzleConnectionConfig;
|
|
344
|
+
client?: TClient;
|
|
345
|
+
};
|
|
346
|
+
const { connection, client, ...drizzleConfig } = config;
|
|
347
|
+
|
|
348
|
+
if (client) {
|
|
349
|
+
const resolvedClient = resolvePostgresClient(client);
|
|
350
|
+
return createDrizzleDatabase(resolvedClient, drizzleConfig);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const resolvedClient = resolvePostgresClientFromConnection(connection);
|
|
354
|
+
return createDrizzleDatabase(resolvedClient, drizzleConfig);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const client = resolvePostgresClient(params[0] as TClient);
|
|
358
|
+
return createDrizzleDatabase(client, params[1]);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
_drizzle.mock = <TSchema extends Record<string, unknown> = Record<string, never>>(
|
|
362
|
+
config?: DrizzleConfig<TSchema>
|
|
363
|
+
): BunSQLDatabase<TSchema> & { $client: '$client is not available on drizzle.mock()' } => {
|
|
364
|
+
const db = upstreamDrizzle.mock(config);
|
|
365
|
+
(db as unknown as Record<string, unknown>).$client =
|
|
366
|
+
'$client is not available on drizzle.mock()';
|
|
367
|
+
return db as BunSQLDatabase<TSchema> & {
|
|
368
|
+
$client: '$client is not available on drizzle.mock()';
|
|
369
|
+
};
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
export const drizzle = _drizzle as typeof _drizzle & {
|
|
373
|
+
mock: typeof _drizzle.mock;
|
|
374
|
+
};
|
|
375
|
+
|
|
94
376
|
/**
|
|
95
377
|
* Creates a Drizzle ORM instance with a resilient PostgreSQL connection.
|
|
96
378
|
*
|
|
@@ -159,7 +441,7 @@ export function createPostgresDrizzle<
|
|
|
159
441
|
|
|
160
442
|
// Create Drizzle instance using the resilient proxy instead of a static
|
|
161
443
|
// reference to client.raw, which would become stale after reconnection.
|
|
162
|
-
const db =
|
|
444
|
+
const db = upstreamDrizzle({
|
|
163
445
|
client: resilientSQL,
|
|
164
446
|
schema: config?.schema,
|
|
165
447
|
logger: config?.logger,
|