@proteinjs/db 1.25.2 → 1.27.0
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/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/dist/generated/index.js +7 -7
- package/dist/generated/index.js.map +1 -1
- package/dist/generated/test/index.js +5 -5
- package/dist/generated/test/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/src/Db.d.ts +66 -6
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +242 -30
- package/dist/src/Db.js.map +1 -1
- package/dist/src/MigrationRunner.d.ts.map +1 -1
- package/dist/src/MigrationRunner.js +6 -0
- package/dist/src/MigrationRunner.js.map +1 -1
- package/dist/src/UpdatePreserving.d.ts +34 -0
- package/dist/src/UpdatePreserving.d.ts.map +1 -0
- package/dist/src/UpdatePreserving.js +72 -0
- package/dist/src/UpdatePreserving.js.map +1 -0
- package/dist/src/auth/TableAuth.d.ts +9 -0
- package/dist/src/auth/TableAuth.d.ts.map +1 -1
- package/dist/src/auth/TableAuth.js +36 -5
- package/dist/src/auth/TableAuth.js.map +1 -1
- package/dist/src/auth/TableServiceAuth.d.ts +7 -0
- package/dist/src/auth/TableServiceAuth.d.ts.map +1 -1
- package/dist/src/auth/TableServiceAuth.js +34 -0
- package/dist/src/auth/TableServiceAuth.js.map +1 -1
- package/dist/src/reference/ArrayMembershipOps.d.ts +69 -0
- package/dist/src/reference/ArrayMembershipOps.d.ts.map +1 -0
- package/dist/src/reference/ArrayMembershipOps.js +146 -0
- package/dist/src/reference/ArrayMembershipOps.js.map +1 -0
- package/dist/src/services/DbService.d.ts +38 -0
- package/dist/src/services/DbService.d.ts.map +1 -1
- package/dist/src/services/DbService.js.map +1 -1
- package/dist/src/transaction/Transaction.d.ts +19 -2
- package/dist/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/src/transaction/Transaction.js +38 -0
- package/dist/src/transaction/Transaction.js.map +1 -1
- package/dist/src/transaction/TransactionContextFactory.d.ts +18 -1
- package/dist/src/transaction/TransactionContextFactory.d.ts.map +1 -1
- package/dist/test/ArrayMembershipOps.test.d.ts +2 -0
- package/dist/test/ArrayMembershipOps.test.d.ts.map +1 -0
- package/dist/test/ArrayMembershipOps.test.js +147 -0
- package/dist/test/ArrayMembershipOps.test.js.map +1 -0
- package/dist/test/TableServiceAuth.test.js +108 -4
- package/dist/test/TableServiceAuth.test.js.map +1 -1
- package/generated/index.ts +18 -21
- package/generated/test/index.ts +41 -44
- package/index.ts +2 -0
- package/package.json +6 -5
- package/src/Db.ts +202 -24
- package/src/MigrationRunner.ts +6 -0
- package/src/UpdatePreserving.ts +89 -0
- package/src/auth/TableAuth.ts +17 -4
- package/src/auth/TableServiceAuth.ts +36 -1
- package/src/reference/ArrayMembershipOps.ts +155 -0
- package/src/services/DbService.ts +38 -0
- package/src/transaction/Transaction.ts +52 -2
- package/src/transaction/TransactionContextFactory.ts +19 -1
- package/test/ArrayMembershipOps.test.ts +160 -0
- package/test/TableServiceAuth.test.ts +148 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../generated/test/index.ts"],"names":[],"mappings":";AAAA,oCAAoC;;;;;;;;;;;;;;;;AAEpC,+BAA6B;AAC7B,6BAA2B;AAC3B,iCAA+B;AAC/B,iCAA+B;AAC/B,iCAA+B;AAC/B,8BAA4B;AAC5B,gCAA8B;AAC9B,2BAAyB;AACzB,kBAAgB;AAChB,gBAAc;AAGd,4BAA4B;AAE5B,IAAM,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../generated/test/index.ts"],"names":[],"mappings":";AAAA,oCAAoC;;;;;;;;;;;;;;;;AAEpC,+BAA6B;AAC7B,6BAA2B;AAC3B,iCAA+B;AAC/B,iCAA+B;AAC/B,iCAA+B;AAC/B,8BAA4B;AAC5B,gCAA8B;AAC9B,2BAAyB;AACzB,kBAAgB;AAChB,gBAAc;AAGd,4BAA4B;AAE5B,IAAM,WAAW,GAAG,gj8FAAgj8F,CAAC;AAGrk8F,4BAA4B;AAE5B,0FAAgF;AAChF,yCAAwC;AACxC,0FAA+E;AAC/E,0FAAgF;AAChF,0FAA+E;AAC/E,0FAAgF;AAChF,0FAA+E;AAC/E,0FAA2E;AAC3E,0FAA8E;AAC9E,0FAAmF;AACnF,2FAAkF;AAClF,2FAA6E;AAC7E,2FAA2E;AAC3E,sFAAyE;AACzE,wEAA0E;AAC1E,wEAA8E;AAC9E,4GAAiG;AACjG,4GAAwF;AACxF,4GAAwF;AACxF,4GAA8F;AAC9F,wFAA8E;AAC9E,wFAAqF;AACrF,wFAAiF;AACjF,sFAA4F;AAC5F,sFAAgG;AAChG,mCAAkC;AAClC,iEAAgE;AAChE,6DAA4D;AAC5D,2DAA0D;AAC1D,qEAAoE;AACpE,2FAA0F;AAC1F,iFAAgF;AAChF,yEAAwE;AACxE,0EAAyE;AACzE,kEAAiE;AACjE,6EAA4E;AAE5E,IAAM,WAAW,GAAG;IACnB,8BAA8B,EAAE,wCAAc;IAC9C,qBAAqB,EAAE,aAAK;IAC5B,6BAA6B,EAAE,uCAAa;IAC5C,8BAA8B,EAAE,wCAAc;IAC9C,6BAA6B,EAAE,uCAAa;IAC5C,8BAA8B,EAAE,wCAAc;IAC9C,6BAA6B,EAAE,uCAAa;IAC5C,yBAAyB,EAAE,mCAAS;IACpC,4BAA4B,EAAE,sCAAY;IAC1C,iCAAiC,EAAE,2CAAiB;IACpD,gCAAgC,EAAE,2CAAgB;IAClD,2BAA2B,EAAE,sCAAW;IACxC,yBAAyB,EAAE,oCAAS;IACpC,yBAAyB,EAAE,iCAAS;IACpC,iCAAiC,EAAE,kCAAiB;IACpD,qCAAqC,EAAE,sCAAqB;IAC5D,sCAAsC,EAAE,yDAAsB;IAC9D,6BAA6B,EAAE,gDAAa;IAC5C,6BAA6B,EAAE,gDAAa;IAC5C,mCAAmC,EAAE,sDAAmB;IACxD,6BAA6B,EAAE,sCAAa;IAC5C,oCAAoC,EAAE,6CAAoB;IAC1D,gCAAgC,EAAE,yCAAgB;IAClD,4CAA4C,EAAE,oDAA4B;IAC1E,gDAAgD,EAAE,wDAAgC;IAClF,kBAAkB,EAAE,OAAE;IACtB,iCAAiC,EAAE,qCAAiB;IACpD,+BAA+B,EAAE,iCAAe;IAChD,yBAAyB,EAAE,qBAAS;IACpC,8BAA8B,EAAE,+BAAc;IAC9C,wCAAwC,EAAE,mDAAwB;IAClE,mCAAmC,EAAE,yCAAmB;IACxD,+BAA+B,EAAE,iCAAe;IAChD,kCAAkC,EAAE,uCAAkB;IACtD,8BAA8B,EAAE,+BAAc;IAC9C,iCAAiC,EAAE,qCAAiB;CACpD,CAAC;AAGF,kCAAkC;AAElC,oDAAyD;AACzD,6BAAgB,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAGjD,mDAAiC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ export * from './src/auth/TableServiceAuth';
|
|
|
5
5
|
export * from './src/Columns';
|
|
6
6
|
export * from './src/Record';
|
|
7
7
|
export * from './src/reference/ReferenceArray';
|
|
8
|
+
export * from './src/reference/ArrayMembershipOps';
|
|
8
9
|
export * from './src/reference/Reference';
|
|
10
|
+
export * from './src/UpdatePreserving';
|
|
9
11
|
export * from './src/reference/ReferenceCache';
|
|
10
12
|
export * from './src/RecordIterator';
|
|
11
13
|
export * from './src/source/SourceRecord';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,6CAA6C,CAAC;AAE5D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAE1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAE5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,uCAAuC,CAAC;AACtD,cAAc,yCAAyC,CAAC;AAExD,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,6CAA6C,CAAC;AAE5D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAE1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAE5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,uCAAuC,CAAC;AACtD,cAAc,yCAAyC,CAAC;AAExD,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,9 @@ __exportStar(require("./src/auth/TableServiceAuth"), exports);
|
|
|
21
21
|
__exportStar(require("./src/Columns"), exports);
|
|
22
22
|
__exportStar(require("./src/Record"), exports);
|
|
23
23
|
__exportStar(require("./src/reference/ReferenceArray"), exports);
|
|
24
|
+
__exportStar(require("./src/reference/ArrayMembershipOps"), exports);
|
|
24
25
|
__exportStar(require("./src/reference/Reference"), exports);
|
|
26
|
+
__exportStar(require("./src/UpdatePreserving"), exports);
|
|
25
27
|
__exportStar(require("./src/reference/ReferenceCache"), exports);
|
|
26
28
|
__exportStar(require("./src/RecordIterator"), exports);
|
|
27
29
|
__exportStar(require("./src/source/SourceRecord"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,8CAA4B;AAC5B,uDAAqC;AACrC,8DAA4C;AAC5C,gDAA8B;AAC9B,+CAA6B;AAC7B,iEAA+C;AAC/C,4DAA0C;AAC1C,iEAA+C;AAC/C,uDAAqC;AACrC,4DAA0C;AAC1C,4DAA0C;AAC1C,qDAAmC;AACnC,gEAA8C;AAC9C,sEAAoD;AACpD,8EAA4D;AAE5D,gEAA8C;AAC9C,8DAA4C;AAC5C,4DAA0C;AAE1C,sDAAoC;AACpC,8DAA4C;AAE5C,2DAAyC;AACzC,wEAAsD;AACtD,0EAAwD;AAExD,sDAAoC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,8CAA4B;AAC5B,uDAAqC;AACrC,8DAA4C;AAC5C,gDAA8B;AAC9B,+CAA6B;AAC7B,iEAA+C;AAC/C,qEAAmD;AACnD,4DAA0C;AAC1C,yDAAuC;AACvC,iEAA+C;AAC/C,uDAAqC;AACrC,4DAA0C;AAC1C,4DAA0C;AAC1C,qDAAmC;AACnC,gEAA8C;AAC9C,sEAAoD;AACpD,8EAA4D;AAE5D,gEAA8C;AAC9C,8DAA4C;AAC5C,4DAA0C;AAE1C,sDAAoC;AACpC,8DAA4C;AAE5C,2DAAyC;AACzC,wEAAsD;AACtD,0EAAwD;AAExD,sDAAoC"}
|
package/dist/src/Db.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { Table } from './Table';
|
|
|
5
5
|
import { Record, SerializedRecord } from './Record';
|
|
6
6
|
import { ParameterizationConfig, Statement } from '@proteinjs/db-query';
|
|
7
7
|
import { TableManager } from './schema/TableManager';
|
|
8
|
-
import { DefaultTransactionContextFactory } from './transaction/TransactionContextFactory';
|
|
8
|
+
import { DefaultTransactionContextFactory, PostCommitHook } from './transaction/TransactionContextFactory';
|
|
9
|
+
import { ArrayMembershipUpdate } from './reference/ArrayMembershipOps';
|
|
10
|
+
import { PreservedPath } from './UpdatePreserving';
|
|
9
11
|
/** get `Db` if on server, and `DbService` if on browser */
|
|
10
12
|
export declare const getDb: <R extends Record = Record>() => Db<R>;
|
|
11
13
|
export declare const getDbAsSystem: <R extends Record = Record>() => Db<R>;
|
|
@@ -40,7 +42,6 @@ export declare class Db<R extends Record = Record> implements DbService<R> {
|
|
|
40
42
|
private statementConfigFactory;
|
|
41
43
|
private auth;
|
|
42
44
|
private tableWatcherRunner;
|
|
43
|
-
private currentTransaction?;
|
|
44
45
|
private transactionContextFactory;
|
|
45
46
|
serviceMetadata: Service['serviceMetadata'];
|
|
46
47
|
constructor(dbDriver?: DbDriver, getTable?: (tableName: string) => Table<any>, transactionContextFactory?: DefaultTransactionContextFactory, runAsSystem?: boolean);
|
|
@@ -51,6 +52,27 @@ export declare class Db<R extends Record = Record> implements DbService<R> {
|
|
|
51
52
|
get<T extends R>(table: Table<T>, query: Query<T>, options?: QueryOptions<T>): Promise<T>;
|
|
52
53
|
insert<T extends R>(table: Table<T>, record: Omit<T, keyof R>): Promise<T>;
|
|
53
54
|
update<T extends R>(table: Table<T>, record: Partial<T>, query?: Query<T>): Promise<number>;
|
|
55
|
+
/**
|
|
56
|
+
* Apply commutative membership ops (add/remove/move) to a `ReferenceArrayColumn`
|
|
57
|
+
* read-modify-write against COMMITTED truth, so concurrent membership writers
|
|
58
|
+
* converge instead of last-write-wins clobbering each other (the write-side
|
|
59
|
+
* lost-update class). Self-wraps in a transaction when called outside one; the
|
|
60
|
+
* driver's abort/retry re-executes the read, so a retried transaction applies
|
|
61
|
+
* its ops to fresh truth rather than replaying a stale list snapshot.
|
|
62
|
+
*
|
|
63
|
+
* Returns the update count (0 when the ops are a no-op against committed truth
|
|
64
|
+
* or the record no longer exists — a concurrently deleted record wins).
|
|
65
|
+
*/
|
|
66
|
+
updateArrayMembership<T extends R>(table: Table<T>, update: ArrayMembershipUpdate): Promise<number>;
|
|
67
|
+
/**
|
|
68
|
+
* Update with committed-truth preservation for column sub-paths the writer does
|
|
69
|
+
* not own (see `UpdatePreserving.ts`). The payload's listed paths are overlaid
|
|
70
|
+
* with their committed values read inside the same transaction, so this write
|
|
71
|
+
* commutes with the writers that own those paths (e.g. a structural editor op
|
|
72
|
+
* writing a JSON object's styling while a debounced text save owns `content`).
|
|
73
|
+
* Self-wraps in a transaction when called outside one. Plain-JSON columns only.
|
|
74
|
+
*/
|
|
75
|
+
updatePreserving<T extends R>(table: Table<T>, record: Partial<T>, preserve: PreservedPath[]): Promise<number>;
|
|
54
76
|
delete<T extends R>(table: Table<T>, query: Query<T>): Promise<number>;
|
|
55
77
|
private runColumnBeforeDeletes;
|
|
56
78
|
private runCascadeDeletions;
|
|
@@ -79,13 +101,19 @@ export declare class Db<R extends Record = Record> implements DbService<R> {
|
|
|
79
101
|
/**
|
|
80
102
|
* Run a transaction.
|
|
81
103
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
104
|
+
* Db instances are STATELESS with respect to transactions: every operation resolves the
|
|
105
|
+
* ambient transaction (AsyncLocalStorage) at call time, so any Db instance used inside the
|
|
106
|
+
* transaction body — whenever it was constructed — rides the transaction. There is no way
|
|
107
|
+
* to issue an operation outside a transaction from inside its body, and no second session
|
|
108
|
+
* is ever acquired inside one (the historical pool-wedge class is unrepresentable —
|
|
109
|
+
* plans/DB_PERF_PLAN.md P2, in the consumer repo).
|
|
86
110
|
*
|
|
87
111
|
* Note: Nested transactions are not supported; will throw.
|
|
88
112
|
*
|
|
113
|
+
* Note: work spawned inside the body but NOT awaited by it escapes the transaction's
|
|
114
|
+
* lifetime while still holding its context — such work fails loudly on its next db
|
|
115
|
+
* operation (see TransactionContextData.ended). Await everything inside the body, or run
|
|
116
|
+
* it outside the transaction.
|
|
89
117
|
*
|
|
90
118
|
* Example:
|
|
91
119
|
*
|
|
@@ -101,6 +129,38 @@ export declare class Db<R extends Record = Record> implements DbService<R> {
|
|
|
101
129
|
* ```
|
|
102
130
|
*/
|
|
103
131
|
runTransaction<T>(fn: () => Promise<T>): Promise<T>;
|
|
132
|
+
/**
|
|
133
|
+
* Run `hook` once the write unit currently executing is durably committed.
|
|
134
|
+
*
|
|
135
|
+
* - Inside a `runTransaction` scope: the hook is queued on the ambient transaction context and
|
|
136
|
+
* runs after the transaction COMMITS. Hooks never run on rollback.
|
|
137
|
+
* - Outside a transaction: every DML statement auto-commits when it resolves, so the hook runs
|
|
138
|
+
* (awaited) immediately. Callers are responsible for invoking this only from points where
|
|
139
|
+
* the triggering statement has already executed — e.g. `after*` table watchers, never
|
|
140
|
+
* `before*` ones.
|
|
141
|
+
*
|
|
142
|
+
* For side effects that must observe committed truth — e.g. socket notifications that trigger
|
|
143
|
+
* client refetches: a pre-commit emission lets a client refetch read pre-commit rows and
|
|
144
|
+
* "resurrect" state the transaction is deleting.
|
|
145
|
+
*/
|
|
146
|
+
runAfterCommit(hook: PostCommitHook): Promise<void>;
|
|
147
|
+
/**
|
|
148
|
+
* A fresh instance for self-wrapping RMW verbs (`updateArrayMembership`, `updatePreserving`)
|
|
149
|
+
* in a transaction. `runTransaction` carries the open transaction as INSTANCE state, and these
|
|
150
|
+
* verbs also serve the `DbService` RPC path, where one long-lived Db instance handles
|
|
151
|
+
* concurrent requests — self-wrapping on `this` would leak one request's transaction into
|
|
152
|
+
* another's ops (or spuriously reject it as a nested transaction). Same driver/tables/system
|
|
153
|
+
* mode; only the transaction state is isolated.
|
|
154
|
+
*/
|
|
155
|
+
private newSelfWrapDb;
|
|
156
|
+
/**
|
|
157
|
+
* The transaction every driver call rides, resolved from the ambient context AT CALL TIME
|
|
158
|
+
* (statelessness is the safety property: operations inside a transaction body always ride
|
|
159
|
+
* it; operations outside always use the pool). The one remaining failure shape — work that
|
|
160
|
+
* escaped a finished transaction's body while holding its context — throws here by name;
|
|
161
|
+
* handing the driver an ended transaction would fail anyway, with a far worse error.
|
|
162
|
+
*/
|
|
163
|
+
private transactionForDriver;
|
|
104
164
|
private chunk;
|
|
105
165
|
}
|
|
106
166
|
//# sourceMappingURL=Db.d.ts.map
|
package/dist/src/Db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../src/Db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAgB,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAoB,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAEL,KAAK,EAMN,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAoB,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAGtE,OAAO,EAAE,sBAAsB,EAAgB,SAAS,EAAoB,MAAM,qBAAqB,CAAC;AAGxG,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAIrD,OAAO,EACL,gCAAgC,
|
|
1
|
+
{"version":3,"file":"Db.d.ts","sourceRoot":"","sources":["../../src/Db.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Db.js
CHANGED
|
@@ -35,6 +35,15 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
35
35
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
39
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
40
|
+
if (ar || !(i in from)) {
|
|
41
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
42
|
+
ar[i] = from[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
46
|
+
};
|
|
38
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
48
|
exports.Db = exports.getDbAsSystem = exports.getDb = void 0;
|
|
40
49
|
var DbService_1 = require("./services/DbService");
|
|
@@ -53,6 +62,8 @@ var TransactionContextFactory_1 = require("./transaction/TransactionContextFacto
|
|
|
53
62
|
var util_1 = require("@proteinjs/util");
|
|
54
63
|
var Reference_1 = require("./reference/Reference");
|
|
55
64
|
var ReferenceArray_1 = require("./reference/ReferenceArray");
|
|
65
|
+
var ArrayMembershipOps_1 = require("./reference/ArrayMembershipOps");
|
|
66
|
+
var UpdatePreserving_1 = require("./UpdatePreserving");
|
|
56
67
|
/** get `Db` if on server, and `DbService` if on browser */
|
|
57
68
|
var getDb = function () {
|
|
58
69
|
return typeof self === 'undefined' ? new Db() : (0, DbService_1.getDbService)();
|
|
@@ -81,10 +92,6 @@ var Db = /** @class */ (function () {
|
|
|
81
92
|
this.transactionContextFactory = transactionContextFactory
|
|
82
93
|
? transactionContextFactory
|
|
83
94
|
: this.getDefaultTransactionContextFactory();
|
|
84
|
-
var transactionContext = this.transactionContextFactory.getTransactionContext();
|
|
85
|
-
if (transactionContext.currentTransaction) {
|
|
86
|
-
this.currentTransaction = transactionContext.currentTransaction;
|
|
87
|
-
}
|
|
88
95
|
}
|
|
89
96
|
Db.getDefaultDbDriver = function () {
|
|
90
97
|
if (!Db.defaultDbDriver) {
|
|
@@ -168,7 +175,7 @@ var Db = /** @class */ (function () {
|
|
|
168
175
|
generateInsert = function (config) {
|
|
169
176
|
return new db_query_1.StatementFactory().insert(table.name, serializedRecord, _this.statementConfigFactory.getStatementConfig(config));
|
|
170
177
|
};
|
|
171
|
-
return [4 /*yield*/, this.dbDriver.runDml(generateInsert, this.
|
|
178
|
+
return [4 /*yield*/, this.dbDriver.runDml(generateInsert, this.transactionForDriver())];
|
|
172
179
|
case 5:
|
|
173
180
|
_a.sent();
|
|
174
181
|
return [4 /*yield*/, this.tableWatcherRunner.runAfterInsertTableWatchers(table, recordCopy)];
|
|
@@ -225,7 +232,7 @@ var Db = /** @class */ (function () {
|
|
|
225
232
|
generateUpdate = function (config) {
|
|
226
233
|
return new db_query_1.StatementFactory().update(table.name, serializedRecord, qb, _this.statementConfigFactory.getStatementConfig(config));
|
|
227
234
|
};
|
|
228
|
-
return [4 /*yield*/, this.dbDriver.runDml(generateUpdate, this.
|
|
235
|
+
return [4 /*yield*/, this.dbDriver.runDml(generateUpdate, this.transactionForDriver())];
|
|
229
236
|
case 5:
|
|
230
237
|
recordUpdateCount = _b.sent();
|
|
231
238
|
return [4 /*yield*/, this.tableWatcherRunner.runAfterUpdateTableWatchers(table, recordUpdateCount, recordCopy, qb)];
|
|
@@ -236,6 +243,121 @@ var Db = /** @class */ (function () {
|
|
|
236
243
|
});
|
|
237
244
|
});
|
|
238
245
|
};
|
|
246
|
+
/**
|
|
247
|
+
* Apply commutative membership ops (add/remove/move) to a `ReferenceArrayColumn`
|
|
248
|
+
* read-modify-write against COMMITTED truth, so concurrent membership writers
|
|
249
|
+
* converge instead of last-write-wins clobbering each other (the write-side
|
|
250
|
+
* lost-update class). Self-wraps in a transaction when called outside one; the
|
|
251
|
+
* driver's abort/retry re-executes the read, so a retried transaction applies
|
|
252
|
+
* its ops to fresh truth rather than replaying a stale list snapshot.
|
|
253
|
+
*
|
|
254
|
+
* Returns the update count (0 when the ops are a no-op against committed truth
|
|
255
|
+
* or the record no longer exists — a concurrently deleted record wins).
|
|
256
|
+
*/
|
|
257
|
+
Db.prototype.updateArrayMembership = function (table, update) {
|
|
258
|
+
var _a, _b;
|
|
259
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
260
|
+
var db_1, column, qb, rows, currentRefArray, currentIds, _c, ids, changed, record;
|
|
261
|
+
var _this = this;
|
|
262
|
+
return __generator(this, function (_d) {
|
|
263
|
+
switch (_d.label) {
|
|
264
|
+
case 0:
|
|
265
|
+
if (!!this.transactionContextFactory.getTransactionContext().currentTransaction) return [3 /*break*/, 2];
|
|
266
|
+
db_1 = this.newSelfWrapDb();
|
|
267
|
+
return [4 /*yield*/, db_1.runTransaction(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
268
|
+
switch (_a.label) {
|
|
269
|
+
case 0: return [4 /*yield*/, db_1.updateArrayMembership(table, update)];
|
|
270
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
271
|
+
}
|
|
272
|
+
}); }); })];
|
|
273
|
+
case 1: return [2 /*return*/, _d.sent()];
|
|
274
|
+
case 2:
|
|
275
|
+
column = table.columns[update.columnPropertyName];
|
|
276
|
+
if (!column || ((_a = column.constructor) === null || _a === void 0 ? void 0 : _a.name) !== 'ReferenceArrayColumn') {
|
|
277
|
+
throw new Error("updateArrayMembership requires a ReferenceArrayColumn; '".concat(update.columnPropertyName, "' on table '").concat(table.name, "' is not one"));
|
|
278
|
+
}
|
|
279
|
+
qb = new QueryBuilderFactory_1.QueryBuilderFactory().getQueryBuilder(table);
|
|
280
|
+
return [4 /*yield*/, this.addColumnQueries(table, qb, 'write')];
|
|
281
|
+
case 3:
|
|
282
|
+
_d.sent();
|
|
283
|
+
qb.select({ fields: ['id', update.columnPropertyName] });
|
|
284
|
+
qb.condition({ field: 'id', operator: '=', value: update.recordId });
|
|
285
|
+
return [4 /*yield*/, this._query(table, qb)];
|
|
286
|
+
case 4:
|
|
287
|
+
rows = _d.sent();
|
|
288
|
+
if (rows.length === 0) {
|
|
289
|
+
return [2 /*return*/, 0];
|
|
290
|
+
}
|
|
291
|
+
currentRefArray = rows[0][update.columnPropertyName];
|
|
292
|
+
currentIds = (_b = currentRefArray === null || currentRefArray === void 0 ? void 0 : currentRefArray._ids) !== null && _b !== void 0 ? _b : [];
|
|
293
|
+
_c = (0, ArrayMembershipOps_1.applyArrayMembershipOps)(currentIds, update.ops), ids = _c.ids, changed = _c.changed;
|
|
294
|
+
if (!changed) {
|
|
295
|
+
return [2 /*return*/, 0];
|
|
296
|
+
}
|
|
297
|
+
record = { id: update.recordId };
|
|
298
|
+
record[update.columnPropertyName] = new ReferenceArray_1.ReferenceArray(column.referenceTable, ids);
|
|
299
|
+
return [4 /*yield*/, this.update(table, record)];
|
|
300
|
+
case 5: return [2 /*return*/, _d.sent()];
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
/**
|
|
306
|
+
* Update with committed-truth preservation for column sub-paths the writer does
|
|
307
|
+
* not own (see `UpdatePreserving.ts`). The payload's listed paths are overlaid
|
|
308
|
+
* with their committed values read inside the same transaction, so this write
|
|
309
|
+
* commutes with the writers that own those paths (e.g. a structural editor op
|
|
310
|
+
* writing a JSON object's styling while a debounced text save owns `content`).
|
|
311
|
+
* Self-wraps in a transaction when called outside one. Plain-JSON columns only.
|
|
312
|
+
*/
|
|
313
|
+
Db.prototype.updatePreserving = function (table, record, preserve) {
|
|
314
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
315
|
+
var db_2, applicable, qb, rows, recordCopy, _i, applicable_1, p;
|
|
316
|
+
var _this = this;
|
|
317
|
+
return __generator(this, function (_a) {
|
|
318
|
+
switch (_a.label) {
|
|
319
|
+
case 0:
|
|
320
|
+
if (!!this.transactionContextFactory.getTransactionContext().currentTransaction) return [3 /*break*/, 2];
|
|
321
|
+
db_2 = this.newSelfWrapDb();
|
|
322
|
+
return [4 /*yield*/, db_2.runTransaction(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
|
|
323
|
+
switch (_a.label) {
|
|
324
|
+
case 0: return [4 /*yield*/, db_2.updatePreserving(table, record, preserve)];
|
|
325
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
326
|
+
}
|
|
327
|
+
}); }); })];
|
|
328
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
329
|
+
case 2:
|
|
330
|
+
if (!record.id) {
|
|
331
|
+
throw new Error("updatePreserving must be called with a record with an id property");
|
|
332
|
+
}
|
|
333
|
+
applicable = preserve.filter(function (p) { return record[p.columnPropertyName] !== undefined; });
|
|
334
|
+
if (!(applicable.length === 0)) return [3 /*break*/, 4];
|
|
335
|
+
return [4 /*yield*/, this.update(table, record)];
|
|
336
|
+
case 3: return [2 /*return*/, _a.sent()];
|
|
337
|
+
case 4:
|
|
338
|
+
qb = new QueryBuilderFactory_1.QueryBuilderFactory().getQueryBuilder(table);
|
|
339
|
+
return [4 /*yield*/, this.addColumnQueries(table, qb, 'write')];
|
|
340
|
+
case 5:
|
|
341
|
+
_a.sent();
|
|
342
|
+
qb.select({ fields: __spreadArray(['id'], applicable.map(function (p) { return p.columnPropertyName; }), true) });
|
|
343
|
+
qb.condition({ field: 'id', operator: '=', value: record.id });
|
|
344
|
+
return [4 /*yield*/, this._query(table, qb)];
|
|
345
|
+
case 6:
|
|
346
|
+
rows = _a.sent();
|
|
347
|
+
if (rows.length === 0) {
|
|
348
|
+
return [2 /*return*/, 0];
|
|
349
|
+
}
|
|
350
|
+
recordCopy = Object.assign({}, record);
|
|
351
|
+
for (_i = 0, applicable_1 = applicable; _i < applicable_1.length; _i++) {
|
|
352
|
+
p = applicable_1[_i];
|
|
353
|
+
recordCopy[p.columnPropertyName] = (0, UpdatePreserving_1.overlayPreservedPaths)(rows[0][p.columnPropertyName], recordCopy[p.columnPropertyName], p.paths, p.whenType);
|
|
354
|
+
}
|
|
355
|
+
return [4 /*yield*/, this.update(table, recordCopy)];
|
|
356
|
+
case 7: return [2 /*return*/, _a.sent()];
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
};
|
|
239
361
|
Db.prototype.delete = function (table, query) {
|
|
240
362
|
return __awaiter(this, void 0, void 0, function () {
|
|
241
363
|
var qb, recordsToDelete, recordsToDeleteIds, deleteQb, generateDelete, recordDeleteCount;
|
|
@@ -268,7 +390,7 @@ var Db = /** @class */ (function () {
|
|
|
268
390
|
return [4 /*yield*/, this.tableWatcherRunner.runBeforeDeleteTableWatchers(table, recordsToDelete, qb, deleteQb)];
|
|
269
391
|
case 4:
|
|
270
392
|
_a.sent();
|
|
271
|
-
return [4 /*yield*/, this.dbDriver.runDml(generateDelete, this.
|
|
393
|
+
return [4 /*yield*/, this.dbDriver.runDml(generateDelete, this.transactionForDriver())];
|
|
272
394
|
case 5:
|
|
273
395
|
recordDeleteCount = _a.sent();
|
|
274
396
|
return [4 /*yield*/, this.runCascadeDeletions(table, recordsToDelete)];
|
|
@@ -581,7 +703,7 @@ var Db = /** @class */ (function () {
|
|
|
581
703
|
generateQuery = function (config) {
|
|
582
704
|
return qb.toSql(_this.statementConfigFactory.getStatementConfig(config));
|
|
583
705
|
};
|
|
584
|
-
return [4 /*yield*/, this.dbDriver.runQuery(generateQuery, this.
|
|
706
|
+
return [4 /*yield*/, this.dbDriver.runQuery(generateQuery, this.transactionForDriver())];
|
|
585
707
|
case 1:
|
|
586
708
|
serializedRecords = _a.sent();
|
|
587
709
|
recordSerializer = new Record_1.RecordSerializer(table);
|
|
@@ -660,7 +782,7 @@ var Db = /** @class */ (function () {
|
|
|
660
782
|
generateQuery = function (config) {
|
|
661
783
|
return qb.toSql(_this.statementConfigFactory.getStatementConfig(config));
|
|
662
784
|
};
|
|
663
|
-
return [4 /*yield*/, this.dbDriver.runQuery(generateQuery, this.
|
|
785
|
+
return [4 /*yield*/, this.dbDriver.runQuery(generateQuery, this.transactionForDriver())];
|
|
664
786
|
case 2:
|
|
665
787
|
result = _a.sent();
|
|
666
788
|
return [2 /*return*/, result[0]['count']];
|
|
@@ -736,13 +858,19 @@ var Db = /** @class */ (function () {
|
|
|
736
858
|
/**
|
|
737
859
|
* Run a transaction.
|
|
738
860
|
*
|
|
739
|
-
*
|
|
740
|
-
*
|
|
741
|
-
*
|
|
742
|
-
*
|
|
861
|
+
* Db instances are STATELESS with respect to transactions: every operation resolves the
|
|
862
|
+
* ambient transaction (AsyncLocalStorage) at call time, so any Db instance used inside the
|
|
863
|
+
* transaction body — whenever it was constructed — rides the transaction. There is no way
|
|
864
|
+
* to issue an operation outside a transaction from inside its body, and no second session
|
|
865
|
+
* is ever acquired inside one (the historical pool-wedge class is unrepresentable —
|
|
866
|
+
* plans/DB_PERF_PLAN.md P2, in the consumer repo).
|
|
743
867
|
*
|
|
744
868
|
* Note: Nested transactions are not supported; will throw.
|
|
745
869
|
*
|
|
870
|
+
* Note: work spawned inside the body but NOT awaited by it escapes the transaction's
|
|
871
|
+
* lifetime while still holding its context — such work fails loudly on its next db
|
|
872
|
+
* operation (see TransactionContextData.ended). Await everything inside the body, or run
|
|
873
|
+
* it outside the transaction.
|
|
746
874
|
*
|
|
747
875
|
* Example:
|
|
748
876
|
*
|
|
@@ -759,46 +887,130 @@ var Db = /** @class */ (function () {
|
|
|
759
887
|
*/
|
|
760
888
|
Db.prototype.runTransaction = function (fn) {
|
|
761
889
|
return __awaiter(this, void 0, void 0, function () {
|
|
890
|
+
var postCommitHooks, result, _i, postCommitHooks_1, postCommitHook, error_1;
|
|
762
891
|
var _this = this;
|
|
763
892
|
return __generator(this, function (_a) {
|
|
764
893
|
switch (_a.label) {
|
|
765
894
|
case 0:
|
|
766
|
-
if (this.currentTransaction) {
|
|
767
|
-
throw new Error("Nested transactions are not supported. A transaction is already running
|
|
895
|
+
if (this.transactionContextFactory.getTransactionContext().currentTransaction) {
|
|
896
|
+
throw new Error("Nested transactions are not supported. A transaction is already running in this context.");
|
|
768
897
|
}
|
|
898
|
+
postCommitHooks = [];
|
|
769
899
|
return [4 /*yield*/, this.dbDriver.runTransaction(function (transaction) { return __awaiter(_this, void 0, void 0, function () {
|
|
770
|
-
var
|
|
900
|
+
var contextData;
|
|
771
901
|
return __generator(this, function (_a) {
|
|
772
902
|
switch (_a.label) {
|
|
773
903
|
case 0:
|
|
774
|
-
|
|
904
|
+
// A fresh ambient store per attempt: the transaction, the attempt's post-commit hook
|
|
905
|
+
// queue (shared by every Db instance created inside — see runAfterCommit), and the
|
|
906
|
+
// ended-tombstone below.
|
|
907
|
+
postCommitHooks = [];
|
|
908
|
+
contextData = { currentTransaction: transaction, postCommitHooks: postCommitHooks };
|
|
775
909
|
_a.label = 1;
|
|
776
910
|
case 1:
|
|
777
911
|
_a.trys.push([1, , 3, 4]);
|
|
778
|
-
return [4 /*yield*/, this.transactionContextFactory.runInContext(
|
|
779
|
-
var result;
|
|
780
|
-
return __generator(this, function (_a) {
|
|
781
|
-
switch (_a.label) {
|
|
782
|
-
case 0: return [4 /*yield*/, fn()];
|
|
783
|
-
case 1:
|
|
784
|
-
result = _a.sent();
|
|
785
|
-
return [2 /*return*/, result];
|
|
786
|
-
}
|
|
787
|
-
});
|
|
788
|
-
}); })];
|
|
912
|
+
return [4 /*yield*/, this.transactionContextFactory.runInContext(contextData, fn)];
|
|
789
913
|
case 2: return [2 /*return*/, _a.sent()];
|
|
790
914
|
case 3:
|
|
791
|
-
|
|
915
|
+
// Tombstone the store: detached work spawned inside the body still holds it by
|
|
916
|
+
// reference — the flag turns its next db operation into a loud error instead of a
|
|
917
|
+
// silent op on a finished transaction (see transactionForDriver).
|
|
918
|
+
contextData.ended = true;
|
|
792
919
|
return [7 /*endfinally*/];
|
|
793
920
|
case 4: return [2 /*return*/];
|
|
794
921
|
}
|
|
795
922
|
});
|
|
796
923
|
}); })];
|
|
797
|
-
case 1:
|
|
924
|
+
case 1:
|
|
925
|
+
result = _a.sent();
|
|
926
|
+
_i = 0, postCommitHooks_1 = postCommitHooks;
|
|
927
|
+
_a.label = 2;
|
|
928
|
+
case 2:
|
|
929
|
+
if (!(_i < postCommitHooks_1.length)) return [3 /*break*/, 7];
|
|
930
|
+
postCommitHook = postCommitHooks_1[_i];
|
|
931
|
+
_a.label = 3;
|
|
932
|
+
case 3:
|
|
933
|
+
_a.trys.push([3, 5, , 6]);
|
|
934
|
+
return [4 /*yield*/, postCommitHook()];
|
|
935
|
+
case 4:
|
|
936
|
+
_a.sent();
|
|
937
|
+
return [3 /*break*/, 6];
|
|
938
|
+
case 5:
|
|
939
|
+
error_1 = _a.sent();
|
|
940
|
+
this.logger.error({ message: "Post-commit hook failed", error: error_1 });
|
|
941
|
+
return [3 /*break*/, 6];
|
|
942
|
+
case 6:
|
|
943
|
+
_i++;
|
|
944
|
+
return [3 /*break*/, 2];
|
|
945
|
+
case 7: return [2 /*return*/, result];
|
|
946
|
+
}
|
|
947
|
+
});
|
|
948
|
+
});
|
|
949
|
+
};
|
|
950
|
+
/**
|
|
951
|
+
* Run `hook` once the write unit currently executing is durably committed.
|
|
952
|
+
*
|
|
953
|
+
* - Inside a `runTransaction` scope: the hook is queued on the ambient transaction context and
|
|
954
|
+
* runs after the transaction COMMITS. Hooks never run on rollback.
|
|
955
|
+
* - Outside a transaction: every DML statement auto-commits when it resolves, so the hook runs
|
|
956
|
+
* (awaited) immediately. Callers are responsible for invoking this only from points where
|
|
957
|
+
* the triggering statement has already executed — e.g. `after*` table watchers, never
|
|
958
|
+
* `before*` ones.
|
|
959
|
+
*
|
|
960
|
+
* For side effects that must observe committed truth — e.g. socket notifications that trigger
|
|
961
|
+
* client refetches: a pre-commit emission lets a client refetch read pre-commit rows and
|
|
962
|
+
* "resurrect" state the transaction is deleting.
|
|
963
|
+
*/
|
|
964
|
+
Db.prototype.runAfterCommit = function (hook) {
|
|
965
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
966
|
+
var transactionContext;
|
|
967
|
+
return __generator(this, function (_a) {
|
|
968
|
+
switch (_a.label) {
|
|
969
|
+
case 0:
|
|
970
|
+
transactionContext = this.transactionContextFactory.getTransactionContext();
|
|
971
|
+
if (transactionContext.currentTransaction) {
|
|
972
|
+
if (!transactionContext.postCommitHooks) {
|
|
973
|
+
// runTransaction is the only opener of transaction scopes and always seeds the queue —
|
|
974
|
+
// an active transaction without one means a second scope owner appeared. Fail loudly
|
|
975
|
+
// rather than run the hook at (wrong) pre-commit time.
|
|
976
|
+
throw new Error("Active transaction context has no post-commit hook queue. Transaction scopes must be opened via Db.runTransaction.");
|
|
977
|
+
}
|
|
978
|
+
transactionContext.postCommitHooks.push(hook);
|
|
979
|
+
return [2 /*return*/];
|
|
980
|
+
}
|
|
981
|
+
return [4 /*yield*/, hook()];
|
|
982
|
+
case 1:
|
|
983
|
+
_a.sent();
|
|
984
|
+
return [2 /*return*/];
|
|
798
985
|
}
|
|
799
986
|
});
|
|
800
987
|
});
|
|
801
988
|
};
|
|
989
|
+
/**
|
|
990
|
+
* A fresh instance for self-wrapping RMW verbs (`updateArrayMembership`, `updatePreserving`)
|
|
991
|
+
* in a transaction. `runTransaction` carries the open transaction as INSTANCE state, and these
|
|
992
|
+
* verbs also serve the `DbService` RPC path, where one long-lived Db instance handles
|
|
993
|
+
* concurrent requests — self-wrapping on `this` would leak one request's transaction into
|
|
994
|
+
* another's ops (or spuriously reject it as a nested transaction). Same driver/tables/system
|
|
995
|
+
* mode; only the transaction state is isolated.
|
|
996
|
+
*/
|
|
997
|
+
Db.prototype.newSelfWrapDb = function () {
|
|
998
|
+
return new Db(this.dbDriver, this.getTable, this.transactionContextFactory, this.runAsSystem);
|
|
999
|
+
};
|
|
1000
|
+
/**
|
|
1001
|
+
* The transaction every driver call rides, resolved from the ambient context AT CALL TIME
|
|
1002
|
+
* (statelessness is the safety property: operations inside a transaction body always ride
|
|
1003
|
+
* it; operations outside always use the pool). The one remaining failure shape — work that
|
|
1004
|
+
* escaped a finished transaction's body while holding its context — throws here by name;
|
|
1005
|
+
* handing the driver an ended transaction would fail anyway, with a far worse error.
|
|
1006
|
+
*/
|
|
1007
|
+
Db.prototype.transactionForDriver = function () {
|
|
1008
|
+
var context = this.transactionContextFactory.getTransactionContext();
|
|
1009
|
+
if (context.ended) {
|
|
1010
|
+
throw new Error("Db operation issued in the context of a transaction that already ended: work spawned inside a runTransaction body (and not awaited by it) survived the transaction. Await the work inside the body, or run it outside the transaction.");
|
|
1011
|
+
}
|
|
1012
|
+
return context.currentTransaction;
|
|
1013
|
+
};
|
|
802
1014
|
// Utility: simple chunker
|
|
803
1015
|
Db.prototype.chunk = function (arr, size) {
|
|
804
1016
|
if (size <= 0) {
|