monsqlize 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -769,31 +769,51 @@ async function runModelV1Hook(hooksFactory, model, operation, phase, context, ..
769
769
  }
770
770
  return hook(context, ...args);
771
771
  }
772
+ function mapModelSchemaValidationErrors(errors = []) {
773
+ return errors.map((error) => ({
774
+ field: error.path ?? "",
775
+ message: error.message ?? ""
776
+ }));
777
+ }
772
778
  function validateModelSchemaPayload(context, document, options, metadata = {}) {
773
779
  const shouldValidate = context.validateEnabled || options?.validate === true;
774
780
  if (!shouldValidate) {
775
- return;
781
+ return document;
776
782
  }
777
783
  if (options?.skipValidation) {
778
- return;
784
+ return document;
779
785
  }
780
786
  if (!context.schemaCache || !context.schemaValidateFn) {
781
- return;
787
+ return document;
782
788
  }
783
789
  const result = context.schemaValidateFn(context.schemaCache, document);
784
- if (result.valid) {
785
- return;
790
+ if (!result.valid) {
791
+ const errors = mapModelSchemaValidationErrors(result.errors);
792
+ const fields = [...new Set(errors.map((item) => item.field).filter(Boolean))];
793
+ const summary = fields.length > 0 ? ` (${fields.join(", ")})` : "";
794
+ throw withModelErrorMetadata(
795
+ createError(ErrorCodes.VALIDATION_ERROR, `Schema validation failed${summary}`),
796
+ {
797
+ errors,
798
+ ...metadata
799
+ }
800
+ );
786
801
  }
787
- const errors = result.errors ?? [];
788
- const fields = [...new Set(errors.map((item) => item.path ?? item.field).filter(Boolean))];
789
- const summary = fields.length > 0 ? ` (${fields.join(", ")})` : "";
790
- throw withModelErrorMetadata(
791
- createError(ErrorCodes.VALIDATION_ERROR, `Schema validation failed${summary}`),
792
- {
793
- errors,
794
- ...metadata
795
- }
796
- );
802
+ const normalized = result.data === void 0 ? document : result.data;
803
+ if (normalized === null || typeof normalized !== "object" || Array.isArray(normalized)) {
804
+ const errors = [{
805
+ field: "_schema",
806
+ message: "Schema validation returned non-object data for a complete-document write."
807
+ }];
808
+ throw withModelErrorMetadata(
809
+ createError(ErrorCodes.VALIDATION_ERROR, errors[0].message),
810
+ {
811
+ errors,
812
+ ...metadata
813
+ }
814
+ );
815
+ }
816
+ return normalized;
797
817
  }
798
818
  function applyModelSoftDeleteFilter(query, options, softDeleteConfig) {
799
819
  if (!softDeleteConfig?.enabled) {
@@ -999,6 +1019,19 @@ function applyModelReplaceTimestamps(replacement, timestampsConfig, nowFactory)
999
1019
  [timestampsConfig.updatedAt]: nowFactory()
1000
1020
  };
1001
1021
  }
1022
+ function preserveModelReplaceCreatedAt(original, normalized, timestampsConfig) {
1023
+ if (!timestampsConfig || timestampsConfig.createdAt === false) {
1024
+ return normalized;
1025
+ }
1026
+ const field = timestampsConfig.createdAt;
1027
+ if (normalized[field] !== void 0 || original[field] === void 0) {
1028
+ return normalized;
1029
+ }
1030
+ return {
1031
+ ...normalized,
1032
+ [field]: original[field]
1033
+ };
1034
+ }
1002
1035
 
1003
1036
  // src/capabilities/model/model-instance-helpers.ts
1004
1037
  var DEFAULT_POPULATE_MAX_DEPTH = 5;
@@ -1219,11 +1252,8 @@ function validateModelDocument(runtime, document) {
1219
1252
  const result = runtime.schemaValidateFn(runtime.schemaCache, document ?? {});
1220
1253
  return {
1221
1254
  valid: result.valid,
1222
- errors: (result.errors ?? []).map((error) => ({
1223
- field: error.field ?? error.path ?? "",
1224
- message: error.message ?? ""
1225
- })),
1226
- data: result.data ?? document
1255
+ errors: mapModelSchemaValidationErrors(result.errors),
1256
+ data: result.data === void 0 ? document : result.data
1227
1257
  };
1228
1258
  } catch (error) {
1229
1259
  return {
@@ -1243,44 +1273,87 @@ function applyModelDefaults(definition, document) {
1243
1273
  }
1244
1274
  return payload;
1245
1275
  }
1276
+ function serializeModelWriteDocument(document) {
1277
+ const payload = serializeDocument(document);
1278
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(document))) {
1279
+ if (descriptor.get || descriptor.set) {
1280
+ delete payload[key];
1281
+ }
1282
+ }
1283
+ return payload;
1284
+ }
1285
+ function replaceModelDocumentData(document, payload) {
1286
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(document))) {
1287
+ if (!descriptor.enumerable || descriptor.get || descriptor.set || typeof descriptor.value === "function") {
1288
+ continue;
1289
+ }
1290
+ if (!Object.prototype.hasOwnProperty.call(payload, key) && descriptor.configurable !== false) {
1291
+ delete document[key];
1292
+ }
1293
+ }
1294
+ for (const [key, value] of Object.entries(payload)) {
1295
+ const descriptor = Object.getOwnPropertyDescriptor(document, key);
1296
+ if (descriptor?.get || descriptor?.set || descriptor?.writable === false) {
1297
+ continue;
1298
+ }
1299
+ document[key] = value;
1300
+ }
1301
+ }
1246
1302
  async function saveModelDocument(collection, document, options = {}) {
1247
1303
  const nowFactory = options.nowFactory ?? (() => /* @__PURE__ */ new Date());
1248
- let payload = serializeDocument(document);
1304
+ let payload = serializeModelWriteDocument(document);
1249
1305
  if (payload._id !== void 0) {
1306
+ const documentId = payload._id;
1250
1307
  if (options.versionConfig?.enabled) {
1251
1308
  const expectedVersion = assertNumericExpectedVersion(payload[options.versionConfig.field], "save");
1252
- const replacement = applyModelReplaceVersion(
1309
+ if (options.schemaValidationContext) {
1310
+ payload = preserveModelReplaceCreatedAt(
1311
+ serializeModelWriteDocument(document),
1312
+ validateModelSchemaPayload(options.schemaValidationContext, payload),
1313
+ options.timestampsConfig ?? null
1314
+ );
1315
+ }
1316
+ const replacement2 = applyModelReplaceVersion(
1253
1317
  applyModelReplaceTimestamps(payload, options.timestampsConfig ?? null, nowFactory),
1254
1318
  options.versionConfig,
1255
1319
  expectedVersion
1256
1320
  );
1257
- if (options.schemaValidationContext) {
1258
- validateModelSchemaPayload(options.schemaValidationContext, replacement);
1259
- }
1260
1321
  const result2 = await collection.replaceOne(
1261
- { _id: payload._id, [options.versionConfig.field]: expectedVersion },
1262
- replacement,
1322
+ { _id: documentId, [options.versionConfig.field]: expectedVersion },
1323
+ replacement2,
1263
1324
  { upsert: false }
1264
1325
  );
1265
1326
  assertModelOptimisticLockMatched(result2, options.versionConfig);
1266
- Object.assign(document, replacement);
1327
+ replaceModelDocumentData(document, replacement2);
1328
+ document._id = documentId;
1267
1329
  return document;
1268
1330
  }
1269
1331
  if (options.schemaValidationContext) {
1270
- validateModelSchemaPayload(options.schemaValidationContext, payload);
1332
+ payload = preserveModelReplaceCreatedAt(
1333
+ serializeModelWriteDocument(document),
1334
+ validateModelSchemaPayload(options.schemaValidationContext, payload),
1335
+ options.timestampsConfig ?? null
1336
+ );
1271
1337
  }
1272
- await collection.replaceOne({ _id: payload._id }, payload, { upsert: true });
1338
+ const replacement = applyModelReplaceTimestamps(
1339
+ payload,
1340
+ options.timestampsConfig ?? null,
1341
+ nowFactory
1342
+ );
1343
+ await collection.replaceOne({ _id: documentId }, replacement, { upsert: true });
1344
+ replaceModelDocumentData(document, replacement);
1345
+ document._id = documentId;
1273
1346
  return document;
1274
1347
  }
1348
+ if (options.schemaValidationContext) {
1349
+ payload = validateModelSchemaPayload(options.schemaValidationContext, payload);
1350
+ }
1275
1351
  payload = applyModelInsertVersion(
1276
1352
  applyModelInsertTimestamps(payload, options.timestampsConfig ?? null, nowFactory),
1277
1353
  options.versionConfig ?? null
1278
1354
  );
1279
- if (options.schemaValidationContext) {
1280
- validateModelSchemaPayload(options.schemaValidationContext, payload);
1281
- }
1282
1355
  const result = await collection.insertOne(payload);
1283
- Object.assign(document, payload);
1356
+ replaceModelDocumentData(document, payload);
1284
1357
  document._id = result.insertedId;
1285
1358
  return document;
1286
1359
  }
@@ -5078,7 +5151,7 @@ async function orchestrateModelInsertOne(context, document, options) {
5078
5151
  } else {
5079
5152
  await invokeStandardOperationHook(context, "insert", "before", { operation: "insertOne", collection: context.collectionName, data: payload });
5080
5153
  }
5081
- validateModelSchemaPayload({
5154
+ payload = validateModelSchemaPayload({
5082
5155
  validateEnabled: context.validateEnabled,
5083
5156
  schemaCache: context.schemaCache,
5084
5157
  schemaValidateFn: context.schemaValidateFn
@@ -5103,23 +5176,23 @@ async function orchestrateModelInsertOne(context, document, options) {
5103
5176
  }
5104
5177
  async function orchestrateModelInsertMany(context, documents, options) {
5105
5178
  const hookContext = {};
5179
+ const docs = (documents ?? []).map((document) => context.applyDefaults(document));
5106
5180
  if (context.hooksFactory) {
5107
- await invokeV1Hook(context, "insert", "before", hookContext, documents);
5181
+ await invokeV1Hook(context, "insert", "before", hookContext, docs);
5108
5182
  } else {
5109
- await invokeStandardOperationHook(context, "insert", "before", { operation: "insertMany", collection: context.collectionName, data: documents });
5183
+ await invokeStandardOperationHook(context, "insert", "before", { operation: "insertMany", collection: context.collectionName, data: docs });
5110
5184
  }
5111
5185
  const resolvedOptions = options ?? {};
5112
- const docs = [];
5113
- for (let index = 0; index < (documents ?? []).length; index++) {
5114
- let doc = context.applyDefaults((documents ?? [])[index]);
5115
- validateModelSchemaPayload({
5186
+ for (let index = 0; index < docs.length; index++) {
5187
+ let doc = docs[index];
5188
+ doc = validateModelSchemaPayload({
5116
5189
  validateEnabled: context.validateEnabled,
5117
5190
  schemaCache: context.schemaCache,
5118
5191
  schemaValidateFn: context.schemaValidateFn
5119
5192
  }, doc, resolvedOptions, { index });
5120
5193
  doc = applyModelInsertTimestamps(doc, context.timestampsConfig, () => context.nowDate());
5121
5194
  doc = applyModelInsertVersion(doc, context.versionConfig);
5122
- docs.push(doc);
5195
+ docs[index] = doc;
5123
5196
  }
5124
5197
  const result = await context.collection.insertMany(docs, options);
5125
5198
  if (context.hooksFactory) {
@@ -5197,17 +5270,22 @@ async function orchestrateModelReplaceOne(context, filter, replacement, options)
5197
5270
  } else {
5198
5271
  await invokeStandardOperationHook(context, "update", "before", { operation: "replaceOne", collection: context.collectionName, filter, update: replacement });
5199
5272
  }
5273
+ let nextReplacement = validateModelSchemaPayload({
5274
+ validateEnabled: context.validateEnabled,
5275
+ schemaCache: context.schemaCache,
5276
+ schemaValidateFn: context.schemaValidateFn
5277
+ }, replacement, options);
5278
+ nextReplacement = preserveModelReplaceCreatedAt(
5279
+ replacement,
5280
+ nextReplacement,
5281
+ context.timestampsConfig
5282
+ );
5200
5283
  const lock = await resolveModelOptimisticLockAsync(context.collection, filter, options, context.versionConfig, "replaceOne");
5201
- const nextReplacement = applyModelReplaceVersion(
5202
- applyModelReplaceTimestamps(replacement, context.timestampsConfig, () => context.nowDate()),
5284
+ nextReplacement = applyModelReplaceVersion(
5285
+ applyModelReplaceTimestamps(nextReplacement, context.timestampsConfig, () => context.nowDate()),
5203
5286
  context.versionConfig,
5204
5287
  lock.expectedVersion
5205
5288
  );
5206
- validateModelSchemaPayload({
5207
- validateEnabled: context.validateEnabled,
5208
- schemaCache: context.schemaCache,
5209
- schemaValidateFn: context.schemaValidateFn
5210
- }, nextReplacement, lock.driverOptions);
5211
5289
  const result = await context.collection.replaceOne(lock.filter, nextReplacement, lock.driverOptions);
5212
5290
  assertModelOptimisticLockMatched(result, context.versionConfig);
5213
5291
  if (context.hooksFactory) {
@@ -5251,17 +5329,22 @@ async function orchestrateModelFindOneAndReplace(context, filter, replacement, o
5251
5329
  } else {
5252
5330
  await invokeStandardOperationHook(context, "update", "before", { operation: "findOneAndReplace", collection: context.collectionName, filter, update: replacement });
5253
5331
  }
5332
+ let nextReplacement = validateModelSchemaPayload({
5333
+ validateEnabled: context.validateEnabled,
5334
+ schemaCache: context.schemaCache,
5335
+ schemaValidateFn: context.schemaValidateFn
5336
+ }, replacement, options);
5337
+ nextReplacement = preserveModelReplaceCreatedAt(
5338
+ replacement,
5339
+ nextReplacement,
5340
+ context.timestampsConfig
5341
+ );
5254
5342
  const lock = await resolveModelOptimisticLockAsync(context.collection, filter, options, context.versionConfig, "findOneAndReplace");
5255
- const nextReplacement = applyModelReplaceVersion(
5256
- applyModelReplaceTimestamps(replacement, context.timestampsConfig, () => context.nowDate()),
5343
+ nextReplacement = applyModelReplaceVersion(
5344
+ applyModelReplaceTimestamps(nextReplacement, context.timestampsConfig, () => context.nowDate()),
5257
5345
  context.versionConfig,
5258
5346
  lock.expectedVersion
5259
5347
  );
5260
- validateModelSchemaPayload({
5261
- validateEnabled: context.validateEnabled,
5262
- schemaCache: context.schemaCache,
5263
- schemaValidateFn: context.schemaValidateFn
5264
- }, nextReplacement, lock.driverOptions);
5265
5348
  const result = await context.extendedCollection().findOneAndReplace(lock.filter, nextReplacement, lock.driverOptions);
5266
5349
  assertModelOptimisticLockDocument(result, context.versionConfig);
5267
5350
  if (context.hooksFactory) {
@@ -5349,23 +5432,24 @@ async function orchestrateModelIncrementOne(context, filter, field, increment, o
5349
5432
  }
5350
5433
  async function orchestrateModelInsertBatch(context, docs, options) {
5351
5434
  const hookContext = {};
5435
+ const docsToInsert = docs.map((doc) => context.applyDefaults(doc));
5352
5436
  if (context.hooksFactory) {
5353
- await invokeV1Hook(context, "insert", "before", hookContext, docs);
5437
+ await invokeV1Hook(context, "insert", "before", hookContext, docsToInsert);
5354
5438
  } else {
5355
- await invokeStandardOperationHook(context, "insert", "before", { operation: "insertBatch", collection: context.collectionName, data: docs });
5439
+ await invokeStandardOperationHook(context, "insert", "before", { operation: "insertBatch", collection: context.collectionName, data: docsToInsert });
5356
5440
  }
5357
5441
  const resolvedOptions = options ?? {};
5358
- const docsToInsert = docs.map((doc, index) => {
5359
- let record = context.applyDefaults(doc);
5360
- validateModelSchemaPayload({
5442
+ for (let index = 0; index < docsToInsert.length; index++) {
5443
+ let record = docsToInsert[index];
5444
+ record = validateModelSchemaPayload({
5361
5445
  validateEnabled: context.validateEnabled,
5362
5446
  schemaCache: context.schemaCache,
5363
5447
  schemaValidateFn: context.schemaValidateFn
5364
5448
  }, record, resolvedOptions, { index });
5365
5449
  record = applyModelInsertTimestamps(record, context.timestampsConfig, () => context.nowDate());
5366
5450
  record = applyModelInsertVersion(record, context.versionConfig);
5367
- return record;
5368
- });
5451
+ docsToInsert[index] = record;
5452
+ }
5369
5453
  const result = await context.extendedCollection().insertBatch(docsToInsert, options);
5370
5454
  if (context.hooksFactory) {
5371
5455
  try {
@@ -6482,9 +6566,28 @@ async function sleep(ms) {
6482
6566
  var import_node_fs = require("node:fs");
6483
6567
  var import_node_path = __toESM(require("node:path"));
6484
6568
  var import_mongodb3 = require("mongodb");
6485
- var DEFAULT_MEMORY_SERVER_VERSION = "7.0.14";
6569
+
6570
+ // config/mongodb-memory-server.json
6571
+ var mongodb_memory_server_default = {
6572
+ defaultVersion: "7.0.37",
6573
+ requiredVersions: [
6574
+ { label: "MongoDB 7.0", version: "7.0.37" },
6575
+ { label: "MongoDB 8.0", version: "8.0.26" }
6576
+ ],
6577
+ managedDbPathKinds: [
6578
+ "single",
6579
+ "replset",
6580
+ "examples-single",
6581
+ "examples-replset",
6582
+ "probe-single",
6583
+ "probe-replset"
6584
+ ]
6585
+ };
6586
+
6587
+ // src/adapters/mongodb/common/connect.ts
6588
+ var DEFAULT_MEMORY_SERVER_VERSION = mongodb_memory_server_default.defaultVersion;
6486
6589
  var DEFAULT_MEMORY_SERVER_LAUNCH_TIMEOUT_MS = 3e4;
6487
- var MANAGED_DB_PATH_PREFIXES = ["single-", "replset-", "examples-single-", "examples-replset-", "probe-single-", "probe-replset-"];
6590
+ var MANAGED_DB_PATH_PREFIXES = mongodb_memory_server_default.managedDbPathKinds.map((kind) => `${kind}-`);
6488
6591
  var _memoryServerInstance = null;
6489
6592
  var _memoryServerStartPromise = null;
6490
6593
  var _memoryServerCleanupOptions = { doCleanup: true, force: true };