@prisma-next/adapter-mongo 0.12.0 → 0.13.0-dev.2
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/control.d.mts +19 -67
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +158 -162
- package/dist/control.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{mongo-adapter-JuKx_-h9.d.mts → mongo-adapter-Ch21r_Sr.d.mts} +1 -1
- package/dist/mongo-adapter-Ch21r_Sr.d.mts.map +1 -0
- package/dist/{mongo-adapter-DAC5qq3o.mjs → mongo-adapter-ifsSo1o1.mjs} +1 -1
- package/dist/{mongo-adapter-DAC5qq3o.mjs.map → mongo-adapter-ifsSo1o1.mjs.map} +1 -1
- package/dist/runtime.mjs +1 -1
- package/package.json +27 -25
- package/src/core/marker-ledger-collection.ts +32 -0
- package/src/core/marker-ledger.ts +7 -215
- package/src/core/mongo-control-adapter.ts +234 -14
- package/src/core/mongo-control-driver.ts +11 -28
- package/src/core/runner-deps.ts +13 -10
- package/src/exports/control.ts +3 -11
- package/dist/mongo-adapter-JuKx_-h9.d.mts.map +0 -1
package/dist/control.d.mts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { t as createMongoAdapter } from "./mongo-adapter-
|
|
2
|
-
import { Db, Document
|
|
1
|
+
import { t as createMongoAdapter } from "./mongo-adapter-Ch21r_Sr.mjs";
|
|
2
|
+
import { Db, Document } from "mongodb";
|
|
3
3
|
import { CollModCommand, CreateCollectionCommand, CreateIndexCommand, DropCollectionCommand, DropIndexCommand, ListCollectionsCommand, ListIndexesCommand, MongoDdlCommandVisitor, MongoInspectionCommandVisitor } from "@prisma-next/mongo-query-ast/control";
|
|
4
4
|
import { MongoSchemaIR } from "@prisma-next/mongo-schema-ir";
|
|
5
5
|
import { MongoControlAdapter, MongoControlAdapterDescriptor } from "@prisma-next/family-mongo/control-adapter";
|
|
6
|
-
import {
|
|
6
|
+
import { MongoAdapter, MongoControlDriverInstance, MongoControlDriverInstance as MongoControlDriverInstance$1, MongoDriver } from "@prisma-next/mongo-lowering";
|
|
7
|
+
import { ContractMarkerRecord, LedgerEntryRecord } from "@prisma-next/contract/types";
|
|
7
8
|
import { ControlDriverInstance, ControlFamilyInstance } from "@prisma-next/framework-components/control";
|
|
8
|
-
import { MongoAdapter, MongoDriver } from "@prisma-next/mongo-lowering";
|
|
9
9
|
|
|
10
10
|
//#region src/core/command-executor.d.ts
|
|
11
11
|
declare class MongoCommandExecutor implements MongoDdlCommandVisitor<Promise<void>> {
|
|
@@ -27,70 +27,18 @@ declare class MongoInspectionExecutor implements MongoInspectionCommandVisitor<P
|
|
|
27
27
|
//#region src/core/introspect-schema.d.ts
|
|
28
28
|
declare function introspectSchema(db: Db): Promise<MongoSchemaIR>;
|
|
29
29
|
//#endregion
|
|
30
|
-
//#region src/core/marker-ledger.d.ts
|
|
31
|
-
/**
|
|
32
|
-
* Reads the marker document for the given contract space, or returns
|
|
33
|
-
* `null` if no marker has been written for that space yet. Each space
|
|
34
|
-
* owns one row keyed by `_id: <space>` — see ADR 212 for the per-space
|
|
35
|
-
* mechanism this enables.
|
|
36
|
-
*/
|
|
37
|
-
declare function readMarker(db: Db, space: string): Promise<ContractMarkerRecord | null>;
|
|
38
|
-
/**
|
|
39
|
-
* Reads every marker doc in the collection (one per contract space)
|
|
40
|
-
* and returns them keyed by `space`. Used by the per-space verifier
|
|
41
|
-
* to detect marker-vs-on-disk drift and orphan marker rows. Returns
|
|
42
|
-
* an empty map when no marker docs have been written yet.
|
|
43
|
-
*
|
|
44
|
-
* Marker docs are keyed by `_id: <space>` (string); ledger entries
|
|
45
|
-
* live in the same collection but use a driver-generated `ObjectId`
|
|
46
|
-
* `_id` plus `type: 'ledger'`. The filter selects string-keyed docs
|
|
47
|
-
* with a `space` field, which excludes ledger entries by construction.
|
|
48
|
-
*/
|
|
49
|
-
declare function readAllMarkers(db: Db): Promise<ReadonlyMap<string, ContractMarkerRecord>>;
|
|
50
|
-
declare function initMarker(db: Db, space: string, destination: {
|
|
51
|
-
readonly storageHash: string;
|
|
52
|
-
readonly profileHash: string;
|
|
53
|
-
readonly invariants?: readonly string[];
|
|
54
|
-
}): Promise<void>;
|
|
55
|
-
/**
|
|
56
|
-
* Updates the marker doc for the given space atomically (CAS on
|
|
57
|
-
* `expectedFrom`).
|
|
58
|
-
*
|
|
59
|
-
* `destination.invariants`:
|
|
60
|
-
* - `undefined` → existing field left untouched.
|
|
61
|
-
* - explicit value → merged into the existing field server-side via an
|
|
62
|
-
* aggregation pipeline (`$setUnion + $sortArray`), atomic at the
|
|
63
|
-
* document level. `[]` is a no-op merge.
|
|
64
|
-
*/
|
|
65
|
-
declare function updateMarker(db: Db, space: string, expectedFrom: string, destination: {
|
|
66
|
-
readonly storageHash: string;
|
|
67
|
-
readonly profileHash: string;
|
|
68
|
-
readonly invariants?: readonly string[];
|
|
69
|
-
}): Promise<boolean>;
|
|
70
|
-
/**
|
|
71
|
-
* Appends a ledger entry for the given space. Ledger entries co-exist
|
|
72
|
-
* with marker docs in the same collection; marker docs use `_id: <space>`
|
|
73
|
-
* (string), ledger entries use `type: 'ledger'` plus a driver-generated
|
|
74
|
-
* ObjectId. Reads partition the two by filter shape.
|
|
75
|
-
*
|
|
76
|
-
* The same `edgeId` may legitimately recur across different spaces (e.g.
|
|
77
|
-
* a synthetic ∅→head edge on first apply), so the ledger key is
|
|
78
|
-
* `(space, edgeId)` — the doc carries `space` for partitioned reads.
|
|
79
|
-
*/
|
|
80
|
-
declare function writeLedgerEntry(db: Db, space: string, entry: {
|
|
81
|
-
readonly edgeId: string;
|
|
82
|
-
readonly from: string;
|
|
83
|
-
readonly to: string;
|
|
84
|
-
}): Promise<void>;
|
|
85
|
-
//#endregion
|
|
86
30
|
//#region src/core/mongo-control-adapter.d.ts
|
|
87
31
|
/**
|
|
88
32
|
* Mongo control adapter for control-plane operations like introspection
|
|
89
33
|
* and marker-ledger CAS. Implements the family-level `MongoControlAdapter`
|
|
90
|
-
* SPI
|
|
91
|
-
*
|
|
34
|
+
* SPI. Every marker/ledger operation builds a canonical command inline via
|
|
35
|
+
* the contract-free fluent builder and dispatches it through the family
|
|
36
|
+
* adapter's lowering path (`createMongoAdapter().lower(plan, {})`) onto the
|
|
37
|
+
* Mongo wire transport (`driver.execute(wireCommand)`) — the same route SQL
|
|
38
|
+
* marker/ledger ops take through `adapter.lower()` → `driver.query()`.
|
|
92
39
|
*/
|
|
93
40
|
declare class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
41
|
+
#private;
|
|
94
42
|
readonly familyId: "mongo";
|
|
95
43
|
readonly targetId: "mongo";
|
|
96
44
|
readMarker(driver: ControlDriverInstance<'mongo', 'mongo'>, space: string): Promise<ContractMarkerRecord | null>;
|
|
@@ -109,15 +57,16 @@ declare class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
109
57
|
readonly edgeId: string;
|
|
110
58
|
readonly from: string;
|
|
111
59
|
readonly to: string;
|
|
60
|
+
readonly migrationName: string;
|
|
61
|
+
readonly migrationHash: string;
|
|
62
|
+
readonly operations: readonly unknown[];
|
|
112
63
|
}): Promise<void>;
|
|
64
|
+
readLedger(driver: ControlDriverInstance<'mongo', 'mongo'>, space?: string): Promise<readonly LedgerEntryRecord[]>;
|
|
113
65
|
introspectSchema(driver: ControlDriverInstance<'mongo', 'mongo'>): Promise<MongoSchemaIR>;
|
|
114
66
|
}
|
|
115
67
|
//#endregion
|
|
116
68
|
//#region src/core/mongo-control-driver.d.ts
|
|
117
|
-
|
|
118
|
-
readonly db: Db;
|
|
119
|
-
}
|
|
120
|
-
declare function createMongoControlDriver(db: Db, client: MongoClient): MongoControlDriverInstance;
|
|
69
|
+
declare function isMongoControlDriver(driver: ControlDriverInstance<'mongo', string>): driver is MongoControlDriverInstance$1;
|
|
121
70
|
//#endregion
|
|
122
71
|
//#region src/core/runner-deps.d.ts
|
|
123
72
|
declare function extractDb(driver: ControlDriverInstance<'mongo', 'mongo'>): Db;
|
|
@@ -143,6 +92,9 @@ interface MarkerOperations {
|
|
|
143
92
|
readonly edgeId: string;
|
|
144
93
|
readonly from: string;
|
|
145
94
|
readonly to: string;
|
|
95
|
+
readonly migrationName: string;
|
|
96
|
+
readonly migrationHash: string;
|
|
97
|
+
readonly operations: readonly unknown[];
|
|
146
98
|
}): Promise<void>;
|
|
147
99
|
}
|
|
148
100
|
interface MongoRunnerDependencies {
|
|
@@ -167,5 +119,5 @@ declare function createMongoRunnerDeps(controlDriver: ControlDriverInstance<'mon
|
|
|
167
119
|
//#region src/exports/control.d.ts
|
|
168
120
|
declare const mongoAdapterDescriptor: MongoControlAdapterDescriptor<'mongo'>;
|
|
169
121
|
//#endregion
|
|
170
|
-
export { type MarkerOperations, MongoCommandExecutor, MongoControlAdapterImpl, type MongoControlDriverInstance, MongoInspectionExecutor, type MongoRunnerDependencies, createMongoAdapter,
|
|
122
|
+
export { type MarkerOperations, MongoCommandExecutor, MongoControlAdapterImpl, type MongoControlDriverInstance, MongoInspectionExecutor, type MongoRunnerDependencies, createMongoAdapter, createMongoRunnerDeps, mongoAdapterDescriptor as default, mongoAdapterDescriptor, extractDb, introspectSchema, isMongoControlDriver };
|
|
171
123
|
//# sourceMappingURL=control.d.mts.map
|
package/dist/control.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/command-executor.ts","../src/core/introspect-schema.ts","../src/core/
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/command-executor.ts","../src/core/introspect-schema.ts","../src/core/mongo-control-adapter.ts","../src/core/mongo-control-driver.ts","../src/core/runner-deps.ts","../src/exports/control.ts"],"mappings":"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"}
|
package/dist/control.mjs
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { r as mongoCodecDescriptors, t as createMongoAdapter } from "./mongo-adapter-
|
|
2
|
-
import {
|
|
1
|
+
import { r as mongoCodecDescriptors, t as createMongoAdapter } from "./mongo-adapter-ifsSo1o1.mjs";
|
|
2
|
+
import { MongoAggFieldRef, MongoAggLiteral, MongoAggOperator } from "@prisma-next/mongo-query-ast/execution";
|
|
3
|
+
import { blindCast } from "@prisma-next/utils/casts";
|
|
3
4
|
import { MongoServerError } from "mongodb";
|
|
4
5
|
import { keysToKeySpec } from "@prisma-next/mongo-query-ast/control";
|
|
5
6
|
import { MongoSchemaCollection, MongoSchemaCollectionOptions, MongoSchemaIR, MongoSchemaIndex, MongoSchemaValidator } from "@prisma-next/mongo-schema-ir";
|
|
6
7
|
import { parseMarkerRowSafely, withMarkerReadErrorHandling } from "@prisma-next/errors/execution";
|
|
8
|
+
import { ledgerOriginFromStored } from "@prisma-next/migration-tools/ledger-origin";
|
|
9
|
+
import { expr, fn } from "@prisma-next/mongo-query-builder";
|
|
10
|
+
import { collection } from "@prisma-next/mongo-query-builder/contract-free";
|
|
7
11
|
import { type } from "arktype";
|
|
8
12
|
//#region src/core/command-executor.ts
|
|
9
13
|
var MongoCommandExecutor = class {
|
|
@@ -167,17 +171,7 @@ async function introspectSchema(db) {
|
|
|
167
171
|
//#region src/core/marker-ledger.ts
|
|
168
172
|
const COLLECTION = "_prisma_migrations";
|
|
169
173
|
const MONGO_MARKER_COLLECTION = `_prisma_migrations marker documents in ${COLLECTION}`;
|
|
170
|
-
|
|
171
|
-
* Marker doc shape.
|
|
172
|
-
*
|
|
173
|
-
* Same fields as the SQL marker row but camelCase + Mongo-native types:
|
|
174
|
-
* `Date` is BSON-hydrated, `meta` is a native object (not JSON-stringified),
|
|
175
|
-
* `_id` and any extension fields are tolerated. `invariants?` is optional —
|
|
176
|
-
* absent reads as `[]` (schemaless default); present-but-malformed throws.
|
|
177
|
-
*
|
|
178
|
-
* `space` is required: every marker doc is keyed by its space id (`_id`)
|
|
179
|
-
* and stamped with a matching `space` field for partitioned reads.
|
|
180
|
-
*/
|
|
174
|
+
const MONGO_LEDGER_COLLECTION = `_prisma_migrations ledger documents in ${COLLECTION}`;
|
|
181
175
|
const MongoMarkerDocSchema = type({
|
|
182
176
|
space: "string",
|
|
183
177
|
storageHash: "string",
|
|
@@ -210,130 +204,19 @@ function parseMongoMarkerDocSafely(doc, space) {
|
|
|
210
204
|
markerLocation: MONGO_MARKER_COLLECTION
|
|
211
205
|
});
|
|
212
206
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return db.collection(cmd.collection).findOneAndUpdate(cmd.filter, cmd.update, { upsert: cmd.upsert });
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Reads the marker document for the given contract space, or returns
|
|
224
|
-
* `null` if no marker has been written for that space yet. Each space
|
|
225
|
-
* owns one row keyed by `_id: <space>` — see ADR 212 for the per-space
|
|
226
|
-
* mechanism this enables.
|
|
227
|
-
*/
|
|
228
|
-
async function readMarker(db, space) {
|
|
229
|
-
const doc = (await withMarkerReadErrorHandling(() => executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: {
|
|
230
|
-
_id: space,
|
|
231
|
-
space
|
|
232
|
-
} }, { $limit: 1 }])), {
|
|
233
|
-
space,
|
|
234
|
-
markerLocation: MONGO_MARKER_COLLECTION
|
|
235
|
-
}))[0];
|
|
236
|
-
if (!doc) return null;
|
|
237
|
-
return parseMongoMarkerDocSafely(doc, space);
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Reads every marker doc in the collection (one per contract space)
|
|
241
|
-
* and returns them keyed by `space`. Used by the per-space verifier
|
|
242
|
-
* to detect marker-vs-on-disk drift and orphan marker rows. Returns
|
|
243
|
-
* an empty map when no marker docs have been written yet.
|
|
244
|
-
*
|
|
245
|
-
* Marker docs are keyed by `_id: <space>` (string); ledger entries
|
|
246
|
-
* live in the same collection but use a driver-generated `ObjectId`
|
|
247
|
-
* `_id` plus `type: 'ledger'`. The filter selects string-keyed docs
|
|
248
|
-
* with a `space` field, which excludes ledger entries by construction.
|
|
249
|
-
*/
|
|
250
|
-
async function readAllMarkers(db) {
|
|
251
|
-
const docs = await withMarkerReadErrorHandling(() => executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: {
|
|
252
|
-
_id: { $type: "string" },
|
|
253
|
-
space: { $type: "string" },
|
|
254
|
-
$expr: { $eq: ["$_id", "$space"] }
|
|
255
|
-
} }])), {
|
|
256
|
-
space: "app",
|
|
257
|
-
markerLocation: MONGO_MARKER_COLLECTION
|
|
258
|
-
});
|
|
259
|
-
const out = /* @__PURE__ */ new Map();
|
|
260
|
-
for (const doc of docs) {
|
|
261
|
-
const space = doc["space"];
|
|
262
|
-
/* v8 ignore next -- @preserve type-narrowing guard: the $match stage above filters on `space: { $type: 'string' }`, so this branch is unreachable at runtime. The check exists so the `out.set(space, ...)` call below can accept `string`. */
|
|
263
|
-
if (typeof space !== "string") continue;
|
|
264
|
-
out.set(space, parseMongoMarkerDocSafely(doc, space));
|
|
265
|
-
}
|
|
266
|
-
return out;
|
|
267
|
-
}
|
|
268
|
-
async function initMarker(db, space, destination) {
|
|
269
|
-
await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
|
|
270
|
-
_id: space,
|
|
271
|
-
space,
|
|
272
|
-
storageHash: destination.storageHash,
|
|
273
|
-
profileHash: destination.profileHash,
|
|
274
|
-
contractJson: null,
|
|
275
|
-
canonicalVersion: null,
|
|
276
|
-
updatedAt: /* @__PURE__ */ new Date(),
|
|
277
|
-
appTag: null,
|
|
278
|
-
meta: {},
|
|
279
|
-
invariants: destination.invariants ?? []
|
|
280
|
-
}));
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Updates the marker doc for the given space atomically (CAS on
|
|
284
|
-
* `expectedFrom`).
|
|
285
|
-
*
|
|
286
|
-
* `destination.invariants`:
|
|
287
|
-
* - `undefined` → existing field left untouched.
|
|
288
|
-
* - explicit value → merged into the existing field server-side via an
|
|
289
|
-
* aggregation pipeline (`$setUnion + $sortArray`), atomic at the
|
|
290
|
-
* document level. `[]` is a no-op merge.
|
|
291
|
-
*/
|
|
292
|
-
async function updateMarker(db, space, expectedFrom, destination) {
|
|
293
|
-
const setBase = {
|
|
294
|
-
storageHash: destination.storageHash,
|
|
295
|
-
profileHash: destination.profileHash,
|
|
296
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
297
|
-
};
|
|
298
|
-
const update = destination.invariants === void 0 ? { $set: setBase } : [{ $set: {
|
|
299
|
-
...setBase,
|
|
300
|
-
invariants: { $sortArray: {
|
|
301
|
-
input: { $setUnion: [{ $ifNull: ["$invariants", []] }, destination.invariants] },
|
|
302
|
-
sortBy: 1
|
|
303
|
-
} }
|
|
304
|
-
} }];
|
|
305
|
-
return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
|
|
306
|
-
_id: space,
|
|
307
|
-
space,
|
|
308
|
-
storageHash: expectedFrom
|
|
309
|
-
}, update, false)) !== null;
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Appends a ledger entry for the given space. Ledger entries co-exist
|
|
313
|
-
* with marker docs in the same collection; marker docs use `_id: <space>`
|
|
314
|
-
* (string), ledger entries use `type: 'ledger'` plus a driver-generated
|
|
315
|
-
* ObjectId. Reads partition the two by filter shape.
|
|
316
|
-
*
|
|
317
|
-
* The same `edgeId` may legitimately recur across different spaces (e.g.
|
|
318
|
-
* a synthetic ∅→head edge on first apply), so the ledger key is
|
|
319
|
-
* `(space, edgeId)` — the doc carries `space` for partitioned reads.
|
|
320
|
-
*/
|
|
321
|
-
async function writeLedgerEntry(db, space, entry) {
|
|
322
|
-
await executeInsertOne(db, new RawInsertOneCommand(COLLECTION, {
|
|
323
|
-
type: "ledger",
|
|
324
|
-
space,
|
|
325
|
-
edgeId: entry.edgeId,
|
|
326
|
-
from: entry.from,
|
|
327
|
-
to: entry.to,
|
|
328
|
-
appliedAt: /* @__PURE__ */ new Date()
|
|
329
|
-
}));
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/core/marker-ledger-collection.ts
|
|
209
|
+
const MARKER_LEDGER_COLLECTION = "_prisma_migrations";
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/core/mongo-control-driver.ts
|
|
212
|
+
function isMongoControlDriver(driver) {
|
|
213
|
+
return driver.familyId === "mongo" && driver.targetId === "mongo" && "execute" in driver && typeof driver.execute === "function";
|
|
330
214
|
}
|
|
331
215
|
//#endregion
|
|
332
216
|
//#region src/core/runner-deps.ts
|
|
333
217
|
function extractDb(driver) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return mongoDriver.db;
|
|
218
|
+
if (!isMongoControlDriver(driver)) throw new Error("Expected a Mongo control driver created by mongoControlDriver.create() from `@prisma-next/driver-mongo/control`.");
|
|
219
|
+
return driver.db;
|
|
337
220
|
}
|
|
338
221
|
/**
|
|
339
222
|
* Build the runner-dependencies envelope. `controlAdapter` is the
|
|
@@ -364,53 +247,166 @@ function createMongoRunnerDeps(controlDriver, driver, _family, controlAdapter =
|
|
|
364
247
|
/**
|
|
365
248
|
* Mongo control adapter for control-plane operations like introspection
|
|
366
249
|
* and marker-ledger CAS. Implements the family-level `MongoControlAdapter`
|
|
367
|
-
* SPI
|
|
368
|
-
*
|
|
250
|
+
* SPI. Every marker/ledger operation builds a canonical command inline via
|
|
251
|
+
* the contract-free fluent builder and dispatches it through the family
|
|
252
|
+
* adapter's lowering path (`createMongoAdapter().lower(plan, {})`) onto the
|
|
253
|
+
* Mongo wire transport (`driver.execute(wireCommand)`) — the same route SQL
|
|
254
|
+
* marker/ledger ops take through `adapter.lower()` → `driver.query()`.
|
|
369
255
|
*/
|
|
370
256
|
var MongoControlAdapterImpl = class {
|
|
371
257
|
familyId = "mongo";
|
|
372
258
|
targetId = "mongo";
|
|
259
|
+
#adapter = createMongoAdapter();
|
|
260
|
+
#markerLedgerCollection = collection(MARKER_LEDGER_COLLECTION);
|
|
261
|
+
async #execute(driver, command) {
|
|
262
|
+
const plan = {
|
|
263
|
+
collection: MARKER_LEDGER_COLLECTION,
|
|
264
|
+
command,
|
|
265
|
+
meta: {
|
|
266
|
+
target: "mongo",
|
|
267
|
+
targetFamily: "mongo",
|
|
268
|
+
storageHash: "",
|
|
269
|
+
lane: "control"
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
const wireCommand = await this.#adapter.lower(plan, {});
|
|
273
|
+
if (!isMongoControlDriver(driver)) throw new Error("Mongo control adapter requires a Mongo control driver with an execute() transport. Provide a MongoControlDriver from `@prisma-next/driver-mongo/control`.");
|
|
274
|
+
const rows = [];
|
|
275
|
+
for await (const row of driver.execute(wireCommand)) rows.push(row);
|
|
276
|
+
return rows;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Server-side invariant-merge aggregation expression:
|
|
280
|
+
* `$sortArray({ input: $setUnion([$ifNull('$invariants', []), incoming]), sortBy: 1 })`.
|
|
281
|
+
*
|
|
282
|
+
* Built through the typed agg-expr layer — `fn.setUnion` plus the generic
|
|
283
|
+
* `MongoAggOperator` for `$ifNull` / `$sortArray` (neither has a named `fn`
|
|
284
|
+
* helper). Returns a `MongoAggOperator` that is passed directly to
|
|
285
|
+
* `f.stage.set({ invariants: ... })` in the update pipeline.
|
|
286
|
+
*/
|
|
287
|
+
#invariantMergeExpr(incoming) {
|
|
288
|
+
const existingOrEmpty = MongoAggOperator.of("$ifNull", [MongoAggFieldRef.of("invariants"), MongoAggLiteral.of([])]);
|
|
289
|
+
const merged = fn.setUnion({
|
|
290
|
+
_field: {
|
|
291
|
+
codecId: "mongo/array@1",
|
|
292
|
+
nullable: false
|
|
293
|
+
},
|
|
294
|
+
node: existingOrEmpty
|
|
295
|
+
}, {
|
|
296
|
+
_field: {
|
|
297
|
+
codecId: "mongo/array@1",
|
|
298
|
+
nullable: false
|
|
299
|
+
},
|
|
300
|
+
node: MongoAggLiteral.of([...incoming])
|
|
301
|
+
});
|
|
302
|
+
return MongoAggOperator.of("$sortArray", {
|
|
303
|
+
input: merged.node,
|
|
304
|
+
sortBy: MongoAggLiteral.of(1)
|
|
305
|
+
});
|
|
306
|
+
}
|
|
373
307
|
async readMarker(driver, space) {
|
|
374
|
-
|
|
308
|
+
const doc = (await withMarkerReadErrorHandling(() => this.#execute(driver, this.#markerLedgerCollection.aggregate().match((f) => f._id.eq(space)).match((f) => f.space.eq(space)).limit(1).build()), {
|
|
309
|
+
space,
|
|
310
|
+
markerLocation: MONGO_MARKER_COLLECTION
|
|
311
|
+
}))[0];
|
|
312
|
+
if (!doc) return null;
|
|
313
|
+
return parseMongoMarkerDocSafely(doc, space);
|
|
375
314
|
}
|
|
376
315
|
async readAllMarkers(driver) {
|
|
377
|
-
|
|
316
|
+
const docs = await withMarkerReadErrorHandling(() => this.#execute(driver, this.#markerLedgerCollection.aggregate().match((f) => f._id.type("string")).match((f) => f.space.type("string")).match((f) => expr(fn.eq(f._id, f.space))).build()), {
|
|
317
|
+
space: "app",
|
|
318
|
+
markerLocation: MONGO_MARKER_COLLECTION
|
|
319
|
+
});
|
|
320
|
+
const out = /* @__PURE__ */ new Map();
|
|
321
|
+
for (const doc of docs) {
|
|
322
|
+
const space = doc["space"];
|
|
323
|
+
/* v8 ignore next -- @preserve type-narrowing guard: the $match stage above filters on `space: { $type: 'string' }`, so this branch is unreachable at runtime. The check exists so the `out.set(space, ...)` call below can accept `string`. */
|
|
324
|
+
if (typeof space !== "string") continue;
|
|
325
|
+
out.set(space, parseMongoMarkerDocSafely(doc, space));
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
378
328
|
}
|
|
379
329
|
async initMarker(driver, space, destination) {
|
|
380
|
-
|
|
330
|
+
const document = {
|
|
331
|
+
_id: space,
|
|
332
|
+
space,
|
|
333
|
+
storageHash: destination.storageHash,
|
|
334
|
+
profileHash: destination.profileHash,
|
|
335
|
+
contractJson: null,
|
|
336
|
+
canonicalVersion: null,
|
|
337
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
338
|
+
appTag: null,
|
|
339
|
+
meta: {},
|
|
340
|
+
invariants: [...destination.invariants ?? []]
|
|
341
|
+
};
|
|
342
|
+
await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));
|
|
381
343
|
}
|
|
382
344
|
async updateMarker(driver, space, expectedFrom, destination) {
|
|
383
|
-
|
|
345
|
+
const { invariants } = destination;
|
|
346
|
+
return (await this.#execute(driver, this.#markerLedgerCollection.match((f) => f._id.eq(space)).match((f) => f.space.eq(space)).match((f) => f.storageHash.eq(expectedFrom)).findOneAndUpdate((f) => [f.stage.set(invariants === void 0 ? {
|
|
347
|
+
storageHash: MongoAggLiteral.of(destination.storageHash),
|
|
348
|
+
profileHash: MongoAggLiteral.of(destination.profileHash),
|
|
349
|
+
updatedAt: MongoAggLiteral.of(/* @__PURE__ */ new Date())
|
|
350
|
+
} : {
|
|
351
|
+
storageHash: MongoAggLiteral.of(destination.storageHash),
|
|
352
|
+
profileHash: MongoAggLiteral.of(destination.profileHash),
|
|
353
|
+
updatedAt: MongoAggLiteral.of(/* @__PURE__ */ new Date()),
|
|
354
|
+
invariants: this.#invariantMergeExpr(invariants)
|
|
355
|
+
})], { upsert: false }))).length > 0;
|
|
384
356
|
}
|
|
385
357
|
async writeLedgerEntry(driver, space, entry) {
|
|
386
|
-
|
|
358
|
+
const document = {
|
|
359
|
+
type: "ledger",
|
|
360
|
+
space,
|
|
361
|
+
edgeId: entry.edgeId,
|
|
362
|
+
from: entry.from,
|
|
363
|
+
to: entry.to,
|
|
364
|
+
migrationName: entry.migrationName,
|
|
365
|
+
migrationHash: entry.migrationHash,
|
|
366
|
+
operations: blindCast(entry.operations),
|
|
367
|
+
appliedAt: /* @__PURE__ */ new Date()
|
|
368
|
+
};
|
|
369
|
+
await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));
|
|
370
|
+
}
|
|
371
|
+
async readLedger(driver, space) {
|
|
372
|
+
const ledgerContext = {
|
|
373
|
+
space: space ?? "*",
|
|
374
|
+
markerLocation: MONGO_LEDGER_COLLECTION
|
|
375
|
+
};
|
|
376
|
+
const chain = this.#markerLedgerCollection.aggregate().match((f) => f.type.eq("ledger"));
|
|
377
|
+
const command = space === void 0 ? chain.sort({ _id: 1 }).build() : chain.match((f) => f.space.eq(space)).sort({ _id: 1 }).build();
|
|
378
|
+
const docs = await withMarkerReadErrorHandling(() => this.#execute(driver, command), ledgerContext);
|
|
379
|
+
const entries = [];
|
|
380
|
+
for (const doc of docs) {
|
|
381
|
+
const migrationName = doc["migrationName"];
|
|
382
|
+
const migrationHash = doc["migrationHash"];
|
|
383
|
+
const from = doc["from"];
|
|
384
|
+
const to = doc["to"];
|
|
385
|
+
const docSpace = doc["space"];
|
|
386
|
+
if (typeof migrationName !== "string" || typeof migrationHash !== "string") continue;
|
|
387
|
+
if (typeof from !== "string" || typeof to !== "string") continue;
|
|
388
|
+
if (typeof docSpace !== "string") continue;
|
|
389
|
+
const appliedAt = doc["appliedAt"];
|
|
390
|
+
const appliedAtDate = appliedAt instanceof Date ? appliedAt : appliedAt !== void 0 ? new Date(String(appliedAt)) : /* @__PURE__ */ new Date();
|
|
391
|
+
const operations = doc["operations"];
|
|
392
|
+
const opList = Array.isArray(operations) ? operations : [];
|
|
393
|
+
entries.push({
|
|
394
|
+
space: docSpace,
|
|
395
|
+
migrationName,
|
|
396
|
+
migrationHash,
|
|
397
|
+
from: ledgerOriginFromStored(from),
|
|
398
|
+
to,
|
|
399
|
+
appliedAt: appliedAtDate,
|
|
400
|
+
operationCount: opList.length
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return entries;
|
|
387
404
|
}
|
|
388
405
|
async introspectSchema(driver) {
|
|
389
406
|
return introspectSchema(extractDb(driver));
|
|
390
407
|
}
|
|
391
408
|
};
|
|
392
409
|
//#endregion
|
|
393
|
-
//#region src/core/mongo-control-driver.ts
|
|
394
|
-
var MongoControlDriverImpl = class {
|
|
395
|
-
familyId = "mongo";
|
|
396
|
-
targetId = "mongo";
|
|
397
|
-
db;
|
|
398
|
-
#client;
|
|
399
|
-
constructor(db, client) {
|
|
400
|
-
this.db = db;
|
|
401
|
-
this.#client = client;
|
|
402
|
-
}
|
|
403
|
-
query() {
|
|
404
|
-
throw new Error("MongoDB control driver does not support SQL queries");
|
|
405
|
-
}
|
|
406
|
-
async close() {
|
|
407
|
-
await this.#client.close();
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
function createMongoControlDriver(db, client) {
|
|
411
|
-
return new MongoControlDriverImpl(db, client);
|
|
412
|
-
}
|
|
413
|
-
//#endregion
|
|
414
410
|
//#region src/exports/control.ts
|
|
415
411
|
const mongoAdapterDescriptor = {
|
|
416
412
|
kind: "adapter",
|
|
@@ -444,6 +440,6 @@ const mongoAdapterDescriptor = {
|
|
|
444
440
|
}
|
|
445
441
|
};
|
|
446
442
|
//#endregion
|
|
447
|
-
export { MongoCommandExecutor, MongoControlAdapterImpl, MongoInspectionExecutor, createMongoAdapter,
|
|
443
|
+
export { MongoCommandExecutor, MongoControlAdapterImpl, MongoInspectionExecutor, createMongoAdapter, createMongoRunnerDeps, mongoAdapterDescriptor as default, mongoAdapterDescriptor, extractDb, introspectSchema, isMongoControlDriver };
|
|
448
444
|
|
|
449
445
|
//# sourceMappingURL=control.mjs.map
|