@pineliner/odb-client 1.0.7 → 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.cjs CHANGED
@@ -4,6 +4,7 @@ var __webpack_modules__ = {
4
4
  __webpack_require__.r(__webpack_exports__);
5
5
  __webpack_require__.d(__webpack_exports__, {
6
6
  ORM: ()=>ORM,
7
+ Transaction: ()=>Transaction,
7
8
  and: ()=>and,
8
9
  createORM: ()=>createORM,
9
10
  eq: ()=>eq,
@@ -294,10 +295,67 @@ var __webpack_modules__ = {
294
295
  return new DeleteBuilder(this.db, this.tableName);
295
296
  }
296
297
  }
298
+ class Transaction {
299
+ orm;
300
+ isCommitted = false;
301
+ isRolledBack = false;
302
+ db;
303
+ savepointName;
304
+ constructor(db, transactionDepth = 0, savepointName){
305
+ this.db = db;
306
+ this.orm = new ORM(db, transactionDepth);
307
+ this.savepointName = savepointName;
308
+ }
309
+ select(fields) {
310
+ this.checkNotFinalized();
311
+ return this.orm.select(fields);
312
+ }
313
+ insert(tableName) {
314
+ this.checkNotFinalized();
315
+ return this.orm.insert(tableName);
316
+ }
317
+ update(tableName) {
318
+ this.checkNotFinalized();
319
+ return this.orm.update(tableName);
320
+ }
321
+ delete(tableName) {
322
+ this.checkNotFinalized();
323
+ return this.orm.delete(tableName);
324
+ }
325
+ execute(sql, params) {
326
+ this.checkNotFinalized();
327
+ return this.orm.execute(sql, params);
328
+ }
329
+ async transaction(fn) {
330
+ this.checkNotFinalized();
331
+ if (fn) return await this.orm.transaction(fn);
332
+ return await this.orm.transaction();
333
+ }
334
+ async commit() {
335
+ if (this.isCommitted) throw new Error('Transaction already committed');
336
+ if (this.isRolledBack) throw new Error('Transaction already rolled back');
337
+ if (this.savepointName) await this.db.execute(`RELEASE SAVEPOINT ${this.savepointName}`, []);
338
+ else await this.db.execute('COMMIT', []);
339
+ this.isCommitted = true;
340
+ }
341
+ async rollback() {
342
+ if (this.isCommitted) throw new Error('Transaction already committed');
343
+ if (this.isRolledBack) throw new Error('Transaction already rolled back');
344
+ if (this.savepointName) await this.db.execute(`ROLLBACK TO SAVEPOINT ${this.savepointName}`, []);
345
+ else await this.db.execute('ROLLBACK', []);
346
+ this.isRolledBack = true;
347
+ }
348
+ checkNotFinalized() {
349
+ if (this.isCommitted) throw new Error('Cannot perform operations on committed transaction');
350
+ if (this.isRolledBack) throw new Error('Cannot perform operations on rolled back transaction');
351
+ }
352
+ }
297
353
  class ORM {
298
354
  db;
299
- constructor(db){
355
+ transactionDepth = 0;
356
+ constructor(db, transactionDepth = 0){
300
357
  this.db = db;
358
+ this.transactionDepth = transactionDepth;
301
359
  }
302
360
  table(tableName) {
303
361
  return new TableQueryBuilder(this.db, tableName);
@@ -323,6 +381,33 @@ var __webpack_modules__ = {
323
381
  execute(sql, params) {
324
382
  return this.db.execute(sql, params);
325
383
  }
384
+ async transaction(fn) {
385
+ if (!fn) if (this.transactionDepth > 0) {
386
+ const savepointName = `sp_${this.transactionDepth}_${Date.now()}`;
387
+ await this.db.execute(`SAVEPOINT ${savepointName}`, []);
388
+ return new Transaction(this.db, this.transactionDepth + 1, savepointName);
389
+ } else {
390
+ await this.db.execute('BEGIN TRANSACTION', []);
391
+ return new Transaction(this.db, 1);
392
+ }
393
+ if (!(this.transactionDepth > 0)) return await this.db.transaction(async (txConnection)=>{
394
+ const txOrm = new ORM(txConnection, 1);
395
+ return await fn(txOrm);
396
+ });
397
+ {
398
+ const savepointName = `sp_${this.transactionDepth}_${Date.now()}`;
399
+ try {
400
+ await this.db.execute(`SAVEPOINT ${savepointName}`, []);
401
+ const nestedOrm = new ORM(this.db, this.transactionDepth + 1);
402
+ const result = await fn(nestedOrm);
403
+ await this.db.execute(`RELEASE SAVEPOINT ${savepointName}`, []);
404
+ return result;
405
+ } catch (error) {
406
+ await this.db.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`, []);
407
+ throw error;
408
+ }
409
+ }
410
+ }
326
411
  }
327
412
  function createORM(db) {
328
413
  return new ORM(db);
@@ -398,6 +483,7 @@ var __webpack_exports__ = {};
398
483
  splitSQLStatements: ()=>splitSQLStatements,
399
484
  where: ()=>src_where,
400
485
  LibSQLAdapter: ()=>LibSQLAdapter,
486
+ ORMTransaction: ()=>orm.Transaction,
401
487
  lt: ()=>orm.lt,
402
488
  fragment: ()=>fragment,
403
489
  isNull: ()=>orm.isNull,
@@ -1948,6 +2034,7 @@ exports.ODBLiteClient = __webpack_exports__.ODBLiteClient;
1948
2034
  exports.ODBLiteError = __webpack_exports__.ODBLiteError;
1949
2035
  exports.ODBLiteTransaction = __webpack_exports__.ODBLiteTransaction;
1950
2036
  exports.ORM = __webpack_exports__.ORM;
2037
+ exports.ORMTransaction = __webpack_exports__.ORMTransaction;
1951
2038
  exports.QueryError = __webpack_exports__.QueryError;
1952
2039
  exports.SQLParser = __webpack_exports__.SQLParser;
1953
2040
  exports.ServiceClient = __webpack_exports__.ServiceClient;
@@ -1996,6 +2083,7 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [
1996
2083
  "ODBLiteError",
1997
2084
  "ODBLiteTransaction",
1998
2085
  "ORM",
2086
+ "ORMTransaction",
1999
2087
  "QueryError",
2000
2088
  "SQLParser",
2001
2089
  "ServiceClient",
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { HTTPClient } from './core/http-client.ts';
5
5
  export { SQLParser, sql, fragment } from './core/sql-parser.ts';
6
6
  export { ServiceClient } from './service/service-client.ts';
7
7
  export { DatabaseManager, parseSQL, splitSQLStatements, BunSQLiteAdapter, LibSQLAdapter, ODBLiteAdapter, sql as sqlTemplate, raw as rawSQL, empty, fragment as sqlFragment, join as sqlJoin, set, where as sqlWhere, convertTemplateToQuery, } from './database/index.ts';
8
- export { ORM, createORM, eq, ne, gt, gte, lt, lte, like, inArray, isNull, isNotNull, and, or, type WhereCondition, type OrderByDirection, } from './orm/index.ts';
8
+ export { ORM, Transaction as ORMTransaction, createORM, eq, ne, gt, gte, lt, lte, like, inArray, isNull, isNotNull, and, or, type WhereCondition, type OrderByDirection, } from './orm/index.ts';
9
9
  export type { ODBLiteConfig, ODBLiteConnection, QueryResult, Transaction, SQLFragment, PreparedQuery, QueryParameter, PrimitiveType, Row } from './types.ts';
10
10
  export type { ServiceClientConfig, ODBLiteDatabase, ODBLiteNode } from './service/service-client.ts';
11
11
  export type { TenancyMode, BackendType, QueryResult as DatabaseQueryResult, Connection, DatabaseAdapter, PreparedStatement as DatabasePreparedStatement, DatabaseManagerConfig, MigrationConfig, BunSQLiteConfig, LibSQLConfig, ODBLiteConfig as DatabaseODBLiteConfig, TenantInfo, ParsedStatements, SQLParserOptions, SqlQuery, SqlFragment, } from './database/index.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAG5D,OAAO,EACL,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,cAAc,EAEd,GAAG,IAAI,WAAW,EAClB,GAAG,IAAI,MAAM,EACb,KAAK,EACL,QAAQ,IAAI,WAAW,EACvB,IAAI,IAAI,OAAO,EACf,GAAG,EACH,KAAK,IAAI,QAAQ,EACjB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,GAAG,EACH,SAAS,EACT,EAAE,EACF,EAAE,EACF,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,IAAI,EACJ,OAAO,EACP,MAAM,EACN,SAAS,EACT,GAAG,EACH,EAAE,EACF,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,GAAG,EACJ,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,WAAW,EACZ,MAAM,6BAA6B,CAAC;AAGrC,YAAY,EACV,WAAW,EACX,WAAW,EACX,WAAW,IAAI,mBAAmB,EAClC,UAAU,EACV,eAAe,EACf,iBAAiB,IAAI,yBAAyB,EAC9C,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,IAAI,qBAAqB,EACtC,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,EACR,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,YAAY,EACZ,eAAe,EACf,UAAU,EACX,MAAM,YAAY,CAAC;AAGpB,eAAO,MACL,GAAG,4BACH,UAAU,mCACV,KAAK,8BACL,YAAY,qCACZ,SAAS,kCACT,IAAI,2BACW,CAAC;AAGlB,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAG5D,OAAO,EACL,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,cAAc,EAEd,GAAG,IAAI,WAAW,EAClB,GAAG,IAAI,MAAM,EACb,KAAK,EACL,QAAQ,IAAI,WAAW,EACvB,IAAI,IAAI,OAAO,EACf,GAAG,EACH,KAAK,IAAI,QAAQ,EACjB,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,GAAG,EACH,WAAW,IAAI,cAAc,EAC7B,SAAS,EACT,EAAE,EACF,EAAE,EACF,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,IAAI,EACJ,OAAO,EACP,MAAM,EACN,SAAS,EACT,GAAG,EACH,EAAE,EACF,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,cAAc,EACd,aAAa,EACb,GAAG,EACJ,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,WAAW,EACZ,MAAM,6BAA6B,CAAC;AAGrC,YAAY,EACV,WAAW,EACX,WAAW,EACX,WAAW,IAAI,mBAAmB,EAClC,UAAU,EACV,eAAe,EACf,iBAAiB,IAAI,yBAAyB,EAC9C,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,IAAI,qBAAqB,EACtC,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,EACR,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,YAAY,EACZ,eAAe,EACf,UAAU,EACX,MAAM,YAAY,CAAC;AAGpB,eAAO,MACL,GAAG,4BACH,UAAU,mCACV,KAAK,8BACL,YAAY,qCACZ,SAAS,kCACT,IAAI,2BACW,CAAC;AAGlB,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ var __webpack_modules__ = {
6
6
  __webpack_require__.r(__webpack_exports__);
7
7
  __webpack_require__.d(__webpack_exports__, {
8
8
  ORM: ()=>ORM,
9
+ Transaction: ()=>Transaction,
9
10
  and: ()=>and,
10
11
  createORM: ()=>createORM,
11
12
  eq: ()=>eq,
@@ -296,10 +297,67 @@ var __webpack_modules__ = {
296
297
  return new DeleteBuilder(this.db, this.tableName);
297
298
  }
298
299
  }
300
+ class Transaction {
301
+ orm;
302
+ isCommitted = false;
303
+ isRolledBack = false;
304
+ db;
305
+ savepointName;
306
+ constructor(db, transactionDepth = 0, savepointName){
307
+ this.db = db;
308
+ this.orm = new ORM(db, transactionDepth);
309
+ this.savepointName = savepointName;
310
+ }
311
+ select(fields) {
312
+ this.checkNotFinalized();
313
+ return this.orm.select(fields);
314
+ }
315
+ insert(tableName) {
316
+ this.checkNotFinalized();
317
+ return this.orm.insert(tableName);
318
+ }
319
+ update(tableName) {
320
+ this.checkNotFinalized();
321
+ return this.orm.update(tableName);
322
+ }
323
+ delete(tableName) {
324
+ this.checkNotFinalized();
325
+ return this.orm.delete(tableName);
326
+ }
327
+ execute(sql, params) {
328
+ this.checkNotFinalized();
329
+ return this.orm.execute(sql, params);
330
+ }
331
+ async transaction(fn) {
332
+ this.checkNotFinalized();
333
+ if (fn) return await this.orm.transaction(fn);
334
+ return await this.orm.transaction();
335
+ }
336
+ async commit() {
337
+ if (this.isCommitted) throw new Error('Transaction already committed');
338
+ if (this.isRolledBack) throw new Error('Transaction already rolled back');
339
+ if (this.savepointName) await this.db.execute(`RELEASE SAVEPOINT ${this.savepointName}`, []);
340
+ else await this.db.execute('COMMIT', []);
341
+ this.isCommitted = true;
342
+ }
343
+ async rollback() {
344
+ if (this.isCommitted) throw new Error('Transaction already committed');
345
+ if (this.isRolledBack) throw new Error('Transaction already rolled back');
346
+ if (this.savepointName) await this.db.execute(`ROLLBACK TO SAVEPOINT ${this.savepointName}`, []);
347
+ else await this.db.execute('ROLLBACK', []);
348
+ this.isRolledBack = true;
349
+ }
350
+ checkNotFinalized() {
351
+ if (this.isCommitted) throw new Error('Cannot perform operations on committed transaction');
352
+ if (this.isRolledBack) throw new Error('Cannot perform operations on rolled back transaction');
353
+ }
354
+ }
299
355
  class ORM {
300
356
  db;
301
- constructor(db){
357
+ transactionDepth = 0;
358
+ constructor(db, transactionDepth = 0){
302
359
  this.db = db;
360
+ this.transactionDepth = transactionDepth;
303
361
  }
304
362
  table(tableName) {
305
363
  return new TableQueryBuilder(this.db, tableName);
@@ -325,6 +383,33 @@ var __webpack_modules__ = {
325
383
  execute(sql, params) {
326
384
  return this.db.execute(sql, params);
327
385
  }
386
+ async transaction(fn) {
387
+ if (!fn) if (this.transactionDepth > 0) {
388
+ const savepointName = `sp_${this.transactionDepth}_${Date.now()}`;
389
+ await this.db.execute(`SAVEPOINT ${savepointName}`, []);
390
+ return new Transaction(this.db, this.transactionDepth + 1, savepointName);
391
+ } else {
392
+ await this.db.execute('BEGIN TRANSACTION', []);
393
+ return new Transaction(this.db, 1);
394
+ }
395
+ if (!(this.transactionDepth > 0)) return await this.db.transaction(async (txConnection)=>{
396
+ const txOrm = new ORM(txConnection, 1);
397
+ return await fn(txOrm);
398
+ });
399
+ {
400
+ const savepointName = `sp_${this.transactionDepth}_${Date.now()}`;
401
+ try {
402
+ await this.db.execute(`SAVEPOINT ${savepointName}`, []);
403
+ const nestedOrm = new ORM(this.db, this.transactionDepth + 1);
404
+ const result = await fn(nestedOrm);
405
+ await this.db.execute(`RELEASE SAVEPOINT ${savepointName}`, []);
406
+ return result;
407
+ } catch (error) {
408
+ await this.db.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`, []);
409
+ throw error;
410
+ }
411
+ }
412
+ }
328
413
  }
329
414
  function createORM(db) {
330
415
  return new ORM(db);
@@ -1875,6 +1960,7 @@ class DatabaseManager {
1875
1960
  var orm = __webpack_require__("./src/orm/index.ts");
1876
1961
  const { raw: src_raw, identifier: src_identifier, where: src_where, insertValues: src_insertValues, updateSet: src_updateSet, join: src_join } = ODBLiteClient;
1877
1962
  var __webpack_exports__ORM = orm.ORM;
1963
+ var __webpack_exports__ORMTransaction = orm.Transaction;
1878
1964
  var __webpack_exports__and = orm.and;
1879
1965
  var __webpack_exports__createORM = orm.createORM;
1880
1966
  var __webpack_exports__eq = orm.eq;
@@ -1888,4 +1974,4 @@ var __webpack_exports__lt = orm.lt;
1888
1974
  var __webpack_exports__lte = orm.lte;
1889
1975
  var __webpack_exports__ne = orm.ne;
1890
1976
  var __webpack_exports__or = orm.or;
1891
- export { BunSQLiteAdapter, ConnectionError, DatabaseManager, HTTPClient, LibSQLAdapter, ODBLiteAdapter, ODBLiteClient, ODBLiteError, ODBLiteTransaction, types_QueryError as QueryError, sql_parser_SQLParser as SQLParser, ServiceClient, SimpleTransaction, convertTemplateToQuery, odblite as default, empty, fragment, src_identifier as identifier, src_insertValues as insertValues, src_join as join, odblite, parseSQL, src_raw as raw, sql_template_raw as rawSQL, set, splitSQLStatements, sql_parser_sql as sql, sql_template_fragment as sqlFragment, sql_template_join as sqlJoin, sql_template_sql as sqlTemplate, sql_template_where as sqlWhere, src_updateSet as updateSet, src_where as where, __webpack_exports__ORM as ORM, __webpack_exports__and as and, __webpack_exports__createORM as createORM, __webpack_exports__eq as eq, __webpack_exports__gt as gt, __webpack_exports__gte as gte, __webpack_exports__inArray as inArray, __webpack_exports__isNotNull as isNotNull, __webpack_exports__isNull as isNull, __webpack_exports__like as like, __webpack_exports__lt as lt, __webpack_exports__lte as lte, __webpack_exports__ne as ne, __webpack_exports__or as or };
1977
+ export { BunSQLiteAdapter, ConnectionError, DatabaseManager, HTTPClient, LibSQLAdapter, ODBLiteAdapter, ODBLiteClient, ODBLiteError, ODBLiteTransaction, types_QueryError as QueryError, sql_parser_SQLParser as SQLParser, ServiceClient, SimpleTransaction, convertTemplateToQuery, odblite as default, empty, fragment, src_identifier as identifier, src_insertValues as insertValues, src_join as join, odblite, parseSQL, src_raw as raw, sql_template_raw as rawSQL, set, splitSQLStatements, sql_parser_sql as sql, sql_template_fragment as sqlFragment, sql_template_join as sqlJoin, sql_template_sql as sqlTemplate, sql_template_where as sqlWhere, src_updateSet as updateSet, src_where as where, __webpack_exports__ORM as ORM, __webpack_exports__ORMTransaction as ORMTransaction, __webpack_exports__and as and, __webpack_exports__createORM as createORM, __webpack_exports__eq as eq, __webpack_exports__gt as gt, __webpack_exports__gte as gte, __webpack_exports__inArray as inArray, __webpack_exports__isNotNull as isNotNull, __webpack_exports__isNull as isNull, __webpack_exports__like as like, __webpack_exports__lt as lt, __webpack_exports__lte as lte, __webpack_exports__ne as ne, __webpack_exports__or as or };
@@ -186,13 +186,53 @@ declare class TableQueryBuilder {
186
186
  */
187
187
  delete(): DeleteBuilder;
188
188
  }
189
+ /**
190
+ * Manual Transaction Control
191
+ * Allows explicit commit/rollback control
192
+ */
193
+ export declare class Transaction {
194
+ private orm;
195
+ private isCommitted;
196
+ private isRolledBack;
197
+ private db;
198
+ private savepointName?;
199
+ constructor(db: Connection, transactionDepth?: number, savepointName?: string);
200
+ /**
201
+ * Access ORM methods (select, insert, update, delete)
202
+ */
203
+ select(fields?: Record<string, any>): {
204
+ from: (tableName: string) => SelectBuilder<any>;
205
+ };
206
+ insert(tableName: string): InsertBuilder<any>;
207
+ update(tableName: string): UpdateBuilder<any>;
208
+ delete(tableName: string): DeleteBuilder;
209
+ execute(sql: string, params?: any[]): Promise<import("../index.ts").DatabaseQueryResult<any>>;
210
+ /**
211
+ * Create nested transaction (savepoint)
212
+ */
213
+ transaction(): Promise<Transaction>;
214
+ transaction<T>(fn: (tx: ORM) => Promise<T>): Promise<T>;
215
+ /**
216
+ * Commit the transaction
217
+ */
218
+ commit(): Promise<void>;
219
+ /**
220
+ * Rollback the transaction
221
+ */
222
+ rollback(): Promise<void>;
223
+ /**
224
+ * Check if transaction is finalized
225
+ */
226
+ private checkNotFinalized;
227
+ }
189
228
  /**
190
229
  * ORM Wrapper for Connection
191
230
  * Provides Drizzle-like syntax for database operations
192
231
  */
193
232
  export declare class ORM {
194
233
  private db;
195
- constructor(db: Connection);
234
+ private transactionDepth;
235
+ constructor(db: Connection, transactionDepth?: number);
196
236
  /**
197
237
  * Access a table for querying
198
238
  */
@@ -219,6 +259,44 @@ export declare class ORM {
219
259
  * Raw query access
220
260
  */
221
261
  execute(sql: string, params?: any[]): Promise<import("../index.ts").DatabaseQueryResult<any>>;
262
+ /**
263
+ * Execute a transaction with support for nested transactions (savepoints)
264
+ * @example
265
+ * // Callback-style transaction
266
+ * const result = await orm.transaction(async (tx) => {
267
+ * const user = await tx.insert('users').values({ name: 'Alice' }).returning()
268
+ * const profile = await tx.insert('profiles').values({
269
+ * userId: user[0].id,
270
+ * bio: 'Hello world',
271
+ * }).returning()
272
+ * return { user, profile }
273
+ * })
274
+ *
275
+ * @example
276
+ * // Manual transaction control
277
+ * const tx = await orm.transaction()
278
+ * try {
279
+ * await tx.insert('users').values({ name: 'Bob' }).execute()
280
+ * await tx.insert('profiles').values({ userId: 1, bio: 'Something' }).execute()
281
+ * await tx.commit()
282
+ * } catch (err) {
283
+ * await tx.rollback()
284
+ * throw err
285
+ * }
286
+ *
287
+ * @example
288
+ * // Nested transaction (savepoint)
289
+ * await orm.transaction(async (outer) => {
290
+ * await outer.insert('users').values({ name: 'Outer' })
291
+ *
292
+ * await outer.transaction(async (inner) => {
293
+ * await inner.insert('users').values({ name: 'Inner' })
294
+ * // If this inner block throws, only the inner part rolls back
295
+ * })
296
+ * })
297
+ */
298
+ transaction(): Promise<Transaction>;
299
+ transaction<T>(fn: (tx: ORM) => Promise<T>): Promise<T>;
222
300
  }
223
301
  /**
224
302
  * Create ORM instance from Connection
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orm/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orm/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pineliner/odb-client",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Isomorphic client for ODB-Lite with postgres.js-like template string SQL support",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -42,4 +42,4 @@
42
42
  "template-strings",
43
43
  "postgres-like"
44
44
  ]
45
- }
45
+ }
package/src/index.ts CHANGED
@@ -32,6 +32,7 @@ export {
32
32
  // ORM exports (Drizzle-like query builder)
33
33
  export {
34
34
  ORM,
35
+ Transaction as ORMTransaction,
35
36
  createORM,
36
37
  eq,
37
38
  ne,
package/src/orm/index.ts CHANGED
@@ -461,6 +461,129 @@ class TableQueryBuilder {
461
461
  }
462
462
  }
463
463
 
464
+ // ============================================================
465
+ // MANUAL TRANSACTION CLASS
466
+ // ============================================================
467
+
468
+ /**
469
+ * Manual Transaction Control
470
+ * Allows explicit commit/rollback control
471
+ */
472
+ export class Transaction {
473
+ private orm: ORM
474
+ private isCommitted: boolean = false
475
+ private isRolledBack: boolean = false
476
+ private db: Connection
477
+ private savepointName?: string
478
+
479
+ constructor(db: Connection, transactionDepth: number = 0, savepointName?: string) {
480
+ this.db = db
481
+ this.orm = new ORM(db, transactionDepth)
482
+ this.savepointName = savepointName
483
+ }
484
+
485
+ /**
486
+ * Access ORM methods (select, insert, update, delete)
487
+ */
488
+ select(fields?: Record<string, any>) {
489
+ this.checkNotFinalized()
490
+ return this.orm.select(fields)
491
+ }
492
+
493
+ insert(tableName: string) {
494
+ this.checkNotFinalized()
495
+ return this.orm.insert(tableName)
496
+ }
497
+
498
+ update(tableName: string) {
499
+ this.checkNotFinalized()
500
+ return this.orm.update(tableName)
501
+ }
502
+
503
+ delete(tableName: string) {
504
+ this.checkNotFinalized()
505
+ return this.orm.delete(tableName)
506
+ }
507
+
508
+ execute(sql: string, params?: any[]) {
509
+ this.checkNotFinalized()
510
+ return this.orm.execute(sql, params)
511
+ }
512
+
513
+ /**
514
+ * Create nested transaction (savepoint)
515
+ */
516
+ async transaction(): Promise<Transaction>
517
+ async transaction<T>(fn: (tx: ORM) => Promise<T>): Promise<T>
518
+ async transaction<T>(fn?: (tx: ORM) => Promise<T>): Promise<T | Transaction> {
519
+ this.checkNotFinalized()
520
+
521
+ if (fn) {
522
+ // Callback-style nested transaction
523
+ return await this.orm.transaction(fn)
524
+ } else {
525
+ // Manual-style nested transaction
526
+ return await this.orm.transaction()
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Commit the transaction
532
+ */
533
+ async commit(): Promise<void> {
534
+ if (this.isCommitted) {
535
+ throw new Error('Transaction already committed')
536
+ }
537
+ if (this.isRolledBack) {
538
+ throw new Error('Transaction already rolled back')
539
+ }
540
+
541
+ if (this.savepointName) {
542
+ // Release savepoint for nested transaction
543
+ await this.db.execute(`RELEASE SAVEPOINT ${this.savepointName}`, [])
544
+ } else {
545
+ // Commit top-level transaction
546
+ await this.db.execute('COMMIT', [])
547
+ }
548
+
549
+ this.isCommitted = true
550
+ }
551
+
552
+ /**
553
+ * Rollback the transaction
554
+ */
555
+ async rollback(): Promise<void> {
556
+ if (this.isCommitted) {
557
+ throw new Error('Transaction already committed')
558
+ }
559
+ if (this.isRolledBack) {
560
+ throw new Error('Transaction already rolled back')
561
+ }
562
+
563
+ if (this.savepointName) {
564
+ // Rollback to savepoint for nested transaction
565
+ await this.db.execute(`ROLLBACK TO SAVEPOINT ${this.savepointName}`, [])
566
+ } else {
567
+ // Rollback top-level transaction
568
+ await this.db.execute('ROLLBACK', [])
569
+ }
570
+
571
+ this.isRolledBack = true
572
+ }
573
+
574
+ /**
575
+ * Check if transaction is finalized
576
+ */
577
+ private checkNotFinalized() {
578
+ if (this.isCommitted) {
579
+ throw new Error('Cannot perform operations on committed transaction')
580
+ }
581
+ if (this.isRolledBack) {
582
+ throw new Error('Cannot perform operations on rolled back transaction')
583
+ }
584
+ }
585
+ }
586
+
464
587
  // ============================================================
465
588
  // ORM CONNECTION WRAPPER
466
589
  // ============================================================
@@ -471,9 +594,11 @@ class TableQueryBuilder {
471
594
  */
472
595
  export class ORM {
473
596
  private db: Connection
597
+ private transactionDepth: number = 0
474
598
 
475
- constructor(db: Connection) {
599
+ constructor(db: Connection, transactionDepth: number = 0) {
476
600
  this.db = db
601
+ this.transactionDepth = transactionDepth
477
602
  }
478
603
 
479
604
  /**
@@ -525,6 +650,96 @@ export class ORM {
525
650
  execute(sql: string, params?: any[]) {
526
651
  return this.db.execute(sql, params)
527
652
  }
653
+
654
+ /**
655
+ * Execute a transaction with support for nested transactions (savepoints)
656
+ * @example
657
+ * // Callback-style transaction
658
+ * const result = await orm.transaction(async (tx) => {
659
+ * const user = await tx.insert('users').values({ name: 'Alice' }).returning()
660
+ * const profile = await tx.insert('profiles').values({
661
+ * userId: user[0].id,
662
+ * bio: 'Hello world',
663
+ * }).returning()
664
+ * return { user, profile }
665
+ * })
666
+ *
667
+ * @example
668
+ * // Manual transaction control
669
+ * const tx = await orm.transaction()
670
+ * try {
671
+ * await tx.insert('users').values({ name: 'Bob' }).execute()
672
+ * await tx.insert('profiles').values({ userId: 1, bio: 'Something' }).execute()
673
+ * await tx.commit()
674
+ * } catch (err) {
675
+ * await tx.rollback()
676
+ * throw err
677
+ * }
678
+ *
679
+ * @example
680
+ * // Nested transaction (savepoint)
681
+ * await orm.transaction(async (outer) => {
682
+ * await outer.insert('users').values({ name: 'Outer' })
683
+ *
684
+ * await outer.transaction(async (inner) => {
685
+ * await inner.insert('users').values({ name: 'Inner' })
686
+ * // If this inner block throws, only the inner part rolls back
687
+ * })
688
+ * })
689
+ */
690
+ async transaction(): Promise<Transaction>
691
+ async transaction<T>(fn: (tx: ORM) => Promise<T>): Promise<T>
692
+ async transaction<T>(fn?: (tx: ORM) => Promise<T>): Promise<T | Transaction> {
693
+ // Manual transaction control (no callback provided)
694
+ if (!fn) {
695
+ if (this.transactionDepth > 0) {
696
+ // Nested manual transaction - create savepoint
697
+ const savepointName = `sp_${this.transactionDepth}_${Date.now()}`
698
+ await this.db.execute(`SAVEPOINT ${savepointName}`, [])
699
+ return new Transaction(this.db, this.transactionDepth + 1, savepointName)
700
+ } else {
701
+ // Top-level manual transaction
702
+ await this.db.execute('BEGIN TRANSACTION', [])
703
+ return new Transaction(this.db, 1)
704
+ }
705
+ }
706
+
707
+ // Callback-style transaction
708
+ // Check if we're already in a transaction (nested transaction)
709
+ if (this.transactionDepth > 0) {
710
+ // Nested transaction - use savepoint
711
+ const savepointName = `sp_${this.transactionDepth}_${Date.now()}`
712
+
713
+ try {
714
+ // Create savepoint
715
+ await this.db.execute(`SAVEPOINT ${savepointName}`, [])
716
+
717
+ // Create a new ORM instance with incremented depth
718
+ const nestedOrm = new ORM(this.db, this.transactionDepth + 1)
719
+
720
+ // Execute the user's transaction function
721
+ const result = await fn(nestedOrm)
722
+
723
+ // Release savepoint on success
724
+ await this.db.execute(`RELEASE SAVEPOINT ${savepointName}`, [])
725
+
726
+ return result
727
+ } catch (error) {
728
+ // Rollback to savepoint on error
729
+ await this.db.execute(`ROLLBACK TO SAVEPOINT ${savepointName}`, [])
730
+ throw error
731
+ }
732
+ } else {
733
+ // Top-level transaction - use the connection's transaction method
734
+ return await this.db.transaction(async (txConnection) => {
735
+ // Create a new ORM instance wrapping the transaction connection
736
+ // Start at depth 1 since we're now inside a transaction
737
+ const txOrm = new ORM(txConnection, 1)
738
+ // Execute the user's transaction function with the transaction ORM
739
+ return await fn(txOrm)
740
+ })
741
+ }
742
+ }
528
743
  }
529
744
 
530
745
  /**