@prisma-next/adapter-mongo 0.12.0-dev.50 → 0.12.0-dev.51
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 +8 -25
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +86 -80
- package/dist/control.mjs.map +1 -1
- package/package.json +24 -22
- package/src/core/marker-ledger-collection.ts +32 -0
- package/src/core/marker-ledger.ts +1 -29
- package/src/core/mongo-control-adapter.ts +128 -75
- package/src/core/mongo-control-driver.ts +6 -1
- package/src/exports/control.ts +2 -72
package/dist/control.d.mts
CHANGED
|
@@ -2,9 +2,9 @@ import { t as createMongoAdapter } from "./mongo-adapter-JuKx_-h9.mjs";
|
|
|
2
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
|
-
import { ContractMarkerRecord, LedgerEntryRecord } from "@prisma-next/contract/types";
|
|
6
5
|
import { MongoControlAdapter, MongoControlAdapterDescriptor } from "@prisma-next/family-mongo/control-adapter";
|
|
7
6
|
import { MongoAdapter, MongoControlDriverInstance, MongoControlDriverInstance as MongoControlDriverInstance$1, MongoDriver } from "@prisma-next/mongo-lowering";
|
|
7
|
+
import { ContractMarkerRecord, LedgerEntryRecord } from "@prisma-next/contract/types";
|
|
8
8
|
import { ControlDriverInstance, ControlFamilyInstance } from "@prisma-next/framework-components/control";
|
|
9
9
|
|
|
10
10
|
//#region src/core/command-executor.d.ts
|
|
@@ -31,10 +31,14 @@ declare function introspectSchema(db: Db): Promise<MongoSchemaIR>;
|
|
|
31
31
|
/**
|
|
32
32
|
* Mongo control adapter for control-plane operations like introspection
|
|
33
33
|
* and marker-ledger CAS. Implements the family-level `MongoControlAdapter`
|
|
34
|
-
* SPI
|
|
35
|
-
*
|
|
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()`.
|
|
36
39
|
*/
|
|
37
40
|
declare class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
41
|
+
#private;
|
|
38
42
|
readonly familyId: "mongo";
|
|
39
43
|
readonly targetId: "mongo";
|
|
40
44
|
readMarker(driver: ControlDriverInstance<'mongo', 'mongo'>, space: string): Promise<ContractMarkerRecord | null>;
|
|
@@ -113,28 +117,7 @@ interface MongoRunnerDependencies {
|
|
|
113
117
|
declare function createMongoRunnerDeps(controlDriver: ControlDriverInstance<'mongo', 'mongo'>, driver: MongoDriver, _family: ControlFamilyInstance<'mongo', MongoSchemaIR>, controlAdapter?: MongoControlAdapter<'mongo'>): MongoRunnerDependencies;
|
|
114
118
|
//#endregion
|
|
115
119
|
//#region src/exports/control.d.ts
|
|
116
|
-
declare function readMarker(db: Db, space: string): Promise<ContractMarkerRecord | null>;
|
|
117
|
-
declare function readAllMarkers(db: Db): Promise<ReadonlyMap<string, ContractMarkerRecord>>;
|
|
118
|
-
declare function initMarker(db: Db, space: string, destination: {
|
|
119
|
-
readonly storageHash: string;
|
|
120
|
-
readonly profileHash: string;
|
|
121
|
-
readonly invariants?: readonly string[];
|
|
122
|
-
}): Promise<void>;
|
|
123
|
-
declare function updateMarker(db: Db, space: string, expectedFrom: string, destination: {
|
|
124
|
-
readonly storageHash: string;
|
|
125
|
-
readonly profileHash: string;
|
|
126
|
-
readonly invariants?: readonly string[];
|
|
127
|
-
}): Promise<boolean>;
|
|
128
|
-
declare function readLedger(db: Db, space?: string): Promise<readonly LedgerEntryRecord[]>;
|
|
129
|
-
declare function writeLedgerEntry(db: Db, space: string, entry: {
|
|
130
|
-
readonly edgeId: string;
|
|
131
|
-
readonly from: string;
|
|
132
|
-
readonly to: string;
|
|
133
|
-
readonly migrationName: string;
|
|
134
|
-
readonly migrationHash: string;
|
|
135
|
-
readonly operations: readonly unknown[];
|
|
136
|
-
}): Promise<void>;
|
|
137
120
|
declare const mongoAdapterDescriptor: MongoControlAdapterDescriptor<'mongo'>;
|
|
138
121
|
//#endregion
|
|
139
|
-
export { type MarkerOperations, MongoCommandExecutor, MongoControlAdapterImpl, type MongoControlDriverInstance, MongoInspectionExecutor, type MongoRunnerDependencies, createMongoAdapter, createMongoRunnerDeps, mongoAdapterDescriptor as default, mongoAdapterDescriptor, extractDb,
|
|
122
|
+
export { type MarkerOperations, MongoCommandExecutor, MongoControlAdapterImpl, type MongoControlDriverInstance, MongoInspectionExecutor, type MongoRunnerDependencies, createMongoAdapter, createMongoRunnerDeps, mongoAdapterDescriptor as default, mongoAdapterDescriptor, extractDb, introspectSchema, isMongoControlDriver };
|
|
140
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/mongo-control-adapter.ts","../src/core/mongo-control-driver.ts","../src/core/runner-deps.ts","../src/exports/control.ts"],"mappings":";;;;;;;;;;cAca,oBAAA,YAAgC,sBAAA,CAAuB,OAAA;EAAA,iBACrC,EAAA;cAAA,EAAA,EAAI,EAAA;EAE3B,WAAA,CAAY,GAAA,EAAK,kBAAA,GAAqB,OAAA;EAmBtC,SAAA,CAAU,GAAA,EAAK,gBAAA,GAAmB,OAAA;EAIlC,gBAAA,CAAiB,GAAA,EAAK,uBAAA,GAA0B,OAAA;EAgBhD,cAAA,CAAe,GAAA,EAAK,qBAAA,GAAwB,OAAA;EAI5C,OAAA,CAAQ,GAAA,EAAK,cAAA,GAAiB,OAAA;AAAA;AAAA,cAWzB,uBAAA,YAAmC,6BAAA,CAA8B,OAAA,CAAQ,QAAA;EAAA,iBACvD,EAAA;cAAA,EAAA,EAAI,EAAA;EAE3B,WAAA,CAAY,GAAA,EAAK,kBAAA,GAAqB,OAAA,CAAQ,QAAA;EAW9C,eAAA,CAAgB,IAAA,EAAM,sBAAA,GAAyB,OAAA,CAAQ,QAAA;AAAA;;;iBCMzC,gBAAA,CAAiB,EAAA,EAAI,EAAA,GAAK,OAAA,CAAQ,aAAA;;;;;;;;;
|
|
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,10 +1,13 @@
|
|
|
1
1
|
import { r as mongoCodecDescriptors, t as createMongoAdapter } from "./mongo-adapter-DAC5qq3o.mjs";
|
|
2
|
-
import {
|
|
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";
|
|
7
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";
|
|
8
11
|
import { type } from "arktype";
|
|
9
12
|
//#region src/core/command-executor.ts
|
|
10
13
|
var MongoCommandExecutor = class {
|
|
@@ -201,19 +204,13 @@ function parseMongoMarkerDocSafely(doc, space) {
|
|
|
201
204
|
markerLocation: MONGO_MARKER_COLLECTION
|
|
202
205
|
});
|
|
203
206
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
async function executeInsertOne(db, cmd) {
|
|
208
|
-
await db.collection(cmd.collection).insertOne(cmd.document);
|
|
209
|
-
}
|
|
210
|
-
async function executeFindOneAndUpdate(db, cmd) {
|
|
211
|
-
return db.collection(cmd.collection).findOneAndUpdate(cmd.filter, cmd.update, { upsert: cmd.upsert });
|
|
212
|
-
}
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/core/marker-ledger-collection.ts
|
|
209
|
+
const MARKER_LEDGER_COLLECTION = "_prisma_migrations";
|
|
213
210
|
//#endregion
|
|
214
211
|
//#region src/core/mongo-control-driver.ts
|
|
215
212
|
function isMongoControlDriver(driver) {
|
|
216
|
-
return driver.familyId === "mongo" && driver.targetId === "mongo";
|
|
213
|
+
return driver.familyId === "mongo" && driver.targetId === "mongo" && "execute" in driver && typeof driver.execute === "function";
|
|
217
214
|
}
|
|
218
215
|
//#endregion
|
|
219
216
|
//#region src/core/runner-deps.ts
|
|
@@ -250,18 +247,65 @@ function createMongoRunnerDeps(controlDriver, driver, _family, controlAdapter =
|
|
|
250
247
|
/**
|
|
251
248
|
* Mongo control adapter for control-plane operations like introspection
|
|
252
249
|
* and marker-ledger CAS. Implements the family-level `MongoControlAdapter`
|
|
253
|
-
* SPI
|
|
254
|
-
*
|
|
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()`.
|
|
255
255
|
*/
|
|
256
256
|
var MongoControlAdapterImpl = class {
|
|
257
257
|
familyId = "mongo";
|
|
258
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
|
+
}
|
|
259
307
|
async readMarker(driver, space) {
|
|
260
|
-
const
|
|
261
|
-
const doc = (await withMarkerReadErrorHandling(() => executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: {
|
|
262
|
-
_id: space,
|
|
263
|
-
space
|
|
264
|
-
} }, { $limit: 1 }])), {
|
|
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()), {
|
|
265
309
|
space,
|
|
266
310
|
markerLocation: MONGO_MARKER_COLLECTION
|
|
267
311
|
}))[0];
|
|
@@ -269,12 +313,7 @@ var MongoControlAdapterImpl = class {
|
|
|
269
313
|
return parseMongoMarkerDocSafely(doc, space);
|
|
270
314
|
}
|
|
271
315
|
async readAllMarkers(driver) {
|
|
272
|
-
const
|
|
273
|
-
const docs = await withMarkerReadErrorHandling(() => executeAggregate(db, new RawAggregateCommand(COLLECTION, [{ $match: {
|
|
274
|
-
_id: { $type: "string" },
|
|
275
|
-
space: { $type: "string" },
|
|
276
|
-
$expr: { $eq: ["$_id", "$space"] }
|
|
277
|
-
} }])), {
|
|
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()), {
|
|
278
317
|
space: "app",
|
|
279
318
|
markerLocation: MONGO_MARKER_COLLECTION
|
|
280
319
|
});
|
|
@@ -288,7 +327,7 @@ var MongoControlAdapterImpl = class {
|
|
|
288
327
|
return out;
|
|
289
328
|
}
|
|
290
329
|
async initMarker(driver, space, destination) {
|
|
291
|
-
|
|
330
|
+
const document = {
|
|
292
331
|
_id: space,
|
|
293
332
|
space,
|
|
294
333
|
storageHash: destination.storageHash,
|
|
@@ -298,31 +337,25 @@ var MongoControlAdapterImpl = class {
|
|
|
298
337
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
299
338
|
appTag: null,
|
|
300
339
|
meta: {},
|
|
301
|
-
invariants: destination.invariants ?? []
|
|
302
|
-
}
|
|
340
|
+
invariants: [...destination.invariants ?? []]
|
|
341
|
+
};
|
|
342
|
+
await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));
|
|
303
343
|
}
|
|
304
344
|
async updateMarker(driver, space, expectedFrom, destination) {
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
storageHash: destination.storageHash,
|
|
308
|
-
profileHash: destination.profileHash,
|
|
309
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
} }
|
|
317
|
-
} }];
|
|
318
|
-
return await executeFindOneAndUpdate(db, new RawFindOneAndUpdateCommand(COLLECTION, {
|
|
319
|
-
_id: space,
|
|
320
|
-
space,
|
|
321
|
-
storageHash: expectedFrom
|
|
322
|
-
}, update, false)) !== null;
|
|
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;
|
|
323
356
|
}
|
|
324
357
|
async writeLedgerEntry(driver, space, entry) {
|
|
325
|
-
|
|
358
|
+
const document = {
|
|
326
359
|
type: "ledger",
|
|
327
360
|
space,
|
|
328
361
|
edgeId: entry.edgeId,
|
|
@@ -330,19 +363,19 @@ var MongoControlAdapterImpl = class {
|
|
|
330
363
|
to: entry.to,
|
|
331
364
|
migrationName: entry.migrationName,
|
|
332
365
|
migrationHash: entry.migrationHash,
|
|
333
|
-
operations: entry.operations,
|
|
366
|
+
operations: blindCast(entry.operations),
|
|
334
367
|
appliedAt: /* @__PURE__ */ new Date()
|
|
335
|
-
}
|
|
368
|
+
};
|
|
369
|
+
await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));
|
|
336
370
|
}
|
|
337
371
|
async readLedger(driver, space) {
|
|
338
|
-
const db = extractDb(driver);
|
|
339
372
|
const ledgerContext = {
|
|
340
373
|
space: space ?? "*",
|
|
341
374
|
markerLocation: MONGO_LEDGER_COLLECTION
|
|
342
375
|
};
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
const docs = await withMarkerReadErrorHandling(() =>
|
|
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);
|
|
346
379
|
const entries = [];
|
|
347
380
|
for (const doc of docs) {
|
|
348
381
|
const migrationName = doc["migrationName"];
|
|
@@ -375,33 +408,6 @@ var MongoControlAdapterImpl = class {
|
|
|
375
408
|
};
|
|
376
409
|
//#endregion
|
|
377
410
|
//#region src/exports/control.ts
|
|
378
|
-
const defaultControlAdapter = new MongoControlAdapterImpl();
|
|
379
|
-
function controlDriverFromDb(db) {
|
|
380
|
-
return {
|
|
381
|
-
familyId: "mongo",
|
|
382
|
-
targetId: "mongo",
|
|
383
|
-
db,
|
|
384
|
-
close: async () => {}
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
async function readMarker(db, space) {
|
|
388
|
-
return defaultControlAdapter.readMarker(controlDriverFromDb(db), space);
|
|
389
|
-
}
|
|
390
|
-
async function readAllMarkers(db) {
|
|
391
|
-
return defaultControlAdapter.readAllMarkers(controlDriverFromDb(db));
|
|
392
|
-
}
|
|
393
|
-
async function initMarker(db, space, destination) {
|
|
394
|
-
await defaultControlAdapter.initMarker(controlDriverFromDb(db), space, destination);
|
|
395
|
-
}
|
|
396
|
-
async function updateMarker(db, space, expectedFrom, destination) {
|
|
397
|
-
return defaultControlAdapter.updateMarker(controlDriverFromDb(db), space, expectedFrom, destination);
|
|
398
|
-
}
|
|
399
|
-
async function readLedger(db, space) {
|
|
400
|
-
return defaultControlAdapter.readLedger(controlDriverFromDb(db), space);
|
|
401
|
-
}
|
|
402
|
-
async function writeLedgerEntry(db, space, entry) {
|
|
403
|
-
await defaultControlAdapter.writeLedgerEntry(controlDriverFromDb(db), space, entry);
|
|
404
|
-
}
|
|
405
411
|
const mongoAdapterDescriptor = {
|
|
406
412
|
kind: "adapter",
|
|
407
413
|
id: "mongo",
|
|
@@ -434,6 +440,6 @@ const mongoAdapterDescriptor = {
|
|
|
434
440
|
}
|
|
435
441
|
};
|
|
436
442
|
//#endregion
|
|
437
|
-
export { MongoCommandExecutor, MongoControlAdapterImpl, MongoInspectionExecutor, createMongoAdapter, createMongoRunnerDeps, mongoAdapterDescriptor as default, mongoAdapterDescriptor, extractDb,
|
|
443
|
+
export { MongoCommandExecutor, MongoControlAdapterImpl, MongoInspectionExecutor, createMongoAdapter, createMongoRunnerDeps, mongoAdapterDescriptor as default, mongoAdapterDescriptor, extractDb, introspectSchema, isMongoControlDriver };
|
|
438
444
|
|
|
439
445
|
//# sourceMappingURL=control.mjs.map
|
package/dist/control.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.mjs","names":[],"sources":["../src/core/command-executor.ts","../src/core/introspect-schema.ts","../src/core/marker-ledger.ts","../src/core/mongo-control-driver.ts","../src/core/runner-deps.ts","../src/core/mongo-control-adapter.ts","../src/exports/control.ts"],"sourcesContent":["import type {\n CollModCommand,\n CreateCollectionCommand,\n CreateIndexCommand,\n DropCollectionCommand,\n DropIndexCommand,\n ListCollectionsCommand,\n ListIndexesCommand,\n MongoDdlCommandVisitor,\n MongoInspectionCommandVisitor,\n} from '@prisma-next/mongo-query-ast/control';\nimport { keysToKeySpec } from '@prisma-next/mongo-query-ast/control';\nimport { type Db, type Document, MongoServerError } from 'mongodb';\n\nexport class MongoCommandExecutor implements MongoDdlCommandVisitor<Promise<void>> {\n constructor(private readonly db: Db) {}\n\n async createIndex(cmd: CreateIndexCommand): Promise<void> {\n const keySpec: Document = keysToKeySpec(cmd.keys);\n const options: Record<string, unknown> = {};\n if (cmd.unique !== undefined) options['unique'] = cmd.unique;\n if (cmd.sparse !== undefined) options['sparse'] = cmd.sparse;\n if (cmd.expireAfterSeconds !== undefined)\n options['expireAfterSeconds'] = cmd.expireAfterSeconds;\n if (cmd.partialFilterExpression !== undefined)\n options['partialFilterExpression'] = cmd.partialFilterExpression;\n if (cmd.name !== undefined) options['name'] = cmd.name;\n if (cmd.wildcardProjection !== undefined)\n options['wildcardProjection'] = cmd.wildcardProjection;\n if (cmd.collation !== undefined) options['collation'] = cmd.collation;\n if (cmd.weights !== undefined) options['weights'] = cmd.weights;\n if (cmd.default_language !== undefined) options['default_language'] = cmd.default_language;\n if (cmd.language_override !== undefined) options['language_override'] = cmd.language_override;\n await this.db.collection(cmd.collection).createIndex(keySpec, options);\n }\n\n async dropIndex(cmd: DropIndexCommand): Promise<void> {\n await this.db.collection(cmd.collection).dropIndex(cmd.name);\n }\n\n async createCollection(cmd: CreateCollectionCommand): Promise<void> {\n const options: Record<string, unknown> = {};\n if (cmd.capped !== undefined) options['capped'] = cmd.capped;\n if (cmd.size !== undefined) options['size'] = cmd.size;\n if (cmd.max !== undefined) options['max'] = cmd.max;\n if (cmd.timeseries !== undefined) options['timeseries'] = cmd.timeseries;\n if (cmd.collation !== undefined) options['collation'] = cmd.collation;\n if (cmd.clusteredIndex !== undefined) options['clusteredIndex'] = cmd.clusteredIndex;\n if (cmd.validator !== undefined) options['validator'] = cmd.validator;\n if (cmd.validationLevel !== undefined) options['validationLevel'] = cmd.validationLevel;\n if (cmd.validationAction !== undefined) options['validationAction'] = cmd.validationAction;\n if (cmd.changeStreamPreAndPostImages !== undefined)\n options['changeStreamPreAndPostImages'] = cmd.changeStreamPreAndPostImages;\n await this.db.createCollection(cmd.collection, options);\n }\n\n async dropCollection(cmd: DropCollectionCommand): Promise<void> {\n await this.db.collection(cmd.collection).drop();\n }\n\n async collMod(cmd: CollModCommand): Promise<void> {\n const command: Record<string, unknown> = { collMod: cmd.collection };\n if (cmd.validator !== undefined) command['validator'] = cmd.validator;\n if (cmd.validationLevel !== undefined) command['validationLevel'] = cmd.validationLevel;\n if (cmd.validationAction !== undefined) command['validationAction'] = cmd.validationAction;\n if (cmd.changeStreamPreAndPostImages !== undefined)\n command['changeStreamPreAndPostImages'] = cmd.changeStreamPreAndPostImages;\n await this.db.command(command);\n }\n}\n\nexport class MongoInspectionExecutor implements MongoInspectionCommandVisitor<Promise<Document[]>> {\n constructor(private readonly db: Db) {}\n\n async listIndexes(cmd: ListIndexesCommand): Promise<Document[]> {\n try {\n return await this.db.collection(cmd.collection).listIndexes().toArray();\n } catch (error: unknown) {\n if (error instanceof MongoServerError && error.code === 26) {\n return [];\n }\n throw error;\n }\n }\n\n async listCollections(_cmd: ListCollectionsCommand): Promise<Document[]> {\n return this.db.listCollections().toArray();\n }\n}\n","import type { MongoIndexKey, MongoIndexKeyDirection } from '@prisma-next/mongo-contract';\nimport {\n MongoSchemaCollection,\n MongoSchemaCollectionOptions,\n MongoSchemaIndex,\n MongoSchemaIR,\n MongoSchemaValidator,\n} from '@prisma-next/mongo-schema-ir';\nimport type { Db, Document } from 'mongodb';\n\nconst PRISMA_MIGRATIONS_COLLECTION = '_prisma_migrations';\n\nfunction parseIndexKeys(keySpec: Record<string, unknown>): MongoIndexKey[] {\n const keys: MongoIndexKey[] = [];\n for (const [field, direction] of Object.entries(keySpec)) {\n keys.push({ field, direction: direction as MongoIndexKeyDirection });\n }\n return keys;\n}\n\n/**\n * Exported for unit tests to exercise the defensive `!key` guard; not part of\n * the public API. Callers in this package use it via the `introspectSchema`\n * pipeline only.\n */\nexport function isDefaultIdIndex(doc: Document): boolean {\n const key = doc['key'] as Record<string, unknown> | undefined;\n if (!key) return false;\n const entries = Object.entries(key);\n return entries.length === 1 && entries[0]?.[0] === '_id' && entries[0]?.[1] === 1;\n}\n\nfunction parseIndex(doc: Document): MongoSchemaIndex {\n const keySpec = doc['key'] as Record<string, unknown>;\n return new MongoSchemaIndex({\n keys: parseIndexKeys(keySpec),\n unique: doc['unique'] as boolean | undefined,\n sparse: doc['sparse'] as boolean | undefined,\n expireAfterSeconds: doc['expireAfterSeconds'] as number | undefined,\n partialFilterExpression: doc['partialFilterExpression'] as Record<string, unknown> | undefined,\n wildcardProjection: doc['wildcardProjection'] as Record<string, 0 | 1> | undefined,\n collation: doc['collation'] as Record<string, unknown> | undefined,\n weights: doc['weights'] as Record<string, number> | undefined,\n default_language: doc['default_language'] as string | undefined,\n language_override: doc['language_override'] as string | undefined,\n });\n}\n\nfunction parseValidator(options: Document): MongoSchemaValidator | undefined {\n const validator = options['validator'] as Record<string, unknown> | undefined;\n if (!validator) return undefined;\n\n const jsonSchema = validator['$jsonSchema'] as Record<string, unknown> | undefined;\n if (!jsonSchema) return undefined;\n\n return new MongoSchemaValidator({\n jsonSchema,\n validationLevel: (options['validationLevel'] as 'strict' | 'moderate') ?? 'strict',\n validationAction: (options['validationAction'] as 'error' | 'warn') ?? 'error',\n });\n}\n\nfunction parseCollectionOptions(info: Document): MongoSchemaCollectionOptions | undefined {\n const options = info['options'] as Record<string, unknown> | undefined;\n if (!options) return undefined;\n\n const capped = options['capped'] as boolean | undefined;\n const size = options['size'] as number | undefined;\n const max = options['max'] as number | undefined;\n const timeseries = options['timeseries'] as\n | { timeField: string; metaField?: string; granularity?: 'seconds' | 'minutes' | 'hours' }\n | undefined;\n const collation = options['collation'] as Record<string, unknown> | undefined;\n const changeStreamPreAndPostImages = options['changeStreamPreAndPostImages'] as\n | { enabled: boolean }\n | undefined;\n const clusteredIndex = options['clusteredIndex'] as { name?: string } | undefined;\n\n const hasMeaningfulOptions =\n capped || timeseries || collation || changeStreamPreAndPostImages || clusteredIndex;\n if (!hasMeaningfulOptions) return undefined;\n\n return new MongoSchemaCollectionOptions({\n ...(capped ? { capped: { size: size ?? 0, ...(max != null ? { max } : {}) } } : {}),\n ...(timeseries ? { timeseries } : {}),\n ...(collation ? { collation } : {}),\n ...(changeStreamPreAndPostImages ? { changeStreamPreAndPostImages } : {}),\n ...(clusteredIndex ? { clusteredIndex } : {}),\n });\n}\n\nexport async function introspectSchema(db: Db): Promise<MongoSchemaIR> {\n const collectionInfos = await db.listCollections().toArray();\n\n const collections: MongoSchemaCollection[] = [];\n\n for (const info of collectionInfos) {\n const name = info['name'] as string;\n const type = info['type'] as string | undefined;\n\n if (name === PRISMA_MIGRATIONS_COLLECTION) continue;\n if (name.startsWith('system.')) continue;\n if (type === 'view') continue;\n\n const indexDocs = await db.collection(name).listIndexes().toArray();\n const indexes = indexDocs.filter((doc) => !isDefaultIdIndex(doc)).map(parseIndex);\n\n const infoOptions = 'options' in info ? (info['options'] as Record<string, unknown>) : {};\n const validator = parseValidator(infoOptions);\n const options = parseCollectionOptions(info);\n\n collections.push(\n new MongoSchemaCollection({\n name,\n indexes,\n ...(validator ? { validator } : {}),\n ...(options ? { options } : {}),\n }),\n );\n }\n\n return new MongoSchemaIR(collections);\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport { parseMarkerRowSafely } from '@prisma-next/errors/execution';\nimport type {\n RawAggregateCommand,\n RawFindOneAndUpdateCommand,\n RawInsertOneCommand,\n} from '@prisma-next/mongo-query-ast/execution';\nimport { type } from 'arktype';\nimport type { Db, Document, UpdateFilter } from 'mongodb';\n\nexport const COLLECTION = '_prisma_migrations';\nexport const MONGO_MARKER_COLLECTION = `_prisma_migrations marker documents in ${COLLECTION}`;\nexport const MONGO_LEDGER_COLLECTION = `_prisma_migrations ledger documents in ${COLLECTION}`;\n\nconst MongoMarkerDocSchema = type({\n space: 'string',\n storageHash: 'string',\n profileHash: 'string',\n 'contractJson?': 'unknown | null',\n 'canonicalVersion?': 'number | null',\n 'updatedAt?': 'Date',\n 'appTag?': 'string | null',\n 'meta?': type({ '[string]': 'unknown' }).or('null'),\n 'invariants?': type('string').array(),\n '+': 'delete',\n});\n\nexport function parseMongoMarkerDoc(doc: unknown): ContractMarkerRecord {\n const result = MongoMarkerDocSchema(doc);\n if (result instanceof type.errors) {\n throw new Error(`Invalid marker doc on ${COLLECTION}: ${result.summary}`);\n }\n return {\n storageHash: result.storageHash,\n profileHash: result.profileHash,\n contractJson: result.contractJson ?? null,\n canonicalVersion: result.canonicalVersion ?? null,\n updatedAt: result.updatedAt ?? new Date(),\n appTag: result.appTag ?? null,\n meta: (result.meta as Record<string, unknown> | null) ?? {},\n invariants: result.invariants ?? [],\n };\n}\n\nexport function parseMongoMarkerDocSafely(doc: unknown, space: string): ContractMarkerRecord {\n return parseMarkerRowSafely(doc, parseMongoMarkerDoc, {\n space,\n markerLocation: MONGO_MARKER_COLLECTION,\n });\n}\n\nexport async function executeAggregate(db: Db, cmd: RawAggregateCommand): Promise<Document[]> {\n return db\n .collection(cmd.collection)\n .aggregate(cmd.pipeline as Record<string, unknown>[])\n .toArray();\n}\n\nexport async function executeInsertOne(db: Db, cmd: RawInsertOneCommand): Promise<void> {\n await db.collection(cmd.collection).insertOne(cmd.document);\n}\n\nexport async function executeFindOneAndUpdate(\n db: Db,\n cmd: RawFindOneAndUpdateCommand,\n): Promise<Document | null> {\n return db\n .collection(cmd.collection)\n .findOneAndUpdate(cmd.filter, cmd.update as UpdateFilter<Document> | Document[], {\n upsert: cmd.upsert,\n });\n}\n","import type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';\n\nexport function isMongoControlDriver(\n driver: ControlDriverInstance<'mongo', string>,\n): driver is MongoControlDriverInstance {\n return driver.familyId === 'mongo' && driver.targetId === 'mongo';\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type { MongoControlAdapter } from '@prisma-next/family-mongo/control-adapter';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n} from '@prisma-next/framework-components/control';\nimport type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';\nimport type {\n MongoDdlCommandVisitor,\n MongoInspectionCommandVisitor,\n} from '@prisma-next/mongo-query-ast/control';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport type { Db } from 'mongodb';\nimport { createMongoAdapter } from '../mongo-adapter';\nimport { MongoCommandExecutor, MongoInspectionExecutor } from './command-executor';\nimport { MongoControlAdapterImpl } from './mongo-control-adapter';\nimport { isMongoControlDriver } from './mongo-control-driver';\n\nexport function extractDb(driver: ControlDriverInstance<'mongo', 'mongo'>): Db {\n if (!isMongoControlDriver(driver)) {\n throw new Error(\n 'Expected a Mongo control driver created by ' +\n 'mongoControlDriver.create() from `@prisma-next/driver-mongo/control`.',\n );\n }\n return driver.db;\n}\n\n/**\n * Marker / ledger operations the Mongo runner depends on. Every method\n * takes a `space` parameter so each loaded contract space addresses its\n * own marker row independently — see ADR 212 for the per-space\n * mechanism.\n */\nexport interface MarkerOperations {\n readMarker(space: string): Promise<ContractMarkerRecord | null>;\n initMarker(\n space: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<void>;\n updateMarker(\n space: string,\n expectedFrom: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<boolean>;\n writeLedgerEntry(\n space: string,\n entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n },\n ): Promise<void>;\n}\n\nexport interface MongoRunnerDependencies {\n readonly commandExecutor: MongoDdlCommandVisitor<Promise<void>>;\n readonly inspectionExecutor: MongoInspectionCommandVisitor<Promise<Record<string, unknown>[]>>;\n readonly adapter: MongoAdapter;\n readonly driver: MongoDriver;\n readonly markerOps: MarkerOperations;\n readonly introspectSchema: () => Promise<MongoSchemaIR>;\n}\n\n/**\n * Build the runner-dependencies envelope. `controlAdapter` is the\n * dispatch surface for wire-level Mongo CAS operations (marker reads,\n * marker advances, ledger appends, introspection); the envelope's\n * `markerOps` shim simply forwards each call through it. When the\n * caller already has a `MongoControlAdapter` on the control stack it\n * can pass it in; otherwise a default `MongoControlAdapterImpl` is\n * constructed locally.\n */\nexport function createMongoRunnerDeps(\n controlDriver: ControlDriverInstance<'mongo', 'mongo'>,\n driver: MongoDriver,\n // Vestigial after the family→adapter SPI refactor: the runner dependencies\n // now route every wire-level call through `controlAdapter`, so the `family`\n // instance is no longer consulted. Kept on the signature to avoid rippling\n // through ~14 call sites; a follow-up that already touches this factory\n // should drop the parameter outright.\n _family: ControlFamilyInstance<'mongo', MongoSchemaIR>,\n controlAdapter: MongoControlAdapter<'mongo'> = new MongoControlAdapterImpl(),\n): MongoRunnerDependencies {\n return {\n commandExecutor: new MongoCommandExecutor(extractDb(controlDriver)),\n inspectionExecutor: new MongoInspectionExecutor(extractDb(controlDriver)),\n adapter: createMongoAdapter(),\n driver,\n markerOps: {\n readMarker: (space) => controlAdapter.readMarker(controlDriver, space),\n initMarker: (space, dest) => controlAdapter.initMarker(controlDriver, space, dest),\n updateMarker: (space, expectedFrom, dest) =>\n controlAdapter.updateMarker(controlDriver, space, expectedFrom, dest),\n writeLedgerEntry: (space, entry) =>\n controlAdapter.writeLedgerEntry(controlDriver, space, entry),\n },\n introspectSchema: () => controlAdapter.introspectSchema(controlDriver),\n };\n}\n","import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';\nimport { withMarkerReadErrorHandling } from '@prisma-next/errors/execution';\nimport type { MongoControlAdapter } from '@prisma-next/family-mongo/control-adapter';\nimport type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport { ledgerOriginFromStored } from '@prisma-next/migration-tools/ledger-origin';\nimport {\n RawAggregateCommand,\n RawFindOneAndUpdateCommand,\n RawInsertOneCommand,\n} from '@prisma-next/mongo-query-ast/execution';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport type { Document } from 'mongodb';\nimport { introspectSchema } from './introspect-schema';\nimport {\n COLLECTION,\n executeAggregate,\n executeFindOneAndUpdate,\n executeInsertOne,\n MONGO_LEDGER_COLLECTION,\n MONGO_MARKER_COLLECTION,\n parseMongoMarkerDocSafely,\n} from './marker-ledger';\nimport { extractDb } from './runner-deps';\n\n/**\n * Mongo control adapter for control-plane operations like introspection\n * and marker-ledger CAS. Implements the family-level `MongoControlAdapter`\n * SPI by extracting the underlying `Db` from the framework-shaped driver\n * per call.\n */\nexport class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {\n readonly familyId = 'mongo' as const;\n readonly targetId = 'mongo' as const;\n\n async readMarker(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n ): Promise<ContractMarkerRecord | null> {\n const db = extractDb(driver);\n const markerContext = { space, markerLocation: MONGO_MARKER_COLLECTION };\n const docs = await withMarkerReadErrorHandling(\n () =>\n executeAggregate(\n db,\n new RawAggregateCommand(COLLECTION, [{ $match: { _id: space, space } }, { $limit: 1 }]),\n ),\n markerContext,\n );\n const doc = docs[0];\n if (!doc) return null;\n return parseMongoMarkerDocSafely(doc, space);\n }\n\n async readAllMarkers(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n ): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n const db = extractDb(driver);\n const markerContext = { space: 'app', markerLocation: MONGO_MARKER_COLLECTION };\n const docs = await withMarkerReadErrorHandling(\n () =>\n executeAggregate(\n db,\n new RawAggregateCommand(COLLECTION, [\n {\n $match: {\n _id: { $type: 'string' },\n space: { $type: 'string' },\n $expr: { $eq: ['$_id', '$space'] },\n },\n },\n ]),\n ),\n markerContext,\n );\n const out = new Map<string, ContractMarkerRecord>();\n for (const doc of docs) {\n const space = doc['space'];\n /* 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`. */\n if (typeof space !== 'string') continue;\n out.set(space, parseMongoMarkerDocSafely(doc, space));\n }\n return out;\n }\n\n async initMarker(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<void> {\n const db = extractDb(driver);\n const cmd = new RawInsertOneCommand(COLLECTION, {\n _id: space,\n space,\n storageHash: destination.storageHash,\n profileHash: destination.profileHash,\n contractJson: null,\n canonicalVersion: null,\n updatedAt: new Date(),\n appTag: null,\n meta: {},\n invariants: destination.invariants ?? [],\n });\n await executeInsertOne(db, cmd);\n }\n\n async updateMarker(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n expectedFrom: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<boolean> {\n const db = extractDb(driver);\n const setBase: Record<string, unknown> = {\n storageHash: destination.storageHash,\n profileHash: destination.profileHash,\n updatedAt: new Date(),\n };\n const update: Document | Document[] =\n destination.invariants === undefined\n ? { $set: setBase }\n : [\n {\n $set: {\n ...setBase,\n invariants: {\n $sortArray: {\n input: {\n $setUnion: [{ $ifNull: ['$invariants', []] }, destination.invariants],\n },\n sortBy: 1,\n },\n },\n },\n },\n ];\n const cmd = new RawFindOneAndUpdateCommand(\n COLLECTION,\n { _id: space, space, storageHash: expectedFrom },\n update,\n false,\n );\n const result = await executeFindOneAndUpdate(db, cmd);\n return result !== null;\n }\n\n async writeLedgerEntry(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n },\n ): Promise<void> {\n const db = extractDb(driver);\n const cmd = new RawInsertOneCommand(COLLECTION, {\n type: 'ledger',\n space,\n edgeId: entry.edgeId,\n from: entry.from,\n to: entry.to,\n migrationName: entry.migrationName,\n migrationHash: entry.migrationHash,\n operations: entry.operations,\n appliedAt: new Date(),\n });\n await executeInsertOne(db, cmd);\n }\n\n async readLedger(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space?: string,\n ): Promise<readonly LedgerEntryRecord[]> {\n const db = extractDb(driver);\n const ledgerContext = { space: space ?? '*', markerLocation: MONGO_LEDGER_COLLECTION };\n const matchStage: Record<string, unknown> = { type: 'ledger' };\n if (space !== undefined) {\n matchStage['space'] = space;\n }\n const docs = await withMarkerReadErrorHandling(\n () =>\n executeAggregate(\n db,\n new RawAggregateCommand(COLLECTION, [{ $match: matchStage }, { $sort: { _id: 1 } }]),\n ),\n ledgerContext,\n );\n\n const entries: LedgerEntryRecord[] = [];\n for (const doc of docs) {\n const migrationName = doc['migrationName'];\n const migrationHash = doc['migrationHash'];\n const from = doc['from'];\n const to = doc['to'];\n const docSpace = doc['space'];\n if (typeof migrationName !== 'string' || typeof migrationHash !== 'string') {\n continue;\n }\n if (typeof from !== 'string' || typeof to !== 'string') {\n continue;\n }\n if (typeof docSpace !== 'string') {\n continue;\n }\n const appliedAt = doc['appliedAt'];\n const appliedAtDate =\n appliedAt instanceof Date\n ? appliedAt\n : appliedAt !== undefined\n ? new Date(String(appliedAt))\n : new Date();\n const operations = doc['operations'];\n const opList = Array.isArray(operations) ? operations : [];\n entries.push({\n space: docSpace,\n migrationName,\n migrationHash,\n from: ledgerOriginFromStored(from),\n to,\n appliedAt: appliedAtDate,\n operationCount: opList.length,\n });\n }\n return entries;\n }\n\n async introspectSchema(driver: ControlDriverInstance<'mongo', 'mongo'>): Promise<MongoSchemaIR> {\n return introspectSchema(extractDb(driver));\n }\n}\n","import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';\nimport type { MongoControlAdapterDescriptor } from '@prisma-next/family-mongo/control-adapter';\nimport type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport type { Db } from 'mongodb';\n\nexport type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';\nexport { MongoCommandExecutor, MongoInspectionExecutor } from '../core/command-executor';\nexport { introspectSchema } from '../core/introspect-schema';\nexport { MongoControlAdapterImpl } from '../core/mongo-control-adapter';\nexport { isMongoControlDriver } from '../core/mongo-control-driver';\nexport {\n createMongoRunnerDeps,\n extractDb,\n type MarkerOperations,\n type MongoRunnerDependencies,\n} from '../core/runner-deps';\nexport { createMongoAdapter } from '../mongo-adapter';\n\nimport { mongoCodecDescriptors } from '../core/codecs';\nimport { MongoControlAdapterImpl } from '../core/mongo-control-adapter';\n\nconst defaultControlAdapter = new MongoControlAdapterImpl();\n\nfunction controlDriverFromDb(db: Db): ControlDriverInstance<'mongo', 'mongo'> & { db: Db } {\n return {\n familyId: 'mongo',\n targetId: 'mongo',\n db,\n close: async () => {},\n };\n}\n\nexport async function readMarker(db: Db, space: string): Promise<ContractMarkerRecord | null> {\n return defaultControlAdapter.readMarker(controlDriverFromDb(db), space);\n}\n\nexport async function readAllMarkers(db: Db): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n return defaultControlAdapter.readAllMarkers(controlDriverFromDb(db));\n}\n\nexport async function initMarker(\n db: Db,\n space: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n): Promise<void> {\n await defaultControlAdapter.initMarker(controlDriverFromDb(db), space, destination);\n}\n\nexport async function updateMarker(\n db: Db,\n space: string,\n expectedFrom: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n): Promise<boolean> {\n return defaultControlAdapter.updateMarker(\n controlDriverFromDb(db),\n space,\n expectedFrom,\n destination,\n );\n}\n\nexport async function readLedger(db: Db, space?: string): Promise<readonly LedgerEntryRecord[]> {\n return defaultControlAdapter.readLedger(controlDriverFromDb(db), space);\n}\n\nexport async function writeLedgerEntry(\n db: Db,\n space: string,\n entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n },\n): Promise<void> {\n await defaultControlAdapter.writeLedgerEntry(controlDriverFromDb(db), space, entry);\n}\n\nexport const mongoAdapterDescriptor: MongoControlAdapterDescriptor<'mongo'> = {\n kind: 'adapter',\n id: 'mongo',\n familyId: 'mongo',\n targetId: 'mongo',\n version: '0.0.1',\n scalarTypeDescriptors: new Map([\n ['String', 'mongo/string@1'],\n ['Int', 'mongo/int32@1'],\n ['Boolean', 'mongo/bool@1'],\n ['DateTime', 'mongo/date@1'],\n ['ObjectId', 'mongo/objectId@1'],\n ['Float', 'mongo/double@1'],\n ]),\n types: {\n codecTypes: {\n codecDescriptors: mongoCodecDescriptors,\n import: {\n package: '@prisma-next/adapter-mongo/codec-types',\n named: 'CodecTypes',\n alias: 'MongoCodecTypes',\n },\n typeImports: [\n {\n package: '@prisma-next/adapter-mongo/codec-types',\n named: 'Vector',\n alias: 'Vector',\n },\n ],\n },\n },\n create(_stack) {\n return new MongoControlAdapterImpl();\n },\n};\n\nexport default mongoAdapterDescriptor;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"control.mjs","names":["#adapter","#markerLedgerCollection","#execute","#invariantMergeExpr"],"sources":["../src/core/command-executor.ts","../src/core/introspect-schema.ts","../src/core/marker-ledger.ts","../src/core/marker-ledger-collection.ts","../src/core/mongo-control-driver.ts","../src/core/runner-deps.ts","../src/core/mongo-control-adapter.ts","../src/exports/control.ts"],"sourcesContent":["import type {\n CollModCommand,\n CreateCollectionCommand,\n CreateIndexCommand,\n DropCollectionCommand,\n DropIndexCommand,\n ListCollectionsCommand,\n ListIndexesCommand,\n MongoDdlCommandVisitor,\n MongoInspectionCommandVisitor,\n} from '@prisma-next/mongo-query-ast/control';\nimport { keysToKeySpec } from '@prisma-next/mongo-query-ast/control';\nimport { type Db, type Document, MongoServerError } from 'mongodb';\n\nexport class MongoCommandExecutor implements MongoDdlCommandVisitor<Promise<void>> {\n constructor(private readonly db: Db) {}\n\n async createIndex(cmd: CreateIndexCommand): Promise<void> {\n const keySpec: Document = keysToKeySpec(cmd.keys);\n const options: Record<string, unknown> = {};\n if (cmd.unique !== undefined) options['unique'] = cmd.unique;\n if (cmd.sparse !== undefined) options['sparse'] = cmd.sparse;\n if (cmd.expireAfterSeconds !== undefined)\n options['expireAfterSeconds'] = cmd.expireAfterSeconds;\n if (cmd.partialFilterExpression !== undefined)\n options['partialFilterExpression'] = cmd.partialFilterExpression;\n if (cmd.name !== undefined) options['name'] = cmd.name;\n if (cmd.wildcardProjection !== undefined)\n options['wildcardProjection'] = cmd.wildcardProjection;\n if (cmd.collation !== undefined) options['collation'] = cmd.collation;\n if (cmd.weights !== undefined) options['weights'] = cmd.weights;\n if (cmd.default_language !== undefined) options['default_language'] = cmd.default_language;\n if (cmd.language_override !== undefined) options['language_override'] = cmd.language_override;\n await this.db.collection(cmd.collection).createIndex(keySpec, options);\n }\n\n async dropIndex(cmd: DropIndexCommand): Promise<void> {\n await this.db.collection(cmd.collection).dropIndex(cmd.name);\n }\n\n async createCollection(cmd: CreateCollectionCommand): Promise<void> {\n const options: Record<string, unknown> = {};\n if (cmd.capped !== undefined) options['capped'] = cmd.capped;\n if (cmd.size !== undefined) options['size'] = cmd.size;\n if (cmd.max !== undefined) options['max'] = cmd.max;\n if (cmd.timeseries !== undefined) options['timeseries'] = cmd.timeseries;\n if (cmd.collation !== undefined) options['collation'] = cmd.collation;\n if (cmd.clusteredIndex !== undefined) options['clusteredIndex'] = cmd.clusteredIndex;\n if (cmd.validator !== undefined) options['validator'] = cmd.validator;\n if (cmd.validationLevel !== undefined) options['validationLevel'] = cmd.validationLevel;\n if (cmd.validationAction !== undefined) options['validationAction'] = cmd.validationAction;\n if (cmd.changeStreamPreAndPostImages !== undefined)\n options['changeStreamPreAndPostImages'] = cmd.changeStreamPreAndPostImages;\n await this.db.createCollection(cmd.collection, options);\n }\n\n async dropCollection(cmd: DropCollectionCommand): Promise<void> {\n await this.db.collection(cmd.collection).drop();\n }\n\n async collMod(cmd: CollModCommand): Promise<void> {\n const command: Record<string, unknown> = { collMod: cmd.collection };\n if (cmd.validator !== undefined) command['validator'] = cmd.validator;\n if (cmd.validationLevel !== undefined) command['validationLevel'] = cmd.validationLevel;\n if (cmd.validationAction !== undefined) command['validationAction'] = cmd.validationAction;\n if (cmd.changeStreamPreAndPostImages !== undefined)\n command['changeStreamPreAndPostImages'] = cmd.changeStreamPreAndPostImages;\n await this.db.command(command);\n }\n}\n\nexport class MongoInspectionExecutor implements MongoInspectionCommandVisitor<Promise<Document[]>> {\n constructor(private readonly db: Db) {}\n\n async listIndexes(cmd: ListIndexesCommand): Promise<Document[]> {\n try {\n return await this.db.collection(cmd.collection).listIndexes().toArray();\n } catch (error: unknown) {\n if (error instanceof MongoServerError && error.code === 26) {\n return [];\n }\n throw error;\n }\n }\n\n async listCollections(_cmd: ListCollectionsCommand): Promise<Document[]> {\n return this.db.listCollections().toArray();\n }\n}\n","import type { MongoIndexKey, MongoIndexKeyDirection } from '@prisma-next/mongo-contract';\nimport {\n MongoSchemaCollection,\n MongoSchemaCollectionOptions,\n MongoSchemaIndex,\n MongoSchemaIR,\n MongoSchemaValidator,\n} from '@prisma-next/mongo-schema-ir';\nimport type { Db, Document } from 'mongodb';\n\nconst PRISMA_MIGRATIONS_COLLECTION = '_prisma_migrations';\n\nfunction parseIndexKeys(keySpec: Record<string, unknown>): MongoIndexKey[] {\n const keys: MongoIndexKey[] = [];\n for (const [field, direction] of Object.entries(keySpec)) {\n keys.push({ field, direction: direction as MongoIndexKeyDirection });\n }\n return keys;\n}\n\n/**\n * Exported for unit tests to exercise the defensive `!key` guard; not part of\n * the public API. Callers in this package use it via the `introspectSchema`\n * pipeline only.\n */\nexport function isDefaultIdIndex(doc: Document): boolean {\n const key = doc['key'] as Record<string, unknown> | undefined;\n if (!key) return false;\n const entries = Object.entries(key);\n return entries.length === 1 && entries[0]?.[0] === '_id' && entries[0]?.[1] === 1;\n}\n\nfunction parseIndex(doc: Document): MongoSchemaIndex {\n const keySpec = doc['key'] as Record<string, unknown>;\n return new MongoSchemaIndex({\n keys: parseIndexKeys(keySpec),\n unique: doc['unique'] as boolean | undefined,\n sparse: doc['sparse'] as boolean | undefined,\n expireAfterSeconds: doc['expireAfterSeconds'] as number | undefined,\n partialFilterExpression: doc['partialFilterExpression'] as Record<string, unknown> | undefined,\n wildcardProjection: doc['wildcardProjection'] as Record<string, 0 | 1> | undefined,\n collation: doc['collation'] as Record<string, unknown> | undefined,\n weights: doc['weights'] as Record<string, number> | undefined,\n default_language: doc['default_language'] as string | undefined,\n language_override: doc['language_override'] as string | undefined,\n });\n}\n\nfunction parseValidator(options: Document): MongoSchemaValidator | undefined {\n const validator = options['validator'] as Record<string, unknown> | undefined;\n if (!validator) return undefined;\n\n const jsonSchema = validator['$jsonSchema'] as Record<string, unknown> | undefined;\n if (!jsonSchema) return undefined;\n\n return new MongoSchemaValidator({\n jsonSchema,\n validationLevel: (options['validationLevel'] as 'strict' | 'moderate') ?? 'strict',\n validationAction: (options['validationAction'] as 'error' | 'warn') ?? 'error',\n });\n}\n\nfunction parseCollectionOptions(info: Document): MongoSchemaCollectionOptions | undefined {\n const options = info['options'] as Record<string, unknown> | undefined;\n if (!options) return undefined;\n\n const capped = options['capped'] as boolean | undefined;\n const size = options['size'] as number | undefined;\n const max = options['max'] as number | undefined;\n const timeseries = options['timeseries'] as\n | { timeField: string; metaField?: string; granularity?: 'seconds' | 'minutes' | 'hours' }\n | undefined;\n const collation = options['collation'] as Record<string, unknown> | undefined;\n const changeStreamPreAndPostImages = options['changeStreamPreAndPostImages'] as\n | { enabled: boolean }\n | undefined;\n const clusteredIndex = options['clusteredIndex'] as { name?: string } | undefined;\n\n const hasMeaningfulOptions =\n capped || timeseries || collation || changeStreamPreAndPostImages || clusteredIndex;\n if (!hasMeaningfulOptions) return undefined;\n\n return new MongoSchemaCollectionOptions({\n ...(capped ? { capped: { size: size ?? 0, ...(max != null ? { max } : {}) } } : {}),\n ...(timeseries ? { timeseries } : {}),\n ...(collation ? { collation } : {}),\n ...(changeStreamPreAndPostImages ? { changeStreamPreAndPostImages } : {}),\n ...(clusteredIndex ? { clusteredIndex } : {}),\n });\n}\n\nexport async function introspectSchema(db: Db): Promise<MongoSchemaIR> {\n const collectionInfos = await db.listCollections().toArray();\n\n const collections: MongoSchemaCollection[] = [];\n\n for (const info of collectionInfos) {\n const name = info['name'] as string;\n const type = info['type'] as string | undefined;\n\n if (name === PRISMA_MIGRATIONS_COLLECTION) continue;\n if (name.startsWith('system.')) continue;\n if (type === 'view') continue;\n\n const indexDocs = await db.collection(name).listIndexes().toArray();\n const indexes = indexDocs.filter((doc) => !isDefaultIdIndex(doc)).map(parseIndex);\n\n const infoOptions = 'options' in info ? (info['options'] as Record<string, unknown>) : {};\n const validator = parseValidator(infoOptions);\n const options = parseCollectionOptions(info);\n\n collections.push(\n new MongoSchemaCollection({\n name,\n indexes,\n ...(validator ? { validator } : {}),\n ...(options ? { options } : {}),\n }),\n );\n }\n\n return new MongoSchemaIR(collections);\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport { parseMarkerRowSafely } from '@prisma-next/errors/execution';\nimport { type } from 'arktype';\n\nexport const COLLECTION = '_prisma_migrations';\nexport const MONGO_MARKER_COLLECTION = `_prisma_migrations marker documents in ${COLLECTION}`;\nexport const MONGO_LEDGER_COLLECTION = `_prisma_migrations ledger documents in ${COLLECTION}`;\n\nconst MongoMarkerDocSchema = type({\n space: 'string',\n storageHash: 'string',\n profileHash: 'string',\n 'contractJson?': 'unknown | null',\n 'canonicalVersion?': 'number | null',\n 'updatedAt?': 'Date',\n 'appTag?': 'string | null',\n 'meta?': type({ '[string]': 'unknown' }).or('null'),\n 'invariants?': type('string').array(),\n '+': 'delete',\n});\n\nexport function parseMongoMarkerDoc(doc: unknown): ContractMarkerRecord {\n const result = MongoMarkerDocSchema(doc);\n if (result instanceof type.errors) {\n throw new Error(`Invalid marker doc on ${COLLECTION}: ${result.summary}`);\n }\n return {\n storageHash: result.storageHash,\n profileHash: result.profileHash,\n contractJson: result.contractJson ?? null,\n canonicalVersion: result.canonicalVersion ?? null,\n updatedAt: result.updatedAt ?? new Date(),\n appTag: result.appTag ?? null,\n meta: result.meta ?? {},\n invariants: result.invariants ?? [],\n };\n}\n\nexport function parseMongoMarkerDocSafely(doc: unknown, space: string): ContractMarkerRecord {\n return parseMarkerRowSafely(doc, parseMongoMarkerDoc, {\n space,\n markerLocation: MONGO_MARKER_COLLECTION,\n });\n}\n","/**\n * Document shape of the `_prisma_migrations` collection, which stores both the\n * per-space contract **markers** (`space` / `storageHash` / … / `invariants`)\n * and the migration **ledger** entries (`type` / `edgeId` / … / `appliedAt`) —\n * so the shape is their union. Declared once so the contract-free field\n * accessor is typed without threading a contract, codecs, or paths at the call\n * sites.\n */\nexport type MarkerLedgerDocShape = {\n readonly _id: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n // Marker fields\n readonly space: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly storageHash: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly profileHash: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly contractJson: { readonly codecId: 'mongo/string@1'; readonly nullable: true };\n readonly canonicalVersion: { readonly codecId: 'mongo/double@1'; readonly nullable: true };\n readonly updatedAt: { readonly codecId: 'mongo/date@1'; readonly nullable: false };\n readonly appTag: { readonly codecId: 'mongo/string@1'; readonly nullable: true };\n readonly meta: { readonly codecId: 'mongo/document@1'; readonly nullable: true };\n readonly invariants: { readonly codecId: 'mongo/array@1'; readonly nullable: false };\n // Ledger fields\n readonly type: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly edgeId: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly from: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly to: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly migrationName: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly migrationHash: { readonly codecId: 'mongo/string@1'; readonly nullable: false };\n readonly operations: { readonly codecId: 'mongo/array@1'; readonly nullable: false };\n readonly appliedAt: { readonly codecId: 'mongo/date@1'; readonly nullable: false };\n};\n\nexport const MARKER_LEDGER_COLLECTION = '_prisma_migrations';\n","import type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';\n\nexport function isMongoControlDriver(\n driver: ControlDriverInstance<'mongo', string>,\n): driver is MongoControlDriverInstance {\n return (\n driver.familyId === 'mongo' &&\n driver.targetId === 'mongo' &&\n 'execute' in driver &&\n typeof driver.execute === 'function'\n );\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type { MongoControlAdapter } from '@prisma-next/family-mongo/control-adapter';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n} from '@prisma-next/framework-components/control';\nimport type { MongoAdapter, MongoDriver } from '@prisma-next/mongo-lowering';\nimport type {\n MongoDdlCommandVisitor,\n MongoInspectionCommandVisitor,\n} from '@prisma-next/mongo-query-ast/control';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport type { Db } from 'mongodb';\nimport { createMongoAdapter } from '../mongo-adapter';\nimport { MongoCommandExecutor, MongoInspectionExecutor } from './command-executor';\nimport { MongoControlAdapterImpl } from './mongo-control-adapter';\nimport { isMongoControlDriver } from './mongo-control-driver';\n\nexport function extractDb(driver: ControlDriverInstance<'mongo', 'mongo'>): Db {\n if (!isMongoControlDriver(driver)) {\n throw new Error(\n 'Expected a Mongo control driver created by ' +\n 'mongoControlDriver.create() from `@prisma-next/driver-mongo/control`.',\n );\n }\n return driver.db;\n}\n\n/**\n * Marker / ledger operations the Mongo runner depends on. Every method\n * takes a `space` parameter so each loaded contract space addresses its\n * own marker row independently — see ADR 212 for the per-space\n * mechanism.\n */\nexport interface MarkerOperations {\n readMarker(space: string): Promise<ContractMarkerRecord | null>;\n initMarker(\n space: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<void>;\n updateMarker(\n space: string,\n expectedFrom: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<boolean>;\n writeLedgerEntry(\n space: string,\n entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n },\n ): Promise<void>;\n}\n\nexport interface MongoRunnerDependencies {\n readonly commandExecutor: MongoDdlCommandVisitor<Promise<void>>;\n readonly inspectionExecutor: MongoInspectionCommandVisitor<Promise<Record<string, unknown>[]>>;\n readonly adapter: MongoAdapter;\n readonly driver: MongoDriver;\n readonly markerOps: MarkerOperations;\n readonly introspectSchema: () => Promise<MongoSchemaIR>;\n}\n\n/**\n * Build the runner-dependencies envelope. `controlAdapter` is the\n * dispatch surface for wire-level Mongo CAS operations (marker reads,\n * marker advances, ledger appends, introspection); the envelope's\n * `markerOps` shim simply forwards each call through it. When the\n * caller already has a `MongoControlAdapter` on the control stack it\n * can pass it in; otherwise a default `MongoControlAdapterImpl` is\n * constructed locally.\n */\nexport function createMongoRunnerDeps(\n controlDriver: ControlDriverInstance<'mongo', 'mongo'>,\n driver: MongoDriver,\n // Vestigial after the family→adapter SPI refactor: the runner dependencies\n // now route every wire-level call through `controlAdapter`, so the `family`\n // instance is no longer consulted. Kept on the signature to avoid rippling\n // through ~14 call sites; a follow-up that already touches this factory\n // should drop the parameter outright.\n _family: ControlFamilyInstance<'mongo', MongoSchemaIR>,\n controlAdapter: MongoControlAdapter<'mongo'> = new MongoControlAdapterImpl(),\n): MongoRunnerDependencies {\n return {\n commandExecutor: new MongoCommandExecutor(extractDb(controlDriver)),\n inspectionExecutor: new MongoInspectionExecutor(extractDb(controlDriver)),\n adapter: createMongoAdapter(),\n driver,\n markerOps: {\n readMarker: (space) => controlAdapter.readMarker(controlDriver, space),\n initMarker: (space, dest) => controlAdapter.initMarker(controlDriver, space, dest),\n updateMarker: (space, expectedFrom, dest) =>\n controlAdapter.updateMarker(controlDriver, space, expectedFrom, dest),\n writeLedgerEntry: (space, entry) =>\n controlAdapter.writeLedgerEntry(controlDriver, space, entry),\n },\n introspectSchema: () => controlAdapter.introspectSchema(controlDriver),\n };\n}\n","import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';\nimport { withMarkerReadErrorHandling } from '@prisma-next/errors/execution';\nimport type { MongoControlAdapter } from '@prisma-next/family-mongo/control-adapter';\nimport type { ControlDriverInstance } from '@prisma-next/framework-components/control';\nimport { ledgerOriginFromStored } from '@prisma-next/migration-tools/ledger-origin';\nimport type { MongoAdapter } from '@prisma-next/mongo-lowering';\nimport {\n type AnyMongoCommand,\n MongoAggFieldRef,\n MongoAggLiteral,\n MongoAggOperator,\n type MongoQueryPlan,\n} from '@prisma-next/mongo-query-ast/execution';\nimport { expr, fn } from '@prisma-next/mongo-query-builder';\nimport { collection } from '@prisma-next/mongo-query-builder/contract-free';\nimport type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';\nimport type { MongoValue } from '@prisma-next/mongo-value';\nimport { blindCast } from '@prisma-next/utils/casts';\nimport type { Document } from 'mongodb';\nimport { createMongoAdapter } from '../mongo-adapter';\nimport { introspectSchema } from './introspect-schema';\nimport {\n MONGO_LEDGER_COLLECTION,\n MONGO_MARKER_COLLECTION,\n parseMongoMarkerDocSafely,\n} from './marker-ledger';\nimport { MARKER_LEDGER_COLLECTION, type MarkerLedgerDocShape } from './marker-ledger-collection';\nimport { isMongoControlDriver } from './mongo-control-driver';\nimport { extractDb } from './runner-deps';\n\n/**\n * Mongo control adapter for control-plane operations like introspection\n * and marker-ledger CAS. Implements the family-level `MongoControlAdapter`\n * SPI. Every marker/ledger operation builds a canonical command inline via\n * the contract-free fluent builder and dispatches it through the family\n * adapter's lowering path (`createMongoAdapter().lower(plan, {})`) onto the\n * Mongo wire transport (`driver.execute(wireCommand)`) — the same route SQL\n * marker/ledger ops take through `adapter.lower()` → `driver.query()`.\n */\nexport class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {\n readonly familyId = 'mongo' as const;\n readonly targetId = 'mongo' as const;\n readonly #adapter: MongoAdapter = createMongoAdapter();\n readonly #markerLedgerCollection = collection<MarkerLedgerDocShape>(MARKER_LEDGER_COLLECTION);\n\n async #execute(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n command: AnyMongoCommand,\n ): Promise<Document[]> {\n const plan: MongoQueryPlan = {\n collection: MARKER_LEDGER_COLLECTION,\n command,\n meta: { target: 'mongo', targetFamily: 'mongo', storageHash: '', lane: 'control' },\n };\n const wireCommand = await this.#adapter.lower(plan, {});\n if (!isMongoControlDriver(driver)) {\n throw new Error(\n 'Mongo control adapter requires a Mongo control driver with an execute() transport. ' +\n 'Provide a MongoControlDriver from `@prisma-next/driver-mongo/control`.',\n );\n }\n const rows: Document[] = [];\n for await (const row of driver.execute<Document>(wireCommand)) {\n rows.push(row);\n }\n return rows;\n }\n\n /**\n * Server-side invariant-merge aggregation expression:\n * `$sortArray({ input: $setUnion([$ifNull('$invariants', []), incoming]), sortBy: 1 })`.\n *\n * Built through the typed agg-expr layer — `fn.setUnion` plus the generic\n * `MongoAggOperator` for `$ifNull` / `$sortArray` (neither has a named `fn`\n * helper). Returns a `MongoAggOperator` that is passed directly to\n * `f.stage.set({ invariants: ... })` in the update pipeline.\n */\n #invariantMergeExpr(incoming: readonly string[]): MongoAggOperator {\n const existingOrEmpty = MongoAggOperator.of('$ifNull', [\n MongoAggFieldRef.of('invariants'),\n MongoAggLiteral.of([]),\n ]);\n const merged = fn.setUnion(\n { _field: { codecId: 'mongo/array@1', nullable: false }, node: existingOrEmpty },\n {\n _field: { codecId: 'mongo/array@1', nullable: false },\n node: MongoAggLiteral.of([...incoming]),\n },\n );\n return MongoAggOperator.of('$sortArray', { input: merged.node, sortBy: MongoAggLiteral.of(1) });\n }\n\n async readMarker(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n ): Promise<ContractMarkerRecord | null> {\n const markerContext = { space, markerLocation: MONGO_MARKER_COLLECTION };\n const docs = await withMarkerReadErrorHandling(\n () =>\n this.#execute(\n driver,\n this.#markerLedgerCollection\n .aggregate()\n .match((f) => f._id.eq(space))\n .match((f) => f.space.eq(space))\n .limit(1)\n .build(),\n ),\n markerContext,\n );\n const doc = docs[0];\n if (!doc) return null;\n return parseMongoMarkerDocSafely(doc, space);\n }\n\n async readAllMarkers(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n ): Promise<ReadonlyMap<string, ContractMarkerRecord>> {\n const markerContext = { space: 'app', markerLocation: MONGO_MARKER_COLLECTION };\n const docs = await withMarkerReadErrorHandling(\n () =>\n this.#execute(\n driver,\n this.#markerLedgerCollection\n .aggregate()\n .match((f) => f._id.type('string'))\n .match((f) => f.space.type('string'))\n .match((f) => expr(fn.eq(f._id, f.space)))\n .build(),\n ),\n markerContext,\n );\n const out = new Map<string, ContractMarkerRecord>();\n for (const doc of docs) {\n const space = doc['space'];\n /* 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`. */\n if (typeof space !== 'string') continue;\n out.set(space, parseMongoMarkerDocSafely(doc, space));\n }\n return out;\n }\n\n async initMarker(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<void> {\n const document: Record<string, MongoValue> = {\n _id: space,\n space,\n storageHash: destination.storageHash,\n profileHash: destination.profileHash,\n contractJson: null,\n canonicalVersion: null,\n updatedAt: new Date(),\n appTag: null,\n meta: {},\n invariants: [...(destination.invariants ?? [])],\n };\n await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));\n }\n\n async updateMarker(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n expectedFrom: string,\n destination: {\n readonly storageHash: string;\n readonly profileHash: string;\n readonly invariants?: readonly string[];\n },\n ): Promise<boolean> {\n const { invariants } = destination;\n const docs = await this.#execute(\n driver,\n this.#markerLedgerCollection\n .match((f) => f._id.eq(space))\n .match((f) => f.space.eq(space))\n .match((f) => f.storageHash.eq(expectedFrom))\n .findOneAndUpdate(\n (f) => [\n f.stage.set(\n invariants === undefined\n ? {\n storageHash: MongoAggLiteral.of(destination.storageHash),\n profileHash: MongoAggLiteral.of(destination.profileHash),\n updatedAt: MongoAggLiteral.of(new Date()),\n }\n : {\n storageHash: MongoAggLiteral.of(destination.storageHash),\n profileHash: MongoAggLiteral.of(destination.profileHash),\n updatedAt: MongoAggLiteral.of(new Date()),\n invariants: this.#invariantMergeExpr(invariants),\n },\n ),\n ],\n { upsert: false },\n ),\n );\n return docs.length > 0;\n }\n\n async writeLedgerEntry(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space: string,\n entry: {\n readonly edgeId: string;\n readonly from: string;\n readonly to: string;\n readonly migrationName: string;\n readonly migrationHash: string;\n readonly operations: readonly unknown[];\n },\n ): Promise<void> {\n const document: Record<string, MongoValue> = {\n type: 'ledger',\n space,\n edgeId: entry.edgeId,\n from: entry.from,\n to: entry.to,\n migrationName: entry.migrationName,\n migrationHash: entry.migrationHash,\n operations: blindCast<ReadonlyArray<MongoValue>, 'ledger operation docs are BSON values'>(\n entry.operations,\n ),\n appliedAt: new Date(),\n };\n await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));\n }\n\n async readLedger(\n driver: ControlDriverInstance<'mongo', 'mongo'>,\n space?: string,\n ): Promise<readonly LedgerEntryRecord[]> {\n const ledgerContext = { space: space ?? '*', markerLocation: MONGO_LEDGER_COLLECTION };\n const chain = this.#markerLedgerCollection.aggregate().match((f) => f.type.eq('ledger'));\n const command =\n space === undefined\n ? chain.sort({ _id: 1 }).build()\n : chain\n .match((f) => f.space.eq(space))\n .sort({ _id: 1 })\n .build();\n const docs = await withMarkerReadErrorHandling(\n () => this.#execute(driver, command),\n ledgerContext,\n );\n\n const entries: LedgerEntryRecord[] = [];\n for (const doc of docs) {\n const migrationName = doc['migrationName'];\n const migrationHash = doc['migrationHash'];\n const from = doc['from'];\n const to = doc['to'];\n const docSpace = doc['space'];\n if (typeof migrationName !== 'string' || typeof migrationHash !== 'string') {\n continue;\n }\n if (typeof from !== 'string' || typeof to !== 'string') {\n continue;\n }\n if (typeof docSpace !== 'string') {\n continue;\n }\n const appliedAt = doc['appliedAt'];\n const appliedAtDate =\n appliedAt instanceof Date\n ? appliedAt\n : appliedAt !== undefined\n ? new Date(String(appliedAt))\n : new Date();\n const operations = doc['operations'];\n const opList = Array.isArray(operations) ? operations : [];\n entries.push({\n space: docSpace,\n migrationName,\n migrationHash,\n from: ledgerOriginFromStored(from),\n to,\n appliedAt: appliedAtDate,\n operationCount: opList.length,\n });\n }\n return entries;\n }\n\n async introspectSchema(driver: ControlDriverInstance<'mongo', 'mongo'>): Promise<MongoSchemaIR> {\n return introspectSchema(extractDb(driver));\n }\n}\n","import type { MongoControlAdapterDescriptor } from '@prisma-next/family-mongo/control-adapter';\nimport type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';\n\nexport { MongoCommandExecutor, MongoInspectionExecutor } from '../core/command-executor';\nexport { introspectSchema } from '../core/introspect-schema';\nexport { MongoControlAdapterImpl } from '../core/mongo-control-adapter';\nexport { isMongoControlDriver } from '../core/mongo-control-driver';\nexport {\n createMongoRunnerDeps,\n extractDb,\n type MarkerOperations,\n type MongoRunnerDependencies,\n} from '../core/runner-deps';\nexport { createMongoAdapter } from '../mongo-adapter';\nexport type { MongoControlDriverInstance };\n\nimport { mongoCodecDescriptors } from '../core/codecs';\nimport { MongoControlAdapterImpl } from '../core/mongo-control-adapter';\n\nexport const mongoAdapterDescriptor: MongoControlAdapterDescriptor<'mongo'> = {\n kind: 'adapter',\n id: 'mongo',\n familyId: 'mongo',\n targetId: 'mongo',\n version: '0.0.1',\n scalarTypeDescriptors: new Map([\n ['String', 'mongo/string@1'],\n ['Int', 'mongo/int32@1'],\n ['Boolean', 'mongo/bool@1'],\n ['DateTime', 'mongo/date@1'],\n ['ObjectId', 'mongo/objectId@1'],\n ['Float', 'mongo/double@1'],\n ]),\n types: {\n codecTypes: {\n codecDescriptors: mongoCodecDescriptors,\n import: {\n package: '@prisma-next/adapter-mongo/codec-types',\n named: 'CodecTypes',\n alias: 'MongoCodecTypes',\n },\n typeImports: [\n {\n package: '@prisma-next/adapter-mongo/codec-types',\n named: 'Vector',\n alias: 'Vector',\n },\n ],\n },\n },\n create(_stack) {\n return new MongoControlAdapterImpl();\n },\n};\n\nexport default mongoAdapterDescriptor;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,36 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/adapter-mongo",
|
|
3
|
-
"version": "0.12.0-dev.
|
|
3
|
+
"version": "0.12.0-dev.51",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "MongoDB adapter for Prisma Next (lowers commands to wire format)",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@prisma-next/config": "0.12.0-dev.
|
|
10
|
-
"@prisma-next/contract": "0.12.0-dev.
|
|
11
|
-
"@prisma-next/errors": "0.12.0-dev.
|
|
12
|
-
"@prisma-next/family-mongo": "0.12.0-dev.
|
|
13
|
-
"@prisma-next/framework-components": "0.12.0-dev.
|
|
14
|
-
"@prisma-next/migration-tools": "0.12.0-dev.
|
|
15
|
-
"@prisma-next/mongo-codec": "0.12.0-dev.
|
|
16
|
-
"@prisma-next/mongo-contract": "0.12.0-dev.
|
|
17
|
-
"@prisma-next/mongo-lowering": "0.12.0-dev.
|
|
18
|
-
"@prisma-next/mongo-query-ast": "0.12.0-dev.
|
|
19
|
-
"@prisma-next/mongo-
|
|
20
|
-
"@prisma-next/mongo-
|
|
21
|
-
"@prisma-next/mongo-
|
|
22
|
-
"@prisma-next/
|
|
23
|
-
"@prisma-next/
|
|
9
|
+
"@prisma-next/config": "0.12.0-dev.51",
|
|
10
|
+
"@prisma-next/contract": "0.12.0-dev.51",
|
|
11
|
+
"@prisma-next/errors": "0.12.0-dev.51",
|
|
12
|
+
"@prisma-next/family-mongo": "0.12.0-dev.51",
|
|
13
|
+
"@prisma-next/framework-components": "0.12.0-dev.51",
|
|
14
|
+
"@prisma-next/migration-tools": "0.12.0-dev.51",
|
|
15
|
+
"@prisma-next/mongo-codec": "0.12.0-dev.51",
|
|
16
|
+
"@prisma-next/mongo-contract": "0.12.0-dev.51",
|
|
17
|
+
"@prisma-next/mongo-lowering": "0.12.0-dev.51",
|
|
18
|
+
"@prisma-next/mongo-query-ast": "0.12.0-dev.51",
|
|
19
|
+
"@prisma-next/mongo-query-builder": "0.12.0-dev.51",
|
|
20
|
+
"@prisma-next/mongo-schema-ir": "0.12.0-dev.51",
|
|
21
|
+
"@prisma-next/mongo-value": "0.12.0-dev.51",
|
|
22
|
+
"@prisma-next/mongo-wire": "0.12.0-dev.51",
|
|
23
|
+
"@prisma-next/operations": "0.12.0-dev.51",
|
|
24
|
+
"@prisma-next/utils": "0.12.0-dev.51",
|
|
24
25
|
"arktype": "^2.2.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"mongodb": "^7.2.0",
|
|
28
|
-
"@prisma-next/
|
|
29
|
-
"@prisma-next/
|
|
30
|
-
"@prisma-next/psl
|
|
31
|
-
"@prisma-next/
|
|
32
|
-
"@prisma-next/
|
|
33
|
-
"@prisma-next/
|
|
29
|
+
"@prisma-next/driver-mongo": "0.12.0-dev.51",
|
|
30
|
+
"@prisma-next/errors": "0.12.0-dev.51",
|
|
31
|
+
"@prisma-next/mongo-contract-psl": "0.12.0-dev.51",
|
|
32
|
+
"@prisma-next/psl-parser": "0.12.0-dev.51",
|
|
33
|
+
"@prisma-next/test-utils": "0.12.0-dev.51",
|
|
34
|
+
"@prisma-next/tsconfig": "0.12.0-dev.51",
|
|
35
|
+
"@prisma-next/tsdown": "0.12.0-dev.51",
|
|
34
36
|
"mongodb-memory-server": "11.1.0",
|
|
35
37
|
"tsdown": "0.22.0",
|
|
36
38
|
"typescript": "5.9.3",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document shape of the `_prisma_migrations` collection, which stores both the
|
|
3
|
+
* per-space contract **markers** (`space` / `storageHash` / … / `invariants`)
|
|
4
|
+
* and the migration **ledger** entries (`type` / `edgeId` / … / `appliedAt`) —
|
|
5
|
+
* so the shape is their union. Declared once so the contract-free field
|
|
6
|
+
* accessor is typed without threading a contract, codecs, or paths at the call
|
|
7
|
+
* sites.
|
|
8
|
+
*/
|
|
9
|
+
export type MarkerLedgerDocShape = {
|
|
10
|
+
readonly _id: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
11
|
+
// Marker fields
|
|
12
|
+
readonly space: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
13
|
+
readonly storageHash: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
14
|
+
readonly profileHash: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
15
|
+
readonly contractJson: { readonly codecId: 'mongo/string@1'; readonly nullable: true };
|
|
16
|
+
readonly canonicalVersion: { readonly codecId: 'mongo/double@1'; readonly nullable: true };
|
|
17
|
+
readonly updatedAt: { readonly codecId: 'mongo/date@1'; readonly nullable: false };
|
|
18
|
+
readonly appTag: { readonly codecId: 'mongo/string@1'; readonly nullable: true };
|
|
19
|
+
readonly meta: { readonly codecId: 'mongo/document@1'; readonly nullable: true };
|
|
20
|
+
readonly invariants: { readonly codecId: 'mongo/array@1'; readonly nullable: false };
|
|
21
|
+
// Ledger fields
|
|
22
|
+
readonly type: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
23
|
+
readonly edgeId: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
24
|
+
readonly from: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
25
|
+
readonly to: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
26
|
+
readonly migrationName: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
27
|
+
readonly migrationHash: { readonly codecId: 'mongo/string@1'; readonly nullable: false };
|
|
28
|
+
readonly operations: { readonly codecId: 'mongo/array@1'; readonly nullable: false };
|
|
29
|
+
readonly appliedAt: { readonly codecId: 'mongo/date@1'; readonly nullable: false };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const MARKER_LEDGER_COLLECTION = '_prisma_migrations';
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import type { ContractMarkerRecord } from '@prisma-next/contract/types';
|
|
2
2
|
import { parseMarkerRowSafely } from '@prisma-next/errors/execution';
|
|
3
|
-
import type {
|
|
4
|
-
RawAggregateCommand,
|
|
5
|
-
RawFindOneAndUpdateCommand,
|
|
6
|
-
RawInsertOneCommand,
|
|
7
|
-
} from '@prisma-next/mongo-query-ast/execution';
|
|
8
3
|
import { type } from 'arktype';
|
|
9
|
-
import type { Db, Document, UpdateFilter } from 'mongodb';
|
|
10
4
|
|
|
11
5
|
export const COLLECTION = '_prisma_migrations';
|
|
12
6
|
export const MONGO_MARKER_COLLECTION = `_prisma_migrations marker documents in ${COLLECTION}`;
|
|
@@ -37,7 +31,7 @@ export function parseMongoMarkerDoc(doc: unknown): ContractMarkerRecord {
|
|
|
37
31
|
canonicalVersion: result.canonicalVersion ?? null,
|
|
38
32
|
updatedAt: result.updatedAt ?? new Date(),
|
|
39
33
|
appTag: result.appTag ?? null,
|
|
40
|
-
meta:
|
|
34
|
+
meta: result.meta ?? {},
|
|
41
35
|
invariants: result.invariants ?? [],
|
|
42
36
|
};
|
|
43
37
|
}
|
|
@@ -48,25 +42,3 @@ export function parseMongoMarkerDocSafely(doc: unknown, space: string): Contract
|
|
|
48
42
|
markerLocation: MONGO_MARKER_COLLECTION,
|
|
49
43
|
});
|
|
50
44
|
}
|
|
51
|
-
|
|
52
|
-
export async function executeAggregate(db: Db, cmd: RawAggregateCommand): Promise<Document[]> {
|
|
53
|
-
return db
|
|
54
|
-
.collection(cmd.collection)
|
|
55
|
-
.aggregate(cmd.pipeline as Record<string, unknown>[])
|
|
56
|
-
.toArray();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export async function executeInsertOne(db: Db, cmd: RawInsertOneCommand): Promise<void> {
|
|
60
|
-
await db.collection(cmd.collection).insertOne(cmd.document);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export async function executeFindOneAndUpdate(
|
|
64
|
-
db: Db,
|
|
65
|
-
cmd: RawFindOneAndUpdateCommand,
|
|
66
|
-
): Promise<Document | null> {
|
|
67
|
-
return db
|
|
68
|
-
.collection(cmd.collection)
|
|
69
|
-
.findOneAndUpdate(cmd.filter, cmd.update as UpdateFilter<Document> | Document[], {
|
|
70
|
-
upsert: cmd.upsert,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
@@ -3,46 +3,108 @@ import { withMarkerReadErrorHandling } from '@prisma-next/errors/execution';
|
|
|
3
3
|
import type { MongoControlAdapter } from '@prisma-next/family-mongo/control-adapter';
|
|
4
4
|
import type { ControlDriverInstance } from '@prisma-next/framework-components/control';
|
|
5
5
|
import { ledgerOriginFromStored } from '@prisma-next/migration-tools/ledger-origin';
|
|
6
|
+
import type { MongoAdapter } from '@prisma-next/mongo-lowering';
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
type AnyMongoCommand,
|
|
9
|
+
MongoAggFieldRef,
|
|
10
|
+
MongoAggLiteral,
|
|
11
|
+
MongoAggOperator,
|
|
12
|
+
type MongoQueryPlan,
|
|
10
13
|
} from '@prisma-next/mongo-query-ast/execution';
|
|
14
|
+
import { expr, fn } from '@prisma-next/mongo-query-builder';
|
|
15
|
+
import { collection } from '@prisma-next/mongo-query-builder/contract-free';
|
|
11
16
|
import type { MongoSchemaIR } from '@prisma-next/mongo-schema-ir';
|
|
17
|
+
import type { MongoValue } from '@prisma-next/mongo-value';
|
|
18
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
12
19
|
import type { Document } from 'mongodb';
|
|
20
|
+
import { createMongoAdapter } from '../mongo-adapter';
|
|
13
21
|
import { introspectSchema } from './introspect-schema';
|
|
14
22
|
import {
|
|
15
|
-
COLLECTION,
|
|
16
|
-
executeAggregate,
|
|
17
|
-
executeFindOneAndUpdate,
|
|
18
|
-
executeInsertOne,
|
|
19
23
|
MONGO_LEDGER_COLLECTION,
|
|
20
24
|
MONGO_MARKER_COLLECTION,
|
|
21
25
|
parseMongoMarkerDocSafely,
|
|
22
26
|
} from './marker-ledger';
|
|
27
|
+
import { MARKER_LEDGER_COLLECTION, type MarkerLedgerDocShape } from './marker-ledger-collection';
|
|
28
|
+
import { isMongoControlDriver } from './mongo-control-driver';
|
|
23
29
|
import { extractDb } from './runner-deps';
|
|
24
30
|
|
|
25
31
|
/**
|
|
26
32
|
* Mongo control adapter for control-plane operations like introspection
|
|
27
33
|
* and marker-ledger CAS. Implements the family-level `MongoControlAdapter`
|
|
28
|
-
* SPI
|
|
29
|
-
*
|
|
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()`.
|
|
30
39
|
*/
|
|
31
40
|
export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
32
41
|
readonly familyId = 'mongo' as const;
|
|
33
42
|
readonly targetId = 'mongo' as const;
|
|
43
|
+
readonly #adapter: MongoAdapter = createMongoAdapter();
|
|
44
|
+
readonly #markerLedgerCollection = collection<MarkerLedgerDocShape>(MARKER_LEDGER_COLLECTION);
|
|
45
|
+
|
|
46
|
+
async #execute(
|
|
47
|
+
driver: ControlDriverInstance<'mongo', 'mongo'>,
|
|
48
|
+
command: AnyMongoCommand,
|
|
49
|
+
): Promise<Document[]> {
|
|
50
|
+
const plan: MongoQueryPlan = {
|
|
51
|
+
collection: MARKER_LEDGER_COLLECTION,
|
|
52
|
+
command,
|
|
53
|
+
meta: { target: 'mongo', targetFamily: 'mongo', storageHash: '', lane: 'control' },
|
|
54
|
+
};
|
|
55
|
+
const wireCommand = await this.#adapter.lower(plan, {});
|
|
56
|
+
if (!isMongoControlDriver(driver)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
'Mongo control adapter requires a Mongo control driver with an execute() transport. ' +
|
|
59
|
+
'Provide a MongoControlDriver from `@prisma-next/driver-mongo/control`.',
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const rows: Document[] = [];
|
|
63
|
+
for await (const row of driver.execute<Document>(wireCommand)) {
|
|
64
|
+
rows.push(row);
|
|
65
|
+
}
|
|
66
|
+
return rows;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Server-side invariant-merge aggregation expression:
|
|
71
|
+
* `$sortArray({ input: $setUnion([$ifNull('$invariants', []), incoming]), sortBy: 1 })`.
|
|
72
|
+
*
|
|
73
|
+
* Built through the typed agg-expr layer — `fn.setUnion` plus the generic
|
|
74
|
+
* `MongoAggOperator` for `$ifNull` / `$sortArray` (neither has a named `fn`
|
|
75
|
+
* helper). Returns a `MongoAggOperator` that is passed directly to
|
|
76
|
+
* `f.stage.set({ invariants: ... })` in the update pipeline.
|
|
77
|
+
*/
|
|
78
|
+
#invariantMergeExpr(incoming: readonly string[]): MongoAggOperator {
|
|
79
|
+
const existingOrEmpty = MongoAggOperator.of('$ifNull', [
|
|
80
|
+
MongoAggFieldRef.of('invariants'),
|
|
81
|
+
MongoAggLiteral.of([]),
|
|
82
|
+
]);
|
|
83
|
+
const merged = fn.setUnion(
|
|
84
|
+
{ _field: { codecId: 'mongo/array@1', nullable: false }, node: existingOrEmpty },
|
|
85
|
+
{
|
|
86
|
+
_field: { codecId: 'mongo/array@1', nullable: false },
|
|
87
|
+
node: MongoAggLiteral.of([...incoming]),
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
return MongoAggOperator.of('$sortArray', { input: merged.node, sortBy: MongoAggLiteral.of(1) });
|
|
91
|
+
}
|
|
34
92
|
|
|
35
93
|
async readMarker(
|
|
36
94
|
driver: ControlDriverInstance<'mongo', 'mongo'>,
|
|
37
95
|
space: string,
|
|
38
96
|
): Promise<ContractMarkerRecord | null> {
|
|
39
|
-
const db = extractDb(driver);
|
|
40
97
|
const markerContext = { space, markerLocation: MONGO_MARKER_COLLECTION };
|
|
41
98
|
const docs = await withMarkerReadErrorHandling(
|
|
42
99
|
() =>
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
100
|
+
this.#execute(
|
|
101
|
+
driver,
|
|
102
|
+
this.#markerLedgerCollection
|
|
103
|
+
.aggregate()
|
|
104
|
+
.match((f) => f._id.eq(space))
|
|
105
|
+
.match((f) => f.space.eq(space))
|
|
106
|
+
.limit(1)
|
|
107
|
+
.build(),
|
|
46
108
|
),
|
|
47
109
|
markerContext,
|
|
48
110
|
);
|
|
@@ -54,21 +116,17 @@ export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
54
116
|
async readAllMarkers(
|
|
55
117
|
driver: ControlDriverInstance<'mongo', 'mongo'>,
|
|
56
118
|
): Promise<ReadonlyMap<string, ContractMarkerRecord>> {
|
|
57
|
-
const db = extractDb(driver);
|
|
58
119
|
const markerContext = { space: 'app', markerLocation: MONGO_MARKER_COLLECTION };
|
|
59
120
|
const docs = await withMarkerReadErrorHandling(
|
|
60
121
|
() =>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
]),
|
|
122
|
+
this.#execute(
|
|
123
|
+
driver,
|
|
124
|
+
this.#markerLedgerCollection
|
|
125
|
+
.aggregate()
|
|
126
|
+
.match((f) => f._id.type('string'))
|
|
127
|
+
.match((f) => f.space.type('string'))
|
|
128
|
+
.match((f) => expr(fn.eq(f._id, f.space)))
|
|
129
|
+
.build(),
|
|
72
130
|
),
|
|
73
131
|
markerContext,
|
|
74
132
|
);
|
|
@@ -91,8 +149,7 @@ export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
91
149
|
readonly invariants?: readonly string[];
|
|
92
150
|
},
|
|
93
151
|
): Promise<void> {
|
|
94
|
-
const
|
|
95
|
-
const cmd = new RawInsertOneCommand(COLLECTION, {
|
|
152
|
+
const document: Record<string, MongoValue> = {
|
|
96
153
|
_id: space,
|
|
97
154
|
space,
|
|
98
155
|
storageHash: destination.storageHash,
|
|
@@ -102,9 +159,9 @@ export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
102
159
|
updatedAt: new Date(),
|
|
103
160
|
appTag: null,
|
|
104
161
|
meta: {},
|
|
105
|
-
invariants: destination.invariants ?? [],
|
|
106
|
-
}
|
|
107
|
-
await
|
|
162
|
+
invariants: [...(destination.invariants ?? [])],
|
|
163
|
+
};
|
|
164
|
+
await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));
|
|
108
165
|
}
|
|
109
166
|
|
|
110
167
|
async updateMarker(
|
|
@@ -117,38 +174,34 @@ export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
117
174
|
readonly invariants?: readonly string[];
|
|
118
175
|
},
|
|
119
176
|
): Promise<boolean> {
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
177
|
+
const { invariants } = destination;
|
|
178
|
+
const docs = await this.#execute(
|
|
179
|
+
driver,
|
|
180
|
+
this.#markerLedgerCollection
|
|
181
|
+
.match((f) => f._id.eq(space))
|
|
182
|
+
.match((f) => f.space.eq(space))
|
|
183
|
+
.match((f) => f.storageHash.eq(expectedFrom))
|
|
184
|
+
.findOneAndUpdate(
|
|
185
|
+
(f) => [
|
|
186
|
+
f.stage.set(
|
|
187
|
+
invariants === undefined
|
|
188
|
+
? {
|
|
189
|
+
storageHash: MongoAggLiteral.of(destination.storageHash),
|
|
190
|
+
profileHash: MongoAggLiteral.of(destination.profileHash),
|
|
191
|
+
updatedAt: MongoAggLiteral.of(new Date()),
|
|
192
|
+
}
|
|
193
|
+
: {
|
|
194
|
+
storageHash: MongoAggLiteral.of(destination.storageHash),
|
|
195
|
+
profileHash: MongoAggLiteral.of(destination.profileHash),
|
|
196
|
+
updatedAt: MongoAggLiteral.of(new Date()),
|
|
197
|
+
invariants: this.#invariantMergeExpr(invariants),
|
|
139
198
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const cmd = new RawFindOneAndUpdateCommand(
|
|
145
|
-
COLLECTION,
|
|
146
|
-
{ _id: space, space, storageHash: expectedFrom },
|
|
147
|
-
update,
|
|
148
|
-
false,
|
|
199
|
+
),
|
|
200
|
+
],
|
|
201
|
+
{ upsert: false },
|
|
202
|
+
),
|
|
149
203
|
);
|
|
150
|
-
|
|
151
|
-
return result !== null;
|
|
204
|
+
return docs.length > 0;
|
|
152
205
|
}
|
|
153
206
|
|
|
154
207
|
async writeLedgerEntry(
|
|
@@ -163,8 +216,7 @@ export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
163
216
|
readonly operations: readonly unknown[];
|
|
164
217
|
},
|
|
165
218
|
): Promise<void> {
|
|
166
|
-
const
|
|
167
|
-
const cmd = new RawInsertOneCommand(COLLECTION, {
|
|
219
|
+
const document: Record<string, MongoValue> = {
|
|
168
220
|
type: 'ledger',
|
|
169
221
|
space,
|
|
170
222
|
edgeId: entry.edgeId,
|
|
@@ -172,28 +224,29 @@ export class MongoControlAdapterImpl implements MongoControlAdapter<'mongo'> {
|
|
|
172
224
|
to: entry.to,
|
|
173
225
|
migrationName: entry.migrationName,
|
|
174
226
|
migrationHash: entry.migrationHash,
|
|
175
|
-
operations:
|
|
227
|
+
operations: blindCast<ReadonlyArray<MongoValue>, 'ledger operation docs are BSON values'>(
|
|
228
|
+
entry.operations,
|
|
229
|
+
),
|
|
176
230
|
appliedAt: new Date(),
|
|
177
|
-
}
|
|
178
|
-
await
|
|
231
|
+
};
|
|
232
|
+
await this.#execute(driver, this.#markerLedgerCollection.insertOne(document));
|
|
179
233
|
}
|
|
180
234
|
|
|
181
235
|
async readLedger(
|
|
182
236
|
driver: ControlDriverInstance<'mongo', 'mongo'>,
|
|
183
237
|
space?: string,
|
|
184
238
|
): Promise<readonly LedgerEntryRecord[]> {
|
|
185
|
-
const db = extractDb(driver);
|
|
186
239
|
const ledgerContext = { space: space ?? '*', markerLocation: MONGO_LEDGER_COLLECTION };
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
240
|
+
const chain = this.#markerLedgerCollection.aggregate().match((f) => f.type.eq('ledger'));
|
|
241
|
+
const command =
|
|
242
|
+
space === undefined
|
|
243
|
+
? chain.sort({ _id: 1 }).build()
|
|
244
|
+
: chain
|
|
245
|
+
.match((f) => f.space.eq(space))
|
|
246
|
+
.sort({ _id: 1 })
|
|
247
|
+
.build();
|
|
191
248
|
const docs = await withMarkerReadErrorHandling(
|
|
192
|
-
() =>
|
|
193
|
-
executeAggregate(
|
|
194
|
-
db,
|
|
195
|
-
new RawAggregateCommand(COLLECTION, [{ $match: matchStage }, { $sort: { _id: 1 } }]),
|
|
196
|
-
),
|
|
249
|
+
() => this.#execute(driver, command),
|
|
197
250
|
ledgerContext,
|
|
198
251
|
);
|
|
199
252
|
|
|
@@ -4,5 +4,10 @@ import type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';
|
|
|
4
4
|
export function isMongoControlDriver(
|
|
5
5
|
driver: ControlDriverInstance<'mongo', string>,
|
|
6
6
|
): driver is MongoControlDriverInstance {
|
|
7
|
-
return
|
|
7
|
+
return (
|
|
8
|
+
driver.familyId === 'mongo' &&
|
|
9
|
+
driver.targetId === 'mongo' &&
|
|
10
|
+
'execute' in driver &&
|
|
11
|
+
typeof driver.execute === 'function'
|
|
12
|
+
);
|
|
8
13
|
}
|
package/src/exports/control.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';
|
|
2
1
|
import type { MongoControlAdapterDescriptor } from '@prisma-next/family-mongo/control-adapter';
|
|
3
|
-
import type {
|
|
4
|
-
import type { Db } from 'mongodb';
|
|
2
|
+
import type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';
|
|
5
3
|
|
|
6
|
-
export type { MongoControlDriverInstance } from '@prisma-next/mongo-lowering';
|
|
7
4
|
export { MongoCommandExecutor, MongoInspectionExecutor } from '../core/command-executor';
|
|
8
5
|
export { introspectSchema } from '../core/introspect-schema';
|
|
9
6
|
export { MongoControlAdapterImpl } from '../core/mongo-control-adapter';
|
|
@@ -15,78 +12,11 @@ export {
|
|
|
15
12
|
type MongoRunnerDependencies,
|
|
16
13
|
} from '../core/runner-deps';
|
|
17
14
|
export { createMongoAdapter } from '../mongo-adapter';
|
|
15
|
+
export type { MongoControlDriverInstance };
|
|
18
16
|
|
|
19
17
|
import { mongoCodecDescriptors } from '../core/codecs';
|
|
20
18
|
import { MongoControlAdapterImpl } from '../core/mongo-control-adapter';
|
|
21
19
|
|
|
22
|
-
const defaultControlAdapter = new MongoControlAdapterImpl();
|
|
23
|
-
|
|
24
|
-
function controlDriverFromDb(db: Db): ControlDriverInstance<'mongo', 'mongo'> & { db: Db } {
|
|
25
|
-
return {
|
|
26
|
-
familyId: 'mongo',
|
|
27
|
-
targetId: 'mongo',
|
|
28
|
-
db,
|
|
29
|
-
close: async () => {},
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function readMarker(db: Db, space: string): Promise<ContractMarkerRecord | null> {
|
|
34
|
-
return defaultControlAdapter.readMarker(controlDriverFromDb(db), space);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function readAllMarkers(db: Db): Promise<ReadonlyMap<string, ContractMarkerRecord>> {
|
|
38
|
-
return defaultControlAdapter.readAllMarkers(controlDriverFromDb(db));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function initMarker(
|
|
42
|
-
db: Db,
|
|
43
|
-
space: string,
|
|
44
|
-
destination: {
|
|
45
|
-
readonly storageHash: string;
|
|
46
|
-
readonly profileHash: string;
|
|
47
|
-
readonly invariants?: readonly string[];
|
|
48
|
-
},
|
|
49
|
-
): Promise<void> {
|
|
50
|
-
await defaultControlAdapter.initMarker(controlDriverFromDb(db), space, destination);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function updateMarker(
|
|
54
|
-
db: Db,
|
|
55
|
-
space: string,
|
|
56
|
-
expectedFrom: string,
|
|
57
|
-
destination: {
|
|
58
|
-
readonly storageHash: string;
|
|
59
|
-
readonly profileHash: string;
|
|
60
|
-
readonly invariants?: readonly string[];
|
|
61
|
-
},
|
|
62
|
-
): Promise<boolean> {
|
|
63
|
-
return defaultControlAdapter.updateMarker(
|
|
64
|
-
controlDriverFromDb(db),
|
|
65
|
-
space,
|
|
66
|
-
expectedFrom,
|
|
67
|
-
destination,
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export async function readLedger(db: Db, space?: string): Promise<readonly LedgerEntryRecord[]> {
|
|
72
|
-
return defaultControlAdapter.readLedger(controlDriverFromDb(db), space);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export async function writeLedgerEntry(
|
|
76
|
-
db: Db,
|
|
77
|
-
space: string,
|
|
78
|
-
entry: {
|
|
79
|
-
readonly edgeId: string;
|
|
80
|
-
readonly from: string;
|
|
81
|
-
readonly to: string;
|
|
82
|
-
readonly migrationName: string;
|
|
83
|
-
readonly migrationHash: string;
|
|
84
|
-
readonly operations: readonly unknown[];
|
|
85
|
-
},
|
|
86
|
-
): Promise<void> {
|
|
87
|
-
await defaultControlAdapter.writeLedgerEntry(controlDriverFromDb(db), space, entry);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
20
|
export const mongoAdapterDescriptor: MongoControlAdapterDescriptor<'mongo'> = {
|
|
91
21
|
kind: 'adapter',
|
|
92
22
|
id: 'mongo',
|