couchset 0.2.7 → 0.4.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +292 -152
  3. package/dist/connection/connection.d.ts +68 -0
  4. package/dist/connection/connection.js +495 -0
  5. package/dist/connection/connection.js.map +1 -0
  6. package/dist/connection/env.d.ts +2 -0
  7. package/dist/connection/env.js +16 -0
  8. package/dist/connection/env.js.map +1 -0
  9. package/dist/connection/index.d.ts +3 -0
  10. package/dist/connection/index.js +25 -0
  11. package/dist/connection/index.js.map +1 -0
  12. package/dist/connection/types.d.ts +25 -0
  13. package/dist/connection/types.js +3 -0
  14. package/dist/connection/types.js.map +1 -0
  15. package/dist/database.d.ts +9 -0
  16. package/dist/database.js +196 -0
  17. package/dist/database.js.map +1 -0
  18. package/dist/index.d.ts +20 -6
  19. package/dist/index.js +55 -8
  20. package/dist/index.js.map +1 -1
  21. package/dist/legacy/connection.d.ts +2 -0
  22. package/dist/legacy/connection.js +24 -0
  23. package/dist/legacy/connection.js.map +1 -0
  24. package/dist/legacy/index.d.ts +10 -0
  25. package/dist/legacy/index.js +93 -0
  26. package/dist/legacy/index.js.map +1 -0
  27. package/dist/legacy/model.d.ts +55 -0
  28. package/dist/legacy/model.js +282 -0
  29. package/dist/legacy/model.js.map +1 -0
  30. package/dist/legacy/pagination/index.d.ts +1 -0
  31. package/dist/legacy/pagination/index.js +18 -0
  32. package/dist/legacy/pagination/index.js.map +1 -0
  33. package/dist/legacy/pagination/pagination.d.ts +12 -0
  34. package/dist/legacy/pagination/pagination.js +85 -0
  35. package/dist/legacy/pagination/pagination.js.map +1 -0
  36. package/dist/legacy/search/customQuery.d.ts +13 -0
  37. package/dist/legacy/search/customQuery.js +73 -0
  38. package/dist/legacy/search/customQuery.js.map +1 -0
  39. package/dist/legacy/search/index.d.ts +1 -0
  40. package/dist/legacy/search/index.js +18 -0
  41. package/dist/legacy/search/index.js.map +1 -0
  42. package/dist/model/default-scope.d.ts +10 -0
  43. package/dist/model/default-scope.js +47 -0
  44. package/dist/model/default-scope.js.map +1 -0
  45. package/dist/model/hydrated-document.d.ts +30 -0
  46. package/dist/model/hydrated-document.js +118 -0
  47. package/dist/model/hydrated-document.js.map +1 -0
  48. package/dist/model/include.d.ts +33 -0
  49. package/dist/model/include.js +250 -0
  50. package/dist/model/include.js.map +1 -0
  51. package/dist/model/index.d.ts +192 -52
  52. package/dist/model/index.js +646 -172
  53. package/dist/model/index.js.map +1 -1
  54. package/dist/model/indexes.d.ts +18 -0
  55. package/dist/model/indexes.js +155 -0
  56. package/dist/model/indexes.js.map +1 -0
  57. package/dist/model/keyspace.d.ts +9 -0
  58. package/dist/model/keyspace.js +28 -0
  59. package/dist/model/keyspace.js.map +1 -0
  60. package/dist/model/read-helpers.d.ts +36 -0
  61. package/dist/model/read-helpers.js +275 -0
  62. package/dist/model/read-helpers.js.map +1 -0
  63. package/dist/model/safe-query.d.ts +23 -0
  64. package/dist/model/safe-query.js +138 -0
  65. package/dist/model/safe-query.js.map +1 -0
  66. package/dist/model/ttl.d.ts +9 -0
  67. package/dist/model/ttl.js +73 -0
  68. package/dist/model/ttl.js.map +1 -0
  69. package/dist/model/validation.d.ts +5 -0
  70. package/dist/model/validation.js +104 -0
  71. package/dist/model/validation.js.map +1 -0
  72. package/dist/model/write-helpers.d.ts +39 -0
  73. package/dist/model/write-helpers.js +245 -0
  74. package/dist/model/write-helpers.js.map +1 -0
  75. package/dist/next.d.ts +204 -0
  76. package/dist/next.js +1190 -0
  77. package/dist/next.js.map +1 -0
  78. package/dist/next.types.d.ts +1 -0
  79. package/dist/next.types.js +38 -0
  80. package/dist/next.types.js.map +1 -0
  81. package/dist/pagination/index.d.ts +1 -0
  82. package/dist/pagination/index.js +1 -0
  83. package/dist/pagination/index.js.map +1 -1
  84. package/dist/pagination/pagination.d.ts +1 -8
  85. package/dist/pagination/pagination.js +16 -29
  86. package/dist/pagination/pagination.js.map +1 -1
  87. package/dist/pagination/safe-pagination.d.ts +15 -0
  88. package/dist/pagination/safe-pagination.js +221 -0
  89. package/dist/pagination/safe-pagination.js.map +1 -0
  90. package/dist/pagination/types.d.ts +11 -0
  91. package/dist/pagination/types.js +3 -0
  92. package/dist/pagination/types.js.map +1 -0
  93. package/dist/search/customQuery.d.ts +10 -3
  94. package/dist/search/customQuery.js +17 -18
  95. package/dist/search/customQuery.js.map +1 -1
  96. package/dist/shared/common.model.js +2 -2
  97. package/dist/shared/common.model.js.map +1 -1
  98. package/dist/timeseries/index.d.ts +1 -0
  99. package/dist/timeseries/index.js +18 -0
  100. package/dist/timeseries/index.js.map +1 -0
  101. package/dist/timeseries/time-series-model.d.ts +60 -0
  102. package/dist/timeseries/time-series-model.js +267 -0
  103. package/dist/timeseries/time-series-model.js.map +1 -0
  104. package/dist/utils/awaitTo.d.ts +1 -1
  105. package/dist/utils/awaitTo.js +1 -1
  106. package/dist/utils/awaitTo.js.map +1 -1
  107. package/docs/beta-migration.md +175 -0
  108. package/docs/document-modeling.md +133 -0
  109. package/docs/next-primitives.md +81 -0
  110. package/legacy/index.js +1 -0
  111. package/legacy/package.json +4 -0
  112. package/next/index.js +1 -0
  113. package/next/package.json +4 -0
  114. package/package.json +18 -10
  115. package/dist/connection.d.ts +0 -42
  116. package/dist/connection.js +0 -156
  117. package/dist/connection.js.map +0 -1
@@ -57,40 +57,164 @@ var __rest = (this && this.__rest) || function (s, e) {
57
57
  }
58
58
  return t;
59
59
  };
60
+ var __read = (this && this.__read) || function (o, n) {
61
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
62
+ if (!m) return o;
63
+ var i = m.call(o), r, ar = [], e;
64
+ try {
65
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
66
+ }
67
+ catch (error) { e = { error: error }; }
68
+ finally {
69
+ try {
70
+ if (r && !r.done && (m = i["return"])) m.call(i);
71
+ }
72
+ finally { if (e) throw e.error; }
73
+ }
74
+ return ar;
75
+ };
76
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
77
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
78
+ if (ar || !(i in from)) {
79
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
80
+ ar[i] = from[i];
81
+ }
82
+ }
83
+ return to.concat(ar || Array.prototype.slice.call(from));
84
+ };
85
+ var __values = (this && this.__values) || function(o) {
86
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
87
+ if (m) return m.call(o);
88
+ if (o && typeof o.length === "number") return {
89
+ next: function () {
90
+ if (o && i >= o.length) o = void 0;
91
+ return { value: o && o[i++], done: !o };
92
+ }
93
+ };
94
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
95
+ };
60
96
  var __importDefault = (this && this.__importDefault) || function (mod) {
61
97
  return (mod && mod.__esModule) ? mod : { "default": mod };
62
98
  };
63
99
  Object.defineProperty(exports, "__esModule", { value: true });
64
100
  exports.Model = void 0;
65
- // import {AutomaticMethodOptions, AutomaticOutput, automateImplementation} from '../automate';
66
- var search_1 = require("../search");
67
101
  var utils_1 = require("../utils");
68
102
  var connection_1 = __importDefault(require("../connection"));
69
- var pagination_1 = require("../pagination");
70
- var uuid_1 = require("../uuid");
103
+ var default_scope_1 = require("./default-scope");
104
+ var read_helpers_1 = require("./read-helpers");
105
+ var keyspace_1 = require("./keyspace");
106
+ var safe_query_1 = require("./safe-query");
107
+ var write_helpers_1 = require("./write-helpers");
108
+ var hydrated_document_1 = require("./hydrated-document");
109
+ var indexes_1 = require("./indexes");
110
+ var validation_1 = require("./validation");
71
111
  var Model = /** @class */ (function () {
72
- function Model(name, options) {
112
+ function Model(name, options, connection) {
73
113
  this.scope = '_default';
114
+ this.defaultWhereMode = 'default';
115
+ this.softDelete = false;
116
+ this.codecs = {};
117
+ this.indexes = [];
74
118
  this.schema = {
75
119
  createdAt: 'date',
76
120
  updatedAt: 'date',
77
121
  };
78
- this.graphqlType = null;
79
122
  // this.collection = CouchbaseConnection.Instance.getCollection();
80
123
  this.collectionName = name;
124
+ this.connection = connection;
81
125
  if (options) {
82
- this.graphqlType = (options && options.graphqlType) || null;
126
+ var hasScope = Object.prototype.hasOwnProperty.call(options, 'scope');
127
+ var hasCollection = Object.prototype.hasOwnProperty.call(options, 'collection');
83
128
  this.scope = (options && options.scope) || '_default';
84
- this.schema = __assign(__assign({}, ((options && options.schema) || {})), { createdAt: 'date', updatedAt: 'date' });
129
+ this.scopeName = hasScope ? this.scope : undefined;
130
+ this.collectionTargetName = hasCollection
131
+ ? options.collection || '_default'
132
+ : undefined;
133
+ this.softDelete = !!options.softDelete;
134
+ this.defaultWhere = options.defaultWhere;
135
+ this.validateCreateHook = options.validateCreate;
136
+ this.validateReplaceHook = options.validateReplace;
137
+ this.parseHook = options.parse;
138
+ this.dateFields = options.dateFields;
139
+ this.codecs = options.codecs || {};
140
+ var dateFields_1 = new Set(options.dateFields || []);
141
+ Object.keys(this.codecs).forEach(function (field) {
142
+ var _a;
143
+ if (dateFields_1.has(field) || ((_a = options.schema) === null || _a === void 0 ? void 0 : _a[field]) === 'date') {
144
+ throw new Error("codec for ".concat(field, " conflicts with dateFields or schema date; use one transform"));
145
+ }
146
+ });
147
+ this.indexes = options.indexes || [];
148
+ this.schema = __assign(__assign(__assign({}, ((options && options.schema) || {})), (0, validation_1.schemaFromDateFields)(options.dateFields)), { createdAt: 'date', updatedAt: 'date' });
149
+ }
150
+ // Legacy models participate in the singleton registry. Client-bound
151
+ // models are registered only by their owning CouchsetClient.
152
+ if (this.indexes.length && !this.connection) {
153
+ Model.registeredModels.push(this);
85
154
  }
86
155
  }
87
156
  /**
88
- * Set setGraphqlType
89
- * setGraphqlType
157
+ * Ensure indexes for every constructed model with index declarations.
90
158
  */
91
- Model.prototype.setGraphqlType = function (gqlType) {
92
- this.graphqlType = gqlType;
93
- return this;
159
+ Model.ensureIndexes = function (options) {
160
+ return __awaiter(this, void 0, void 0, function () {
161
+ var queries, seenQueries, _loop_1, _a, _b, model, e_1_1;
162
+ var e_1, _c;
163
+ return __generator(this, function (_d) {
164
+ switch (_d.label) {
165
+ case 0:
166
+ queries = [];
167
+ seenQueries = new Set();
168
+ _loop_1 = function (model) {
169
+ var statements, pending;
170
+ return __generator(this, function (_e) {
171
+ switch (_e.label) {
172
+ case 0: return [4 /*yield*/, model.prepare()];
173
+ case 1:
174
+ _e.sent();
175
+ statements = model.indexStatements(options);
176
+ pending = statements.filter(function (query) { return !seenQueries.has(query); });
177
+ pending.forEach(function (query) { return seenQueries.add(query); });
178
+ return [4 /*yield*/, (0, indexes_1.ensureModelIndexes)(model.couchbaseConnection().cluster, model.keyspace(), model.indexes.filter(function (index, indexPosition) {
179
+ return pending.includes(statements[indexPosition]);
180
+ }), options)];
181
+ case 2:
182
+ _e.sent();
183
+ queries.push.apply(queries, __spreadArray([], __read(pending), false));
184
+ return [2 /*return*/];
185
+ }
186
+ });
187
+ };
188
+ _d.label = 1;
189
+ case 1:
190
+ _d.trys.push([1, 6, 7, 8]);
191
+ _a = __values(Model.registeredModels), _b = _a.next();
192
+ _d.label = 2;
193
+ case 2:
194
+ if (!!_b.done) return [3 /*break*/, 5];
195
+ model = _b.value;
196
+ return [5 /*yield**/, _loop_1(model)];
197
+ case 3:
198
+ _d.sent();
199
+ _d.label = 4;
200
+ case 4:
201
+ _b = _a.next();
202
+ return [3 /*break*/, 2];
203
+ case 5: return [3 /*break*/, 8];
204
+ case 6:
205
+ e_1_1 = _d.sent();
206
+ e_1 = { error: e_1_1 };
207
+ return [3 /*break*/, 8];
208
+ case 7:
209
+ try {
210
+ if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
211
+ }
212
+ finally { if (e_1) throw e_1.error; }
213
+ return [7 /*endfinally*/];
214
+ case 8: return [2 /*return*/, queries];
215
+ }
216
+ });
217
+ });
94
218
  };
95
219
  /**
96
220
  * Refresh and get default collection from CouchbaseConnection
@@ -100,22 +224,75 @@ var Model = /** @class */ (function () {
100
224
  */
101
225
  Model.prototype.fresh = function () {
102
226
  // if couchbase connection has been init
103
- if (connection_1.default.Instance.bucketName) {
104
- this.collection = connection_1.default.Instance.getCollection();
227
+ if (this.couchbaseConnection().isConnected()) {
228
+ var target = this.collectionTarget();
229
+ this.collection = this.couchbaseConnection().getCollection(target.scopeName, target.collectionName);
105
230
  }
106
231
  };
232
+ Model.prototype.prepare = function () {
233
+ return __awaiter(this, void 0, void 0, function () {
234
+ var connection, target;
235
+ return __generator(this, function (_a) {
236
+ switch (_a.label) {
237
+ case 0:
238
+ connection = this.couchbaseConnection();
239
+ if (!!connection.bucket) return [3 /*break*/, 2];
240
+ return [4 /*yield*/, connection.ready()];
241
+ case 1:
242
+ _a.sent();
243
+ _a.label = 2;
244
+ case 2:
245
+ target = this.collectionTarget();
246
+ this.collection = connection.getCollection(target.scopeName, target.collectionName);
247
+ return [2 /*return*/];
248
+ }
249
+ });
250
+ });
251
+ };
252
+ Model.prototype.withConnection = function (operation) {
253
+ return __awaiter(this, void 0, void 0, function () {
254
+ var error_1, connection;
255
+ return __generator(this, function (_a) {
256
+ switch (_a.label) {
257
+ case 0: return [4 /*yield*/, this.prepare()];
258
+ case 1:
259
+ _a.sent();
260
+ _a.label = 2;
261
+ case 2:
262
+ _a.trys.push([2, 4, , 6]);
263
+ return [4 /*yield*/, operation()];
264
+ case 3: return [2 /*return*/, _a.sent()];
265
+ case 4:
266
+ error_1 = _a.sent();
267
+ connection = this.couchbaseConnection();
268
+ if (!connection.shouldReconnect(error_1)) {
269
+ throw error_1;
270
+ }
271
+ connection.markDisconnected(error_1);
272
+ return [4 /*yield*/, this.prepare()];
273
+ case 5:
274
+ _a.sent();
275
+ return [2 /*return*/, operation()];
276
+ case 6: return [2 /*return*/];
277
+ }
278
+ });
279
+ });
280
+ };
107
281
  /** Get this collection
108
282
  * getCollection
109
283
  */
110
284
  Model.prototype.getBucketName = function () {
111
- var _a;
112
- return (_a = connection_1.default.Instance) === null || _a === void 0 ? void 0 : _a.getBucket();
285
+ var bucketName = this.couchbaseConnection().getBucket();
286
+ if (!bucketName) {
287
+ throw new Error('couchset is not connected; call couchset(args) first');
288
+ }
289
+ return bucketName;
113
290
  };
114
291
  /** Get this collection
115
292
  * getCollection
116
293
  */
117
294
  Model.prototype.couchbaseConnection = function () {
118
- return connection_1.default.Instance;
295
+ return this.connection || connection_1.default.Instance;
119
296
  };
120
297
  /** Get this collection
121
298
  * getCollection
@@ -124,217 +301,514 @@ var Model = /** @class */ (function () {
124
301
  this.fresh();
125
302
  return this.collection;
126
303
  };
304
+ Model.prototype.collectionTarget = function () {
305
+ if (!this.scopeName && !this.collectionTargetName) {
306
+ return {};
307
+ }
308
+ return {
309
+ scopeName: this.scopeName || '_default',
310
+ collectionName: this.collectionTargetName || '_default',
311
+ };
312
+ };
313
+ Model.prototype.queryResultKey = function () {
314
+ var target = this.collectionTarget();
315
+ return target.collectionName || this.getBucketName();
316
+ };
317
+ Model.prototype.readContext = function () {
318
+ var _this = this;
319
+ return {
320
+ bucketName: this.keyspace(),
321
+ collectionName: this.collectionName,
322
+ cluster: this.couchbaseConnection().cluster,
323
+ parse: function (data) { return _this.parse(data); },
324
+ resultKey: this.queryResultKey(),
325
+ };
326
+ };
327
+ Model.prototype.readArgs = function (args) {
328
+ if (args === void 0) { args = {}; }
329
+ return (0, default_scope_1.applyDefaultWhere)(args, {
330
+ defaultWhere: this.defaultWhere,
331
+ mode: this.defaultWhereMode,
332
+ softDelete: this.softDelete,
333
+ });
334
+ };
335
+ Model.prototype.writeContext = function () {
336
+ var _this = this;
337
+ return {
338
+ collection: this.getCollection(),
339
+ collectionName: this.collectionName,
340
+ scope: this.scope,
341
+ parse: function (data) { return _this.parse(data); },
342
+ serialize: function (data) { return _this.serialize(data); },
343
+ serializeField: function (path, value) { return _this.serializeField(path, value); },
344
+ validateCreate: this.validateCreateHook,
345
+ validateReplace: this.validateReplaceHook,
346
+ };
347
+ };
348
+ Model.prototype.cloneWithDefaultWhereMode = function (mode) {
349
+ var options = {
350
+ codecs: this.codecs,
351
+ dateFields: this.dateFields,
352
+ defaultWhere: this.defaultWhere,
353
+ parse: this.parseHook,
354
+ schema: this.schema,
355
+ softDelete: this.softDelete,
356
+ validateCreate: this.validateCreateHook,
357
+ validateReplace: this.validateReplaceHook,
358
+ };
359
+ if (this.scopeName) {
360
+ options.scope = this.scopeName;
361
+ }
362
+ if (this.collectionTargetName) {
363
+ options.collection = this.collectionTargetName;
364
+ }
365
+ var model = new Model(this.collectionName, options, this.connection);
366
+ model.defaultWhereMode = mode;
367
+ return model;
368
+ };
369
+ /**
370
+ * Return the active bucket as a SQL++ keyspace identifier.
371
+ */
372
+ Model.prototype.bucket = function () {
373
+ return (0, keyspace_1.bucketIdentifier)(this.getBucketName());
374
+ };
375
+ /**
376
+ * Return this model's SQL++ keyspace target.
377
+ */
378
+ Model.prototype.keyspace = function () {
379
+ var target = this.collectionTarget();
380
+ return (0, keyspace_1.keyspaceIdentifier)({
381
+ bucketName: this.getBucketName(),
382
+ scopeName: target.scopeName,
383
+ collectionName: target.collectionName,
384
+ });
385
+ };
386
+ /**
387
+ * Return a SQL++ FROM target for this model's current bucket.
388
+ */
389
+ Model.prototype.from = function (alias) {
390
+ return (0, keyspace_1.fromTarget)(this.keyspace(), alias);
391
+ };
127
392
  /**
128
- * create
393
+ * Return CREATE INDEX statements for this model without executing them.
129
394
  */
130
- Model.prototype.create = function (data, options) {
395
+ Model.prototype.indexStatements = function (options) {
396
+ var _this = this;
397
+ return this.indexes.map(function (index) { return (0, indexes_1.buildIndexQuery)(_this.keyspace(), index, options); });
398
+ };
399
+ /**
400
+ * Create this model's declared indexes if Couchbase does not already have them.
401
+ */
402
+ Model.prototype.ensureIndexes = function (options) {
131
403
  return __awaiter(this, void 0, void 0, function () {
132
- var id, createdData, error_1;
404
+ var _this = this;
133
405
  return __generator(this, function (_a) {
134
- switch (_a.label) {
135
- case 0:
136
- this.fresh();
137
- id = (0, uuid_1.generateUUID)();
138
- createdData = __assign(__assign({ id: id }, data), { createdAt: new Date(), updatedAt: new Date(), _type: this.collectionName, _scope: this.scope });
139
- _a.label = 1;
140
- case 1:
141
- _a.trys.push([1, 3, , 4]);
142
- return [4 /*yield*/, this.collection.upsert(createdData.id, createdData, options)];
143
- case 2:
144
- _a.sent();
145
- return [2 /*return*/, (0, utils_1.parseSchema)(this.schema, createdData)];
146
- case 3:
147
- error_1 = _a.sent();
148
- throw error_1;
149
- case 4: return [2 /*return*/];
150
- }
406
+ return [2 /*return*/, this.withConnection(function () {
407
+ return (0, indexes_1.ensureModelIndexes)(_this.couchbaseConnection().cluster, _this.keyspace(), _this.indexes, options);
408
+ })];
151
409
  });
152
410
  });
153
411
  };
154
412
  /**
155
- * findById
413
+ * Run a SQL++ query and return rows directly.
156
414
  */
157
- Model.prototype.findById = function (id, options) {
415
+ Model.prototype.queryRows = function (query, params, options) {
158
416
  return __awaiter(this, void 0, void 0, function () {
159
- var data, error_2;
417
+ var _this = this;
418
+ return __generator(this, function (_a) {
419
+ return [2 /*return*/, this.withConnection(function () {
420
+ return (0, safe_query_1.runQueryRows)(_this.couchbaseConnection().cluster, query, params, options);
421
+ })];
422
+ });
423
+ });
424
+ };
425
+ /**
426
+ * Run a SQL++ query and return the first row or null.
427
+ */
428
+ Model.prototype.queryOne = function (query, params, options) {
429
+ return __awaiter(this, void 0, void 0, function () {
430
+ var _this = this;
431
+ return __generator(this, function (_a) {
432
+ return [2 /*return*/, this.withConnection(function () {
433
+ return (0, safe_query_1.runQueryOne)(_this.couchbaseConnection().cluster, query, params, options);
434
+ })];
435
+ });
436
+ });
437
+ };
438
+ /**
439
+ * Run a SQL++ query using limit + 1 pagination.
440
+ */
441
+ Model.prototype.queryPage = function (query, params, options) {
442
+ return __awaiter(this, void 0, void 0, function () {
443
+ var _this = this;
444
+ return __generator(this, function (_a) {
445
+ return [2 /*return*/, this.withConnection(function () {
446
+ return (0, safe_query_1.runQueryPage)(_this.couchbaseConnection().cluster, query, params, options);
447
+ })];
448
+ });
449
+ });
450
+ };
451
+ /**
452
+ * Find many model-scoped documents.
453
+ */
454
+ Model.prototype.findMany = function () {
455
+ return __awaiter(this, arguments, void 0, function (args) {
456
+ var _this = this;
457
+ if (args === void 0) { args = {}; }
458
+ return __generator(this, function (_a) {
459
+ return [2 /*return*/, this.withConnection(function () { return (0, read_helpers_1.findMany)(_this.readContext(), _this.readArgs(args)); })];
460
+ });
461
+ });
462
+ };
463
+ /**
464
+ * Find the first matching model-scoped document.
465
+ */
466
+ Model.prototype.findOne = function () {
467
+ return __awaiter(this, arguments, void 0, function (args) {
468
+ var _this = this;
469
+ if (args === void 0) { args = {}; }
470
+ return __generator(this, function (_a) {
471
+ return [2 /*return*/, this.withConnection(function () { return (0, read_helpers_1.findOne)(_this.readContext(), _this.readArgs(args)); })];
472
+ });
473
+ });
474
+ };
475
+ /**
476
+ * Check whether at least one model-scoped document matches.
477
+ */
478
+ Model.prototype.exists = function () {
479
+ return __awaiter(this, arguments, void 0, function (args) {
480
+ var _this = this;
481
+ if (args === void 0) { args = {}; }
482
+ return __generator(this, function (_a) {
483
+ return [2 /*return*/, this.withConnection(function () { return (0, read_helpers_1.exists)(_this.readContext(), _this.readArgs(args)); })];
484
+ });
485
+ });
486
+ };
487
+ /**
488
+ * Count model-scoped documents.
489
+ */
490
+ Model.prototype.count = function () {
491
+ return __awaiter(this, arguments, void 0, function (args) {
492
+ var _this = this;
493
+ if (args === void 0) { args = {}; }
494
+ return __generator(this, function (_a) {
495
+ return [2 /*return*/, this.withConnection(function () { return (0, read_helpers_1.count)(_this.readContext(), _this.readArgs(args)); })];
496
+ });
497
+ });
498
+ };
499
+ /**
500
+ * Fetch a limit + 1 page of model-scoped documents.
501
+ */
502
+ Model.prototype.page = function () {
503
+ return __awaiter(this, arguments, void 0, function (args) {
504
+ var _this = this;
505
+ if (args === void 0) { args = {}; }
506
+ return __generator(this, function (_a) {
507
+ return [2 /*return*/, this.withConnection(function () { return (0, read_helpers_1.page)(_this.readContext(), _this.readArgs(args)); })];
508
+ });
509
+ });
510
+ };
511
+ Model.prototype.withDeleted = function () {
512
+ return this.cloneWithDefaultWhereMode('withDeleted');
513
+ };
514
+ Model.prototype.onlyDeleted = function () {
515
+ return this.cloneWithDefaultWhereMode('onlyDeleted');
516
+ };
517
+ Model.prototype.withoutDefaultWhere = function () {
518
+ return this.cloneWithDefaultWhereMode('none');
519
+ };
520
+ /**
521
+ * Insert a new document and fail if the id already exists.
522
+ */
523
+ Model.prototype.insert = function (data, options) {
524
+ return __awaiter(this, void 0, void 0, function () {
525
+ var _this = this;
526
+ return __generator(this, function (_a) {
527
+ return [2 /*return*/, this.withConnection(function () { return (0, write_helpers_1.insert)(_this.writeContext(), data, options); })];
528
+ });
529
+ });
530
+ };
531
+ /** @internal Prepare a transaction insert without issuing a normal SDK write. */
532
+ Model.prototype.prepareInsert = function (data) {
533
+ return (0, write_helpers_1.prepareInsertDocument)(this.writeContext(), data);
534
+ };
535
+ /**
536
+ * Explicit insert-or-replace write.
537
+ */
538
+ Model.prototype.upsert = function (data, options) {
539
+ return __awaiter(this, void 0, void 0, function () {
540
+ var _this = this;
541
+ return __generator(this, function (_a) {
542
+ return [2 /*return*/, this.withConnection(function () { return (0, write_helpers_1.upsert)(_this.writeContext(), data, options); })];
543
+ });
544
+ });
545
+ };
546
+ Model.prototype.getById = function (id, options) {
547
+ return __awaiter(this, void 0, void 0, function () {
548
+ var _this = this;
549
+ return __generator(this, function (_a) {
550
+ return [2 /*return*/, this.withConnection(function () { return __awaiter(_this, void 0, void 0, function () {
551
+ var data;
552
+ return __generator(this, function (_a) {
553
+ switch (_a.label) {
554
+ case 0: return [4 /*yield*/, this.collection.get(id, options)];
555
+ case 1:
556
+ data = _a.sent();
557
+ return [2 /*return*/, this.parse(data.content)];
558
+ }
559
+ });
560
+ }); })];
561
+ });
562
+ });
563
+ };
564
+ Model.prototype.findDocById = function (id, options) {
565
+ return __awaiter(this, void 0, void 0, function () {
566
+ var data;
160
567
  return __generator(this, function (_a) {
161
568
  switch (_a.label) {
162
- case 0:
163
- this.fresh();
164
- _a.label = 1;
569
+ case 0: return [4 /*yield*/, this.getById(id, options)];
165
570
  case 1:
166
- _a.trys.push([1, 3, , 4]);
167
- return [4 /*yield*/, this.collection.get(id, options)];
168
- case 2:
169
571
  data = _a.sent();
170
- return [2 /*return*/, (0, utils_1.parseSchema)(this.schema, data.content)];
171
- case 3:
172
- error_2 = _a.sent();
173
- throw error_2;
174
- case 4: return [2 /*return*/];
572
+ return [2 /*return*/, this.hydrate(data)];
175
573
  }
176
574
  });
177
575
  });
178
576
  };
179
577
  /**
180
- * update
578
+ * Find a document with SDK metadata.
181
579
  */
182
- Model.prototype.updateById = function (id, data, opt) {
580
+ Model.prototype.findByIdWithMeta = function (id, options) {
183
581
  return __awaiter(this, void 0, void 0, function () {
184
- var _a, _b, silent, options, updatedDocument, error_3;
185
- return __generator(this, function (_c) {
186
- switch (_c.label) {
187
- case 0:
188
- this.fresh();
189
- _a = opt || {}, _b = _a.silent, silent = _b === void 0 ? false : _b, options = __rest(_a, ["silent"]);
190
- updatedDocument = __assign(__assign({}, data), { id: id, _type: this.collectionName, _scope: this.scope });
191
- if (!silent) {
192
- updatedDocument.updatedAt = new Date();
193
- }
194
- _c.label = 1;
195
- case 1:
196
- _c.trys.push([1, 3, , 4]);
197
- return [4 /*yield*/, this.collection.replace(id, updatedDocument, options)];
198
- case 2:
199
- _c.sent();
200
- return [2 /*return*/, (0, utils_1.parseSchema)(this.schema, updatedDocument)];
201
- case 3:
202
- error_3 = _c.sent();
203
- throw error_3;
204
- case 4: return [2 /*return*/];
205
- }
582
+ var _this = this;
583
+ return __generator(this, function (_a) {
584
+ return [2 /*return*/, this.withConnection(function () { return (0, write_helpers_1.findByIdWithMeta)(_this.writeContext(), id, options); })];
585
+ });
586
+ });
587
+ };
588
+ /** Ergonomic alias for findByIdWithMeta, intended for CAS workflows. */
589
+ Model.prototype.getWithCas = function (id, options) {
590
+ return __awaiter(this, void 0, void 0, function () {
591
+ return __generator(this, function (_a) {
592
+ return [2 /*return*/, this.findByIdWithMeta(id, options)];
206
593
  });
207
594
  });
208
595
  };
209
596
  /**
210
- * save
597
+ * Explicit full-document replace.
211
598
  */
212
- Model.prototype.save = function (data, opt) {
599
+ Model.prototype.replaceById = function (id, data, options) {
213
600
  return __awaiter(this, void 0, void 0, function () {
214
- var id, _a, _b, silent, options, updatedDocument, error_4;
215
- return __generator(this, function (_c) {
216
- switch (_c.label) {
217
- case 0:
218
- this.fresh();
219
- id = data && data.id;
220
- _a = opt || {}, _b = _a.silent, silent = _b === void 0 ? false : _b, options = __rest(_a, ["silent"]);
221
- updatedDocument = __assign(__assign({}, data), { id: id, _type: this.collectionName, _scope: this.scope });
222
- if (!silent) {
223
- updatedDocument.updatedAt = new Date();
224
- }
225
- _c.label = 1;
226
- case 1:
227
- _c.trys.push([1, 3, , 4]);
228
- if (!id) {
229
- throw new Error('document must have id');
230
- }
231
- return [4 /*yield*/, this.collection.replace(id, updatedDocument, options)];
232
- case 2:
233
- _c.sent();
234
- return [2 /*return*/, (0, utils_1.parseSchema)(this.schema, updatedDocument)];
235
- case 3:
236
- error_4 = _c.sent();
237
- console.error(error_4);
238
- throw error_4;
239
- case 4: return [2 /*return*/];
240
- }
601
+ var _this = this;
602
+ return __generator(this, function (_a) {
603
+ return [2 /*return*/, this.withConnection(function () {
604
+ return (0, write_helpers_1.replaceById)(_this.writeContext(), id, data, options);
605
+ })];
241
606
  });
242
607
  });
243
608
  };
244
- Model.prototype.delete = function (id, options) {
609
+ /** @internal Prepare a transaction replace without issuing a normal SDK write. */
610
+ Model.prototype.prepareReplace = function (id, data, options) {
611
+ return (0, write_helpers_1.prepareReplacementDocument)(this.writeContext(), id, data, options);
612
+ };
613
+ /**
614
+ * Replace only when the supplied CAS still describes the current document.
615
+ * CouchSet deliberately performs one SDK operation and never re-reads/retries
616
+ * with a new CAS, because doing so would defeat the caller's concurrency check.
617
+ */
618
+ Model.prototype.replaceIfCas = function (id, data, cas, options) {
245
619
  return __awaiter(this, void 0, void 0, function () {
246
- var error_5;
620
+ return __generator(this, function (_a) {
621
+ return [2 /*return*/, this.replaceById(id, data, __assign(__assign({}, (options || {})), { cas: cas }))];
622
+ });
623
+ });
624
+ };
625
+ /**
626
+ * Remove a one-time document with exactly the CAS supplied by the caller.
627
+ * Missing and CAS-mismatch cases are normal outcomes; transport and ambiguous
628
+ * failures are rethrown so callers never mistake an unknown commit for success.
629
+ */
630
+ Model.prototype.consumeOnce = function (id, cas) {
631
+ return __awaiter(this, void 0, void 0, function () {
632
+ var error_2, name_1, message;
247
633
  return __generator(this, function (_a) {
248
634
  switch (_a.label) {
249
- case 0:
250
- this.fresh();
251
- _a.label = 1;
635
+ case 0: return [4 /*yield*/, this.prepare()];
252
636
  case 1:
253
- _a.trys.push([1, 3, , 4]);
254
- return [4 /*yield*/, this.collection.remove(id, options)];
255
- case 2:
256
637
  _a.sent();
257
- return [2 /*return*/, true];
638
+ _a.label = 2;
639
+ case 2:
640
+ _a.trys.push([2, 4, , 5]);
641
+ return [4 /*yield*/, this.collection.remove(id, { cas: cas })];
258
642
  case 3:
259
- error_5 = _a.sent();
260
- throw error_5;
261
- case 4: return [2 /*return*/];
643
+ _a.sent();
644
+ return [2 /*return*/, { status: 'consumed' }];
645
+ case 4:
646
+ error_2 = _a.sent();
647
+ name_1 = (error_2 === null || error_2 === void 0 ? void 0 : error_2.name) || '';
648
+ message = (error_2 === null || error_2 === void 0 ? void 0 : error_2.message) || '';
649
+ if (/DocumentNotFound|not found/i.test("".concat(name_1, " ").concat(message))) {
650
+ return [2 /*return*/, { status: 'missing' }];
651
+ }
652
+ if (/CasMismatch|cas mismatch/i.test("".concat(name_1, " ").concat(message))) {
653
+ return [2 /*return*/, { status: 'conflict' }];
654
+ }
655
+ throw error_2;
656
+ case 5: return [2 /*return*/];
262
657
  }
263
658
  });
264
659
  });
265
660
  };
266
661
  /**
267
- * Pagination
268
- *
269
- select = ['id', 'createdAt']
270
- where = {
271
- where: { owner: { $eq: "stoqey" }, _type: { $eq: "Trade" } },
272
- },
273
- page = 0,
274
- limit = 10,
275
- orderBy = { createdAt: "DESC" },
276
- * @param args PaginationArgs
277
- */
278
- Model.prototype.pagination = function (_a) {
279
- return __awaiter(this, arguments, void 0, function (_b) {
280
- var whereEx, bucketName, rows;
662
+ * Partial document mutation using common patch operators.
663
+ */
664
+ Model.prototype.patchById = function (id, patch, options) {
665
+ return __awaiter(this, void 0, void 0, function () {
281
666
  var _this = this;
282
- var select = _b.select, where = _b.where, orderBy = _b.orderBy, limit = _b.limit, page = _b.page, _c = _b.customQuery, customQuery = _c === void 0 ? {} : _c;
283
- return __generator(this, function (_d) {
284
- switch (_d.label) {
285
- case 0:
286
- this.fresh(); // refresh
287
- whereEx = { _type: { $eq: this.collectionName } };
288
- if (where) {
289
- whereEx = __assign(__assign({}, whereEx), where);
290
- }
291
- bucketName = connection_1.default.Instance.bucketName;
292
- return [4 /*yield*/, (0, pagination_1.Pagination)({
293
- bucketName: bucketName,
294
- select: select,
295
- where: __assign({ where: whereEx }, customQuery),
296
- limit: limit,
297
- page: page,
298
- orderBy: orderBy,
299
- })];
300
- case 1:
301
- rows = _d.sent();
302
- return [2 /*return*/, rows.map(function (r) { return (0, utils_1.parseSchema)(_this.schema, r); })];
303
- }
667
+ return __generator(this, function (_a) {
668
+ return [2 /*return*/, this.withConnection(function () {
669
+ return (0, write_helpers_1.patchById)(_this.writeContext(), id, patch, options);
670
+ })];
304
671
  });
305
672
  });
306
673
  };
307
674
  /**
308
- * Run a custom query with model parsing
309
- * @param { select, query }
310
- * @returns
675
+ * Couchbase subdocument mutation escape hatch.
311
676
  */
312
- Model.prototype.customQuery = function (_a) {
313
- return __awaiter(this, arguments, void 0, function (_b) {
314
- var response;
315
- var params = _b.params, limit = _b.limit, query = _b.query;
677
+ Model.prototype.mutateById = function (id, specs, options) {
678
+ return __awaiter(this, void 0, void 0, function () {
679
+ var _this = this;
680
+ return __generator(this, function (_a) {
681
+ return [2 /*return*/, this.withConnection(function () {
682
+ return (0, write_helpers_1.mutateById)(_this.writeContext(), id, specs, options);
683
+ })];
684
+ });
685
+ });
686
+ };
687
+ /**
688
+ * Atomic numeric field increment.
689
+ */
690
+ Model.prototype.incrementById = function (id, field, delta, options) {
691
+ return __awaiter(this, void 0, void 0, function () {
692
+ var _this = this;
693
+ return __generator(this, function (_a) {
694
+ return [2 /*return*/, this.withConnection(function () {
695
+ return (0, write_helpers_1.incrementById)(_this.writeContext(), id, field, delta, options);
696
+ })];
697
+ });
698
+ });
699
+ };
700
+ Model.prototype.softDeleteById = function (id, options) {
701
+ return __awaiter(this, void 0, void 0, function () {
702
+ return __generator(this, function (_a) {
703
+ return [2 /*return*/, this.patchById(id, { $set: { deleted: true, deletedAt: new Date() } }, options)];
704
+ });
705
+ });
706
+ };
707
+ Model.prototype.restoreById = function (id, options) {
708
+ return __awaiter(this, void 0, void 0, function () {
709
+ return __generator(this, function (_a) {
710
+ return [2 /*return*/, this.patchById(id, { $unset: ['deleted', 'deletedAt'] }, options)];
711
+ });
712
+ });
713
+ };
714
+ Model.prototype.deleteById = function (id, options) {
715
+ return __awaiter(this, void 0, void 0, function () {
716
+ var _a, _b, hard, removeOptions;
717
+ var _this = this;
316
718
  return __generator(this, function (_c) {
317
- switch (_c.label) {
318
- case 0:
319
- this.fresh(); // refresh
320
- return [4 /*yield*/, (0, search_1.CustomQuery)({
321
- limit: limit,
322
- params: params,
323
- query: query,
324
- })];
719
+ _a = options || {}, _b = _a.hard, hard = _b === void 0 ? false : _b, removeOptions = __rest(_a, ["hard"]);
720
+ if (hard || !this.softDelete) {
721
+ return [2 /*return*/, this.withConnection(function () { return __awaiter(_this, void 0, void 0, function () {
722
+ return __generator(this, function (_a) {
723
+ switch (_a.label) {
724
+ case 0: return [4 /*yield*/, this.collection.remove(id, removeOptions)];
725
+ case 1:
726
+ _a.sent();
727
+ return [2 /*return*/, true];
728
+ }
729
+ });
730
+ }); })];
731
+ }
732
+ return [2 /*return*/, this.softDeleteById(id)];
733
+ });
734
+ });
735
+ };
736
+ Model.prototype.findDocOne = function () {
737
+ return __awaiter(this, arguments, void 0, function (args) {
738
+ var data;
739
+ if (args === void 0) { args = {}; }
740
+ return __generator(this, function (_a) {
741
+ switch (_a.label) {
742
+ case 0: return [4 /*yield*/, this.findOne(args)];
325
743
  case 1:
326
- response = _c.sent();
327
- return [2 /*return*/, response];
744
+ data = _a.sent();
745
+ return [2 /*return*/, data ? this.hydrate(data) : null];
328
746
  }
329
747
  });
330
748
  });
331
749
  };
750
+ Model.prototype.hydrate = function (data) {
751
+ return (0, hydrated_document_1.hydrate)(this, this.parse(data));
752
+ };
332
753
  Model.prototype.parse = function (data) {
333
- this.fresh(); // refresh
334
- return (0, utils_1.parseSchema)(this.schema, data);
754
+ var decoded = this.deserialize(data);
755
+ var parsed = (0, utils_1.parseSchema)(this.schema, decoded);
756
+ var parsedDates = (0, validation_1.parseDateFields)(parsed, this.dateFields);
757
+ return this.parseHook ? this.parseHook(parsedDates) : parsedDates;
758
+ };
759
+ /** @internal Used by the typed client before a document reaches the SDK. */
760
+ Model.prototype.serialize = function (data) {
761
+ var _this = this;
762
+ var result = __assign({}, data);
763
+ Object.keys(this.codecs).forEach(function (path) {
764
+ var current = getPath(result, path);
765
+ if (current !== undefined) {
766
+ setPath(result, path, _this.codecs[path].toDatabase(current));
767
+ }
768
+ });
769
+ return result;
770
+ };
771
+ /** @internal Used by patch helpers and transaction-bound models. */
772
+ Model.prototype.serializeField = function (path, value) {
773
+ return this.codecs[path] ? this.codecs[path].toDatabase(value) : value;
335
774
  };
775
+ Model.prototype.deserialize = function (data) {
776
+ var _this = this;
777
+ var result = __assign({}, data);
778
+ Object.keys(this.codecs).forEach(function (path) {
779
+ var current = getPath(result, path);
780
+ if (current !== undefined) {
781
+ setPath(result, path, _this.codecs[path].fromDatabase(current));
782
+ }
783
+ });
784
+ return result;
785
+ };
786
+ Model.registeredModels = [];
336
787
  return Model;
337
788
  }());
338
789
  exports.Model = Model;
790
+ var getPath = function (data, path) {
791
+ return path.split('.').reduce(function (value, key) { return (value == null ? undefined : value[key]); }, data);
792
+ };
793
+ var setPath = function (data, path, value) {
794
+ var parts = path.split('.');
795
+ var key = parts.pop();
796
+ var target = parts.reduce(function (current, part) {
797
+ var existing = current[part];
798
+ if (Array.isArray(existing)) {
799
+ current[part] = existing.slice();
800
+ }
801
+ else if (existing && typeof existing === 'object') {
802
+ // serialize/parse start with a shallow root copy. Clone every branch
803
+ // we traverse so dotted codecs never mutate caller or SDK content.
804
+ current[part] = __assign({}, existing);
805
+ }
806
+ else {
807
+ current[part] = {};
808
+ }
809
+ return current[part];
810
+ }, data);
811
+ target[key] = value;
812
+ };
339
813
  exports.default = Model;
340
814
  //# sourceMappingURL=index.js.map