pqb 0.40.7 → 0.40.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 CHANGED
@@ -5022,8 +5022,129 @@ declare class AfterCommitError extends OrchidOrmError {
5022
5022
  }
5023
5023
  declare const _afterCommitError: (result: unknown, hookResults: AfterCommitErrorResult[], catchAfterCommitError: ((error: AfterCommitError) => void) | undefined) => void;
5024
5024
  declare class Transaction {
5025
- transaction<T extends PickQueryQAndInternal, Result>(this: T, cb: () => Promise<Result>): Promise<Result>;
5026
- transaction<T extends PickQueryQAndInternal, Result>(this: T, options: IsolationLevel | TransactionOptions, cb: () => Promise<Result>): Promise<Result>;
5025
+ /**
5026
+ * In Orchid ORM the method is `$transaction`, when using `pqb` on its own it is `transaction`.
5027
+ *
5028
+ * `COMMIT` happens automatically after the callback was successfully resolved, and `ROLLBACK` is done automatically if the callback fails.
5029
+ *
5030
+ * Let's consider the case of transferring money from one user to another:
5031
+ *
5032
+ * ```ts
5033
+ * export const transferMoney = async (
5034
+ * fromId: number,
5035
+ * toId: number,
5036
+ * amount: number,
5037
+ * ) => {
5038
+ * try {
5039
+ * // db.$transaction returns data that is returned from the callback
5040
+ * // result here is senderRemainder
5041
+ * const result = await db.$transaction(async () => {
5042
+ * const sender = await db.user.find(fromId);
5043
+ * const senderRemainder = sender.balance - amount;
5044
+ * if (senderRemainder < 0) {
5045
+ * throw new Error('Sender does not have enough money');
5046
+ * }
5047
+ *
5048
+ * await db.user.find(fromId).decrement({
5049
+ * balance: amount,
5050
+ * });
5051
+ * await db.user.find(toId).increment({
5052
+ * balance: amount,
5053
+ * });
5054
+ *
5055
+ * return senderRemainder;
5056
+ * });
5057
+ * } catch (error) {
5058
+ * // handle transaction error
5059
+ * }
5060
+ * };
5061
+ * ```
5062
+ *
5063
+ * It performs 3 queries in a single transaction: load sender record, decrement sender's balance, increment receiver's balance.
5064
+ *
5065
+ * If sender or receiver record doesn't exist, it will throw `NotFound` error, and there is an error thrown when sender's balance is too low.
5066
+ * In such case, the transaction will be rolled back and no changes will be applied to the database.
5067
+ *
5068
+ * Internally, ORM relies on [AsyncLocalStorage](https://nodejs.org/api/async_context.html#class-asynclocalstorage) feature of node.js,
5069
+ * it allows passing the transaction object implicitly. So that any query that is done inside of callback, will run inside a transaction.
5070
+ *
5071
+ * ## nested transactions
5072
+ *
5073
+ * Transactions can be nested one in another.
5074
+ * The top level transaction is the real one,
5075
+ * and the nested ones are emulated with [savepoint](https://www.postgresql.org/docs/current/sql-savepoint.html) instead of `BEGIN`
5076
+ * and [release savepoint](https://www.postgresql.org/docs/current/sql-release-savepoint.html) instead of `COMMIT`.
5077
+ *
5078
+ * Use [ensureTransaction](#ensuretransaction) to run all queries in a single transaction.
5079
+ *
5080
+ * ```ts
5081
+ * const result = await db.$transaction(async () => {
5082
+ * await db.table.create(...one);
5083
+ *
5084
+ * const result = await db.$transaction(async () => {
5085
+ * await db.table.create(...two);
5086
+ * return 123;
5087
+ * });
5088
+ *
5089
+ * await db.table.create(...three);
5090
+ *
5091
+ * return result;
5092
+ * });
5093
+ *
5094
+ * // result is returned from the inner transaction
5095
+ * result === 123;
5096
+ * ```
5097
+ *
5098
+ * If the inner transaction throws an error, and it is caught by `try/catch` of outer transaction,
5099
+ * it performs [rollback to savepoint](https://www.postgresql.org/docs/current/sql-rollback-to.html)
5100
+ * and the outer transaction can continue:
5101
+ *
5102
+ * ```ts
5103
+ * class CustomError extends Error {}
5104
+ *
5105
+ * await db.$transaction(async () => {
5106
+ * try {
5107
+ * await db.$transaction(async () => {
5108
+ * throw new CustomError();
5109
+ * });
5110
+ * } catch (err) {
5111
+ * if (err instanceof CustomError) {
5112
+ * // ignore this error
5113
+ * return;
5114
+ * }
5115
+ * throw err;
5116
+ * }
5117
+ *
5118
+ * // this transaction can continue
5119
+ * await db.table.create(...data);
5120
+ * });
5121
+ * ```
5122
+ *
5123
+ * If the error in the inner transaction is not caught, all nested transactions are rolled back and aborted.
5124
+ */
5125
+ transaction<Result>(this: PickQueryQAndInternal, cb: () => Promise<Result>): Promise<Result>;
5126
+ transaction<Result>(this: PickQueryQAndInternal, options: IsolationLevel | TransactionOptions, cb: () => Promise<Result>): Promise<Result>;
5127
+ /**
5128
+ * Use the `$ensureTransaction` when you want to ensure the sequence of queries is running in a transaction, but there is no need for Postgres [savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html).
5129
+ *
5130
+ * ```ts
5131
+ * async function updateUserBalance(userId: string, amount: number) {
5132
+ * await db.$ensureTransaction(async () => {
5133
+ * await db.transfer.create({ userId, amount })
5134
+ * await db.user.find(userId).increment({ balance: amount })
5135
+ * })
5136
+ * }
5137
+ *
5138
+ * async function saveDeposit(userId: string, deposit: { ... }) {
5139
+ * await db.$ensureTransaction(async () => {
5140
+ * await db.deposit.create(deposit)
5141
+ * // transaction in updateUserBalance won't be started
5142
+ * await updateUserBalance(userId, deposit.amount)
5143
+ * })
5144
+ * }
5145
+ * ```
5146
+ */
5147
+ ensureTransaction<Result>(this: PickQueryQAndInternal, cb: () => Promise<Result>): Promise<Result>;
5027
5148
  }
5028
5149
 
5029
5150
  type AfterHook<Select extends PropertyKey[], Shape extends QueryColumns> = QueryAfterHook<{
package/dist/index.js CHANGED
@@ -3397,6 +3397,32 @@ class Transaction {
3397
3397
  }
3398
3398
  }
3399
3399
  }
3400
+ /**
3401
+ * Use the `$ensureTransaction` when you want to ensure the sequence of queries is running in a transaction, but there is no need for Postgres [savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html).
3402
+ *
3403
+ * ```ts
3404
+ * async function updateUserBalance(userId: string, amount: number) {
3405
+ * await db.$ensureTransaction(async () => {
3406
+ * await db.transfer.create({ userId, amount })
3407
+ * await db.user.find(userId).increment({ balance: amount })
3408
+ * })
3409
+ * }
3410
+ *
3411
+ * async function saveDeposit(userId: string, deposit: { ... }) {
3412
+ * await db.$ensureTransaction(async () => {
3413
+ * await db.deposit.create(deposit)
3414
+ * // transaction in updateUserBalance won't be started
3415
+ * await updateUserBalance(userId, deposit.amount)
3416
+ * })
3417
+ * }
3418
+ * ```
3419
+ */
3420
+ ensureTransaction(cb) {
3421
+ const trx = this.internal.transactionStorage.getStore();
3422
+ if (trx)
3423
+ return cb();
3424
+ return Transaction.prototype.transaction.call(this, cb);
3425
+ }
3400
3426
  }
3401
3427
  const runAfterCommit = async (afterCommit, result) => {
3402
3428
  if (afterCommit) {