@vibeorm/adapter-bun 1.0.2 → 1.1.1

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.ts +43 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeorm/adapter-bun",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "Bun-native database adapter for VibeORM using bun:sql",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -33,7 +33,7 @@
33
33
  "bun": ">=1.1.0"
34
34
  },
35
35
  "dependencies": {
36
- "@vibeorm/runtime": "1.0.2"
36
+ "@vibeorm/runtime": "1.1.1"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
package/src/index.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * tagged templates.
7
7
  */
8
8
 
9
- import type { DatabaseAdapter, QueryResult } from "@vibeorm/runtime";
9
+ import type { DatabaseAdapter, QueryResult, TransactionOptions } from "@vibeorm/runtime";
10
10
 
11
11
  export type BunAdapterOptions = {
12
12
  /** PostgreSQL connection URL. Falls back to DATABASE_URL env var if not provided. */
@@ -73,6 +73,7 @@ export type BunAdapterOptions = {
73
73
 
74
74
  type SqlReserved = {
75
75
  (strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;
76
+ unsafe(query: string, values?: unknown[]): Promise<unknown[]>;
76
77
  release(): void;
77
78
  };
78
79
 
@@ -228,6 +229,14 @@ export function bunAdapter(options?: BunAdapterOptions): DatabaseAdapter {
228
229
  return result as Record<string, unknown>[];
229
230
  }
230
231
 
232
+ function isolationLevelToSql(params: { level: NonNullable<TransactionOptions["isolationLevel"]> }): string {
233
+ switch (params.level) {
234
+ case "ReadCommitted": return "READ COMMITTED";
235
+ case "RepeatableRead": return "REPEATABLE READ";
236
+ case "Serializable": return "SERIALIZABLE";
237
+ }
238
+ }
239
+
231
240
  function createAdapter(sql: SqlInstance): DatabaseAdapter {
232
241
  return {
233
242
  async execute(params) {
@@ -251,11 +260,37 @@ export function bunAdapter(options?: BunAdapterOptions): DatabaseAdapter {
251
260
  };
252
261
  },
253
262
 
254
- async transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T>): Promise<T> {
255
- return sql.begin(async (txSql: SqlInstance) => {
256
- const txAdapter = createAdapter(txSql);
257
- return fn(txAdapter);
258
- });
263
+ async transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T>, options?: TransactionOptions): Promise<T> {
264
+ // Fast path: no custom options — use native sql.begin() for best performance
265
+ if (!options?.isolationLevel && !options?.timeout) {
266
+ return sql.begin(async (txSql: SqlInstance) => {
267
+ const txAdapter = createAdapter(txSql);
268
+ return fn(txAdapter);
269
+ });
270
+ }
271
+
272
+ // Manual path: reserve a connection for custom BEGIN options
273
+ const reserved = await sql.reserve();
274
+ try {
275
+ const isolation = options?.isolationLevel
276
+ ? ` ISOLATION LEVEL ${isolationLevelToSql({ level: options.isolationLevel })}`
277
+ : "";
278
+ await reserved.unsafe(`BEGIN${isolation}`);
279
+
280
+ if (options?.timeout) {
281
+ await reserved.unsafe(`SET LOCAL statement_timeout = ${Number(options.timeout)}`);
282
+ }
283
+
284
+ const txAdapter = createAdapter(reserved as unknown as SqlInstance);
285
+ const result = await fn(txAdapter);
286
+ await reserved.unsafe("COMMIT");
287
+ return result;
288
+ } catch (err) {
289
+ try { await reserved.unsafe("ROLLBACK"); } catch { /* rollback best-effort */ }
290
+ throw err;
291
+ } finally {
292
+ reserved.release();
293
+ }
259
294
  },
260
295
 
261
296
  async connect() {
@@ -284,8 +319,8 @@ export function bunAdapter(options?: BunAdapterOptions): DatabaseAdapter {
284
319
  return createAdapter(getSql()).executeUnsafe(params);
285
320
  },
286
321
 
287
- async transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T>): Promise<T> {
288
- return createAdapter(getSql()).transaction(fn);
322
+ async transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T>, options?: TransactionOptions): Promise<T> {
323
+ return createAdapter(getSql()).transaction(fn, options);
289
324
  },
290
325
 
291
326
  async connect() {