@happyvertical/sql 0.80.5 → 0.80.6

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.js CHANGED
@@ -2666,6 +2666,41 @@ async function createDatabase(options, cacheKey) {
2666
2666
  }
2667
2667
  }
2668
2668
  };
2669
+ let savepointSequence = 0;
2670
+ /**
2671
+ * Builds the `transaction` exposed on a transaction-scoped interface.
2672
+ *
2673
+ * Re-entering runs the callback under a SAVEPOINT on the *same* connection,
2674
+ * which is what callers assume nesting already did. Re-exposing the top-level
2675
+ * `transaction` here (the previous behaviour) checked out a second pooled
2676
+ * connection and began an independent transaction, so the nested work could
2677
+ * not see the enclosing transaction's uncommitted rows, and if the enclosing
2678
+ * transaction held a lock the nested one needed, the two deadlocked in a way
2679
+ * PostgreSQL cannot detect: the outer connection is blocked on a promise
2680
+ * rather than on a lock, so `deadlock_timeout` never fires and the process
2681
+ * hangs until some unrelated timeout.
2682
+ *
2683
+ * @param txClient - The client running the enclosing transaction
2684
+ * @param scopeFor - Builds the interface handed to the nested callback
2685
+ */
2686
+ const createNestedTransaction = (txClient, scopeFor) => {
2687
+ return async (callback) => {
2688
+ savepointSequence += 1;
2689
+ const name = `hv_sp_${savepointSequence}`;
2690
+ await txClient.query(`SAVEPOINT ${name}`);
2691
+ try {
2692
+ const result = await callback(scopeFor());
2693
+ await txClient.query(`RELEASE SAVEPOINT ${name}`);
2694
+ return result;
2695
+ } catch (error) {
2696
+ try {
2697
+ await txClient.query(`ROLLBACK TO SAVEPOINT ${name}`);
2698
+ await txClient.query(`RELEASE SAVEPOINT ${name}`);
2699
+ } catch {}
2700
+ throw error;
2701
+ }
2702
+ };
2703
+ };
2669
2704
  /**
2670
2705
  * Executes a callback within a database transaction
2671
2706
  * Automatically commits on success or rolls back on error
@@ -2806,7 +2841,7 @@ async function createDatabase(options, cacheKey) {
2806
2841
  },
2807
2842
  tableExists,
2808
2843
  syncSchema,
2809
- transaction
2844
+ transaction: createNestedTransaction(txClient, () => txDb)
2810
2845
  };
2811
2846
  const result = await callback(txDb);
2812
2847
  await txClient.query("COMMIT");
@@ -2980,7 +3015,7 @@ async function createDatabase(options, cacheKey) {
2980
3015
  },
2981
3016
  tableExists,
2982
3017
  syncSchema,
2983
- transaction,
3018
+ transaction: createNestedTransaction(txClient, () => txHandle),
2984
3019
  commit,
2985
3020
  rollback,
2986
3021
  isActive