@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 +37 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|