@docstack/client 0.1.5 → 0.1.6

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 (77) hide show
  1. package/LICENSE +10 -0
  2. package/README.md +1 -1
  3. package/lib/core/attribute.d.ts +11 -2
  4. package/lib/core/class.d.ts +29 -6
  5. package/lib/core/content-transfer.d.ts +178 -0
  6. package/lib/core/crypto-engine/index.d.ts +82 -1
  7. package/lib/core/crypto-engine/utils.d.ts +36 -1
  8. package/lib/core/datamodel/index.d.ts +16 -0
  9. package/lib/core/domain.d.ts +1 -1
  10. package/lib/core/guarded-db.d.ts +52 -0
  11. package/lib/core/index.d.ts +106 -1
  12. package/lib/core/policy-engine/index.d.ts +35 -0
  13. package/lib/core/query-engine/classes.d.ts +24 -0
  14. package/lib/core/query-engine/executor.d.ts +11 -0
  15. package/lib/core/query-engine/index.d.ts +2 -1
  16. package/lib/core/query-engine/planner.d.ts +19 -0
  17. package/lib/core/stack.d.ts +676 -7
  18. package/lib/core/sync/class-filter.d.ts +106 -0
  19. package/lib/core/sync/filter-identity.d.ts +53 -0
  20. package/lib/core/sync/index.d.ts +334 -0
  21. package/lib/core/sync/internal-docs.d.ts +159 -0
  22. package/lib/index.d.ts +27 -1
  23. package/lib/index.js +4976 -607
  24. package/lib/index.umd.js +5004 -621
  25. package/lib/plugins/pouchdb.d.ts +43 -3
  26. package/lib/utils/logger/index.d.ts +28 -4
  27. package/lib/utils/logger/transport.d.ts +52 -11
  28. package/package.json +18 -10
  29. package/lib/core/attribute.js +0 -406
  30. package/lib/core/attribute.js.map +0 -1
  31. package/lib/core/class.js +0 -774
  32. package/lib/core/class.js.map +0 -1
  33. package/lib/core/crypto-engine/index.js +0 -229
  34. package/lib/core/crypto-engine/index.js.map +0 -1
  35. package/lib/core/crypto-engine/utils.js +0 -88
  36. package/lib/core/crypto-engine/utils.js.map +0 -1
  37. package/lib/core/datamodel/index.js +0 -1308
  38. package/lib/core/datamodel/index.js.map +0 -1
  39. package/lib/core/domain.js +0 -423
  40. package/lib/core/domain.js.map +0 -1
  41. package/lib/core/index.js +0 -532
  42. package/lib/core/index.js.map +0 -1
  43. package/lib/core/job-engine/index.js +0 -220
  44. package/lib/core/job-engine/index.js.map +0 -1
  45. package/lib/core/policy-engine/index.js +0 -232
  46. package/lib/core/policy-engine/index.js.map +0 -1
  47. package/lib/core/query-engine/accumulators.js +0 -258
  48. package/lib/core/query-engine/accumulators.js.map +0 -1
  49. package/lib/core/query-engine/evaluator.js +0 -179
  50. package/lib/core/query-engine/evaluator.js.map +0 -1
  51. package/lib/core/query-engine/executor.js +0 -405
  52. package/lib/core/query-engine/executor.js.map +0 -1
  53. package/lib/core/query-engine/index.js +0 -4
  54. package/lib/core/query-engine/index.js.map +0 -1
  55. package/lib/core/query-engine/parser.js +0 -515
  56. package/lib/core/query-engine/parser.js.map +0 -1
  57. package/lib/core/query-engine/planner.js +0 -330
  58. package/lib/core/query-engine/planner.js.map +0 -1
  59. package/lib/core/stack.js +0 -1827
  60. package/lib/core/stack.js.map +0 -1
  61. package/lib/core/test-utils/docstack.js +0 -222
  62. package/lib/core/test-utils/docstack.js.map +0 -1
  63. package/lib/core/trigger/index.js +0 -81
  64. package/lib/core/trigger/index.js.map +0 -1
  65. package/lib/index.js.map +0 -1
  66. package/lib/plugins/pouchdb.js +0 -412
  67. package/lib/plugins/pouchdb.js.map +0 -1
  68. package/lib/utils/crypto/index.js +0 -34
  69. package/lib/utils/crypto/index.js.map +0 -1
  70. package/lib/utils/index.js +0 -58
  71. package/lib/utils/index.js.map +0 -1
  72. package/lib/utils/logger/index.js +0 -20
  73. package/lib/utils/logger/index.js.map +0 -1
  74. package/lib/utils/logger/transport.js +0 -28
  75. package/lib/utils/logger/transport.js.map +0 -1
  76. package/lib/workers/dataModel.js +0 -48
  77. package/lib/workers/dataModel.js.map +0 -1
package/lib/core/class.js DELETED
@@ -1,774 +0,0 @@
1
- var _a;
2
- import { Class as Class_, isAttributeModel } from "@docstack/shared";
3
- import createLogger from "../utils/logger/index.js";
4
- import Attribute from "./attribute.js";
5
- import { Trigger } from "./trigger/index.js";
6
- import { z } from "zod";
7
- import clientLogger from "../utils/logger/index.js";
8
- /**
9
- * Represents a data class (schema definition) in the DocStack database.
10
- *
11
- * A Class defines the structure of documents, including their attributes,
12
- * validation rules (via Zod), and triggers that execute during document operations.
13
- *
14
- * Use the static factory methods ({@link Class.create}, {@link Class.fetch}) to
15
- * instantiate classes - the constructor is private.
16
- *
17
- * @example
18
- * ```typescript
19
- * // Create a new class with schema
20
- * const taskClass = await Class.create(stack, 'Task', 'class', 'User Tasks');
21
- *
22
- * // Add attributes to define the schema
23
- * await Attribute.create(taskClass, 'title', 'string', 'Task Title', { mandatory: true });
24
- * await Attribute.create(taskClass, 'isComplete', 'boolean', 'Done?', { defaultValue: false });
25
- *
26
- * // Create documents (cards) of this class
27
- * const task = await taskClass.add({ title: 'My Task', isComplete: false });
28
- * ```
29
- *
30
- * @extends Class_
31
- */
32
- class Class extends Class_ {
33
- constructor() {
34
- super();
35
- /** Map of attribute names to Attribute instances defining the schema. */
36
- this.attributes = {};
37
- /** The raw schema definition from the ClassModel. */
38
- this.schema = {};
39
- /** Zod schema for runtime validation of document data. */
40
- this.schemaZOD = z.object({});
41
- /** Current state indicating if the class is processing an operation. */
42
- this.state = "idle";
43
- /** Array of triggers that execute before/after document operations. */
44
- this.triggers = [];
45
- // TODO: Test
46
- /*
47
- inheritAttributes( parentClass: Class ) {
48
- let parentAttributes = parentClass.getAttributes();
49
- for ( let attribute of parentAttributes ) {
50
- this.addAttribute(attribute);
51
- }
52
- } */
53
- this.build = () => {
54
- return new Promise(async (resolve, reject) => {
55
- let stack = this.getStack();
56
- if (stack) {
57
- // if (parentClassName) this.setParentClass(parentClassName);
58
- let classModel = await stack.addClass(this);
59
- // Hydrate model
60
- if (classModel) {
61
- this.setModel(classModel);
62
- _a.logger.info("build - classModel", { classModel: classModel });
63
- this.setId(classModel._id);
64
- resolve(this);
65
- }
66
- else {
67
- reject("unable to get classModel. Check logs");
68
- }
69
- }
70
- else {
71
- reject("Missing stack assignment");
72
- }
73
- });
74
- };
75
- this.init = (stack, id, name, type, description, schema = {}
76
- // parentClass: Class | null
77
- ) => {
78
- // this.parentClass = parentClass;
79
- if (stack) {
80
- this.stack = stack;
81
- }
82
- this.name = name;
83
- this.id = id;
84
- this.description = description;
85
- this.type = type;
86
- // this.attributes = [];
87
- // this.stack = null;
88
- // this.id = null;
89
- // if (schema) {
90
- // this.schema = schema;
91
- // }
92
- this.setModel({
93
- "~class": type, _id: id, active: true,
94
- name, description,
95
- schema, triggers: [],
96
- });
97
- this.logger = clientLogger(stack).child({ module: "class", className: this.name });
98
- // TODO: Waiting for test of method
99
- // if (parentClass) this.inheritAttributes(parentClass);
100
- };
101
- this.uniqueCheck = async (doc) => {
102
- const fnLogger = this.logger.child({ method: "uniqueCheck", args: { doc } });
103
- const duplicate = await this.getByPrimaryKeys(doc);
104
- if (duplicate == null || duplicate._id == doc._id) {
105
- fnLogger.info("No duplicate found for doc");
106
- return true;
107
- }
108
- else {
109
- fnLogger.info("Duplicate found for doc", { duplicate });
110
- return false;
111
- }
112
- };
113
- this.bulkUniqueCheck = async (pKs) => {
114
- var _b;
115
- const fnLogger = this.logger.child({ method: "bulkUniqueCheck", args: { pKs } });
116
- const ddocId = await ((_b = this.stack) === null || _b === void 0 ? void 0 : _b.addDesignDocumentPKs(this.name, pKs, true));
117
- fnLogger.info(`Created temporary design document '${ddocId}'`);
118
- if (this.stack && ddocId) {
119
- try {
120
- const result = await this.stack.db.query(`${ddocId}/by_pKeys`, {
121
- group: true,
122
- reduce: '_count'
123
- });
124
- const hasDuplicates = result.rows.some(row => row.value > 1);
125
- if (hasDuplicates) {
126
- // 3a. Rollback: new schema is invalid
127
- fnLogger.error('Schema change invalid: new duplicates found.');
128
- const finalTempDoc = await this.stack.db.get(ddocId);
129
- await this.stack.db.remove(finalTempDoc);
130
- return false; // Indicate failure
131
- }
132
- else {
133
- // 3b. Execute: new schema is valid. Replace the live document.
134
- fnLogger.info('Bulk unique check completed: no new duplicates found');
135
- const finalTempDoc = await this.stack.db.get(ddocId);
136
- // Clean up the temporary document
137
- await this.stack.db.remove(finalTempDoc);
138
- return true; // Indicate success
139
- }
140
- }
141
- catch (err) {
142
- console.error('Error during schema validation:', err);
143
- // Ensure the temporary document is removed on error
144
- try {
145
- const finalTempDoc = await this.stack.db.get(ddocId);
146
- await this.stack.db.remove(finalTempDoc);
147
- }
148
- catch (e) { /* ignore */ }
149
- return false;
150
- }
151
- }
152
- else {
153
- fnLogger.error(`Was unable to create temporary design document to group by`);
154
- return false;
155
- }
156
- };
157
- /**
158
- * Validates document data against the class schema using Zod.
159
- *
160
- * @param data - The document data to validate
161
- * @returns `true` if validation passes, `false` otherwise
162
- */
163
- this.validate = async (data) => {
164
- const fnLogger = this.logger.child({ method: "validate" });
165
- const result = await this.schemaZOD.safeParseAsync(data);
166
- fnLogger.debug("Got result", { result });
167
- if (result.success) {
168
- return true;
169
- }
170
- else {
171
- return false;
172
- }
173
- };
174
- // TODO Turn into method (after factory method instantiation refactory is done)
175
- this.setId = (id) => {
176
- this.id = id;
177
- };
178
- this.getName = () => {
179
- return this.name;
180
- };
181
- this.getStack = () => {
182
- return this.stack;
183
- };
184
- this.getDescription = () => {
185
- return this.description;
186
- };
187
- this.getType = () => {
188
- return this.type;
189
- };
190
- this.getId = () => {
191
- return this.id;
192
- };
193
- /**
194
- * Builds the schema object from the current attributes.
195
- * @returns The schema definition object
196
- */
197
- this.buildSchema = () => {
198
- let schema = {};
199
- Object.entries(this.attributes).forEach(t => {
200
- schema[t[0]] = t[1].model;
201
- });
202
- return schema;
203
- };
204
- /**
205
- * Returns the current ClassModel representation of this class.
206
- * @returns The ClassModel document
207
- */
208
- this.getModel = () => {
209
- let triggers = [];
210
- for (const trigger of this.triggers) {
211
- triggers.push(trigger.model);
212
- }
213
- let model = {
214
- _id: this.id,
215
- name: this.getName(),
216
- description: this.getDescription(),
217
- "~class": this.getType(),
218
- schema: this.buildSchema(),
219
- triggers: triggers,
220
- active: true,
221
- _rev: this.model ? this.model._rev : "",
222
- "~createTimestamp": this.model ? this.model["~createTimestamp"] : undefined,
223
- };
224
- return model;
225
- };
226
- // [TODO] Change into buildFromModel
227
- /**
228
- * It hydrates attributes and triggers from given model
229
- * @param model
230
- */
231
- this.setModel = (model) => {
232
- _a.logger.info("setModel - got incoming model", { model: model });
233
- // Retreive current class model
234
- let currentModel = this.getModel();
235
- // Set model arg to the overwrite of the current model with the given one
236
- model = Object.assign(currentModel, model);
237
- if (model.schema) {
238
- // model.schema = {...this.model.schema, ...model.schema};
239
- this.attributes = {};
240
- this.schemaZOD = z.object({});
241
- for (const [key, attrModel] of Object.entries(model.schema)) {
242
- let attribute = new Attribute(this, attrModel.name, attrModel.type, attrModel.description, attrModel.config);
243
- this.attributes[attrModel.name] = attribute;
244
- this.schemaZOD = this.schemaZOD.extend({
245
- [attrModel.name]: attribute.field
246
- });
247
- }
248
- }
249
- if (model.triggers) {
250
- this.triggers = [];
251
- for (const trigger of model.triggers) {
252
- let trigger_ = new Trigger(trigger, this);
253
- this.triggers.push(trigger_);
254
- }
255
- }
256
- this.name = model.name;
257
- this.description = model.description;
258
- this.type = model["~class"];
259
- this.model = model;
260
- _a.logger.info("setModel - model after processing", { model: model });
261
- };
262
- /**
263
- * Returns the primary key attribute names for this class.
264
- * @returns Array of attribute names marked as primary keys
265
- */
266
- this.getPrimaryKeys = () => {
267
- return Object.values(this.attributes).filter(attr => attr.isPrimaryKey())
268
- .map(attr => attr.getName());
269
- };
270
- this.getAttributes = (...names) => {
271
- let attributes = {};
272
- for (const attribute of Object.values(this.attributes)) {
273
- if (names.length > 0) {
274
- // filter with given names
275
- for (let name of names) {
276
- // match?
277
- if (name != null && attribute.getName() == name) {
278
- attributes[attribute.name] = attribute;
279
- }
280
- }
281
- }
282
- else {
283
- // no filter provided add all
284
- attributes[attribute.name] = attribute;
285
- }
286
- }
287
- return attributes;
288
- };
289
- this.hasAllAttributes = (...names) => {
290
- let result = false;
291
- let attributes = this.getAttributes(...names);
292
- for (let attribute of Object.values(attributes)) {
293
- result = names.includes(attribute.getName());
294
- if (!result)
295
- break;
296
- }
297
- return result;
298
- };
299
- this.hasAnyAttributes = (...names) => {
300
- let result = false;
301
- let attributes = this.getAttributes(...names);
302
- for (let attribute of Object.values(attributes)) {
303
- result = names.includes(attribute.getName());
304
- if (result)
305
- break;
306
- }
307
- return result;
308
- };
309
- this.getEncryptedAttributes = () => {
310
- return Object.values(this.attributes).filter((attribute) => {
311
- const config = attribute.model.config;
312
- return (config === null || config === void 0 ? void 0 : config.encrypted) === true && (config === null || config === void 0 ? void 0 : config.primaryKey) !== true;
313
- });
314
- };
315
- // interface of hasAnyAttributes
316
- this.hasAttribute = (name) => {
317
- return this.hasAnyAttributes(name);
318
- };
319
- /**
320
- * Adds a new attribute to the class schema.
321
- * Persists the change to the database.
322
- *
323
- * @param attribute - The Attribute instance or AttributeModel to add
324
- * @returns This Class instance for chaining
325
- *
326
- * @example
327
- * ```typescript
328
- * await taskClass.addAttribute(new Attribute(taskClass, 'dueDate', 'date', 'Due Date'));
329
- * // Or use Attribute.create() for a simpler API
330
- * ```
331
- */
332
- this.addAttribute = async (attribute) => {
333
- var _b;
334
- const fnLogger = this.logger.child({ method: "addAttribute", args: { attribute: attribute.name } });
335
- const attribute_ = isAttributeModel(attribute)
336
- ? new Attribute(this, attribute.name, attribute.type, attribute.description, attribute.config) : attribute;
337
- try {
338
- let name = attribute_.getName();
339
- // console.log("Adding attribute", {className: this.name, attribute: name})
340
- if (!this.hasAttribute(name)) {
341
- fnLogger.info("Adding attribute", { name: name, type: attribute_.getModel() });
342
- this.attributes[name] = attribute_;
343
- let attributeModel = attribute_.getModel();
344
- fnLogger.info("Adding attribute to schema", { attributeModel: attributeModel });
345
- const currentSchema = (_b = this.model.schema) !== null && _b !== void 0 ? _b : {};
346
- this.model.schema = Object.assign(Object.assign({}, currentSchema), { [name]: attributeModel });
347
- this.schemaZOD = this.schemaZOD.extend({
348
- [name]: attribute_.field
349
- });
350
- // TODO:
351
- // this.schema[name] = attributeModel; // sometimes getting schema undefined
352
- // update class on db
353
- fnLogger.info("Checking for requirements before updating class on db", { stack: (this.stack != null), id: this.id });
354
- if (this.stack && this.id) {
355
- // debugger;
356
- fnLogger.info("Updating class on db");
357
- let res = await this.stack.updateClass(this);
358
- return this;
359
- // TODO: Check if this class has subclasses
360
- }
361
- else {
362
- fnLogger.error("Class not updated on db because of missing stack or id");
363
- return this;
364
- }
365
- }
366
- else {
367
- fnLogger.error("Attribute with name " + name + " already exists within this Class");
368
- return this;
369
- }
370
- }
371
- catch (e) {
372
- fnLogger.error("Falied adding attribute because: ", e);
373
- return this;
374
- }
375
- };
376
- /**
377
- * Modifies an existing attribute in the class schema.
378
- *
379
- * @param name - The name of the attribute to modify
380
- * @param attribute - The new Attribute or AttributeModel definition
381
- * @returns This Class instance for chaining
382
- */
383
- this.modifyAttribute = async (name, attribute) => {
384
- const fnLogger = this.logger.child({ method: "modifyAttribute", args: { name } });
385
- const originSchema = Object.assign({}, this.model.schema[name]), originAttr = this.attributes[name];
386
- const attribute_ = isAttributeModel(attribute)
387
- ? new Attribute(this, attribute.name, attribute.type, attribute.description, attribute.config) : attribute;
388
- try {
389
- fnLogger.info(`Attempting to change attribute definition.`);
390
- delete this.model.schema[name];
391
- delete this.attributes[name];
392
- this.schemaZOD = this.schemaZOD.omit({ [name]: true });
393
- return this.addAttribute(attribute_);
394
- }
395
- catch (e) {
396
- // Revert
397
- this.model.schema[name] = originSchema;
398
- this.attributes[name] = originAttr;
399
- fnLogger.error(`Failed at removing attribute from class.'`);
400
- }
401
- return this;
402
- };
403
- /**
404
- * Removes an attribute from the class schema.
405
- *
406
- * @param name - The name of the attribute to remove
407
- * @returns This Class instance for chaining
408
- */
409
- this.removeAttribute = async (name) => {
410
- const fnLogger = this.logger.child({ method: "removeAttribute", args: { name } });
411
- const originSchema = Object.assign({}, this.model.schema[name]), originAttr = this.attributes[name];
412
- try {
413
- fnLogger.info(`Attempting to remove attribute from class.`);
414
- delete this.model.schema[name];
415
- delete this.attributes[name];
416
- this.schemaZOD = this.schemaZOD.omit({ [name]: true });
417
- if (this.stack) {
418
- this.stack.updateClass(this);
419
- }
420
- else
421
- throw new Error("Missing stack, cannot perform updates.");
422
- }
423
- catch (e) {
424
- // Revert
425
- this.model.schema[name] = originSchema;
426
- this.attributes[name] = originAttr;
427
- fnLogger.error(`Failed at removing attribute from class.'`);
428
- }
429
- return this;
430
- };
431
- /**
432
- * Creates a new document (card) of this class type.
433
- *
434
- * @param params - The document data
435
- * @returns The created document, or `null` if stack is not defined
436
- *
437
- * @example
438
- * ```typescript
439
- * const task = await taskClass.addCard({
440
- * title: 'My Task',
441
- * isComplete: false
442
- * });
443
- * ```
444
- */
445
- this.addCard = async (params) => {
446
- const fnLogger = this.logger.child({ method: "addCard", args: { params } });
447
- if (!this.stack) {
448
- fnLogger.error("Stack is not defined");
449
- return null;
450
- }
451
- return await this.stack.createDoc(null, this.getName(), this, params);
452
- };
453
- /**
454
- * Creates multiple documents (cards) of this class type in a batch.
455
- *
456
- * @param paramsArray - Array of document data objects
457
- * @returns Array of created documents
458
- */
459
- this.addCards = async (paramsArray) => {
460
- const fnLogger = this.logger.child({ method: "addCards", args: { paramsArray } });
461
- if (!this.stack) {
462
- fnLogger.error("Stack is not defined");
463
- return [];
464
- }
465
- let addedCards = [];
466
- addedCards = await this.stack.createDocs(paramsArray.map(params => ({ docId: null, params })), this.getName(), this);
467
- return addedCards;
468
- };
469
- this.getByPrimaryKeys = async (params) => {
470
- const fnLogger = this.logger.child({ method: "getByPrimaryKeys" });
471
- // attempt to retrieve card by primary key
472
- let filter = {};
473
- let primaryKeys = this.getPrimaryKeys();
474
- fnLogger.info("Got primary keys", { primaryKeys });
475
- if (primaryKeys.length) {
476
- // executes a reducer function on each element of the primaryKeys array
477
- // that sets each primary key prop to the corresponding param value
478
- primaryKeys.reduce((accumulator, currentValue) => accumulator[currentValue] = params[currentValue], filter);
479
- fnLogger.info("Defined filter", { filter });
480
- let cards = await this.getCards(filter, undefined, 0, 1);
481
- if (cards.length > 0) {
482
- return cards[0];
483
- }
484
- else {
485
- fnLogger.info("Did not find any documents with given primary key", { filter });
486
- return null;
487
- }
488
- }
489
- else {
490
- fnLogger.info("Class has no field specified as primary key");
491
- return null;
492
- }
493
- };
494
- this.addOrUpdateCard = async (params, cardId) => {
495
- const fnLogger = this.logger.child({ method: "addOrUpdateCard", args: { params, cardId } });
496
- const document = await new Promise(async (resolve, reject) => {
497
- if (cardId) {
498
- fnLogger.info("Provided document's id, performing an update");
499
- const res = await this.updateCard(cardId, params);
500
- resolve(res);
501
- }
502
- else {
503
- fnLogger.info("No document id provided, checking for PKs");
504
- const card = await this.getByPrimaryKeys(params);
505
- if (card == null) {
506
- const res = await this.addCard(params);
507
- resolve(res);
508
- }
509
- else {
510
- fnLogger.error("Duplicate card by keys");
511
- reject("Duplicate card by keys");
512
- }
513
- }
514
- });
515
- fnLogger.warn("Updated document", { document });
516
- return document;
517
- };
518
- /**
519
- * Pushes a document to the database.
520
- * This is an alias for {@alias addOrUpdateCard}.
521
- *
522
- * @param params - The document data
523
- * @param docId - Optional document ID. If provided, performs an update.
524
- * @returns The created or updated document
525
- */
526
- this.push = async (params, docId) => {
527
- return this.addOrUpdateCard(params, docId);
528
- };
529
- /**
530
- * Updates an existing document (card) of this class.
531
- *
532
- * @param cardId - The document ID to update
533
- * @param params - The updated document data
534
- * @returns The updated document, or `null` if stack is not defined
535
- */
536
- this.updateCard = async (cardId, params) => {
537
- return new Promise(async (resolve, reject) => {
538
- if (this.stack) {
539
- const res = await this.stack.createDoc(cardId, this.getName(), this, params);
540
- resolve(res);
541
- }
542
- else {
543
- _a.logger.info("no stack defined");
544
- resolve(null);
545
- }
546
- });
547
- };
548
- /**
549
- * Soft-deletes a document by setting its `active` flag to `false`.
550
- *
551
- * @param cardId - The document ID to delete
552
- * @returns `true` if successful, `false` otherwise
553
- */
554
- this.deleteCard = async (cardId) => {
555
- const fnLogger = this.logger.child({ method: "deleteCard", args: { cardId } });
556
- if (this.stack) {
557
- const res = await this.stack.deleteDocument(cardId);
558
- return res;
559
- }
560
- else {
561
- fnLogger.error("Stack is not defined");
562
- return false;
563
- }
564
- };
565
- /**
566
- * Retrieves documents (cards) of this class type.
567
- *
568
- * @param selector - Optional PouchDB/Mango selector for filtering
569
- * @param fields - Optional list of fields to return
570
- * @param skip - Number of documents to skip
571
- * @param limit - Maximum number of documents to return
572
- * @returns Array of matching documents
573
- *
574
- * @example
575
- * ```typescript
576
- * // Get all tasks
577
- * const allTasks = await taskClass.getCards();
578
- *
579
- * // Get incomplete tasks
580
- * const incomplete = await taskClass.getCards({ isComplete: { $eq: false } });
581
- * ```
582
- */
583
- this.getCards = async (selector, fields, skip, limit) => {
584
- const _selector = Object.assign(Object.assign({}, (selector || {})), { "~class": { $eq: this.name } });
585
- this.logger.info("getCards - selector", { selector: _selector, fields, skip, limit });
586
- let docs = (await this.stack.findDocuments(_selector, fields, skip, limit)).docs;
587
- return docs;
588
- };
589
- /**
590
- * Adds a trigger to this class.
591
- * Triggers execute before or after document operations.
592
- *
593
- * @param name - The trigger name
594
- * @param model - The trigger model containing the execution logic
595
- * @returns This Class instance for chaining
596
- *
597
- * @example
598
- * ```typescript
599
- * await taskClass.addTrigger('generate-slug', {
600
- * name: 'generate-slug',
601
- * order: 'before',
602
- * run: `document.slug = document.title.toLowerCase().replace(/\\s+/g, '-'); return document;`
603
- * });
604
- * ```
605
- */
606
- this.addTrigger = async (name, model) => {
607
- const fnLogger = this.logger.child({ method: "addTrigger" });
608
- try {
609
- const trigger = new Trigger(model, this);
610
- this.triggers.push(trigger);
611
- if (this.stack) {
612
- this.setModel();
613
- let res = await this.stack.updateClass(this);
614
- }
615
- else {
616
- throw new Error(`Stack is not defined. Can't update class`);
617
- }
618
- }
619
- catch (e) {
620
- fnLogger.error(e);
621
- }
622
- return this;
623
- };
624
- /**
625
- * Removes a trigger from this class by name.
626
- *
627
- * @param name - The name of the trigger to remove
628
- * @returns This Class instance for chaining
629
- */
630
- this.removeTrigger = async (name) => {
631
- this.triggers = this.triggers.filter(t => t.name != name);
632
- return this;
633
- };
634
- // Private constructor to prevent direct instantiation
635
- /* Populated on async build */
636
- // this.id = null;
637
- }
638
- async add(...paramsArray) {
639
- const fnLogger = this.logger.child({ method: "add", args: { paramsArray } });
640
- const addedCards = await this.addCards(paramsArray);
641
- fnLogger.info("Added cards", { addedCards });
642
- if (paramsArray.length === 1)
643
- return addedCards[0] || null;
644
- return addedCards;
645
- }
646
- async get(...cardId) {
647
- const fnLogger = this.logger.child({ method: "get", args: { cardId } });
648
- if (typeof cardId === "string") {
649
- let docs = await this.getCards({ _id: { $eq: cardId } });
650
- return docs[0] || null;
651
- }
652
- else {
653
- let docs = await this.getCards({ _id: { $in: cardId } });
654
- fnLogger.info("Fetched documents", { docs });
655
- return docs;
656
- }
657
- }
658
- }
659
- _a = Class;
660
- Class.logger = createLogger().child({ module: "class" });
661
- /**
662
- * Gets a Class instance without persisting it to the database.
663
- * Use this for working with existing class models or for testing.
664
- * Sets up a document change listener for real-time updates.
665
- *
666
- * @param stack - The parent stack instance
667
- * @param id - The class ID
668
- * @param name - The class name
669
- * @param type - The class type
670
- * @param description - Optional description
671
- * @param schema - Initial schema definition
672
- * @returns A new Class instance (not persisted)
673
- */
674
- Class.get = (stack, id, name, type, description, schema = {}) => {
675
- const class_ = new _a();
676
- _a.logger.info("Received schema", { schema });
677
- class_.init(stack, id, name, type, description, schema);
678
- // Add listener for new documents of this class type
679
- class_.stack.onClassDoc(name)
680
- .on("change", (change) => {
681
- const evt = new CustomEvent("doc", {
682
- detail: change
683
- });
684
- class_.dispatchEvent(evt);
685
- });
686
- return class_;
687
- };
688
- /**
689
- * Creates a new class and persists it to the database.
690
- * This is the primary factory method for creating new classes.
691
- *
692
- * @param stack - The parent stack instance
693
- * @param name - The name for the new class
694
- * @param type - The class type (typically 'class')
695
- * @param description - Optional description of the class
696
- * @param schema - Initial schema definition
697
- * @returns The persisted Class instance
698
- *
699
- * @example
700
- * ```typescript
701
- * const userClass = await Class.create(stack, 'User', 'class', 'Application users');
702
- * ```
703
- */
704
- Class.create = async (stack, name, type, description, schema = {}) => {
705
- const class_ = _a.get(stack, name, name, type, description, schema);
706
- await class_.build();
707
- return class_;
708
- };
709
- /**
710
- * Builds a Class instance from an existing ClassModel document.
711
- * Hydrates attributes and triggers from the model.
712
- *
713
- * @param stack - The parent stack instance
714
- * @param classModel - The ClassModel document from the database
715
- * @returns The hydrated Class instance
716
- */
717
- Class.buildFromModel = async (stack, classModel) => {
718
- _a.logger.info("buildFromModel - Instantiate from model", { classModel });
719
- if (classModel._rev) {
720
- let classObj = _a.get(stack, classModel._id, classModel.name, classModel["~class"], classModel.description, classModel.schema);
721
- classObj.setModel(classModel);
722
- return classObj;
723
- }
724
- else {
725
- let classObj = await _a.create(stack, classModel.name, classModel["~class"], classModel["~class"], classModel.schema);
726
- classObj.setModel(classModel);
727
- return classObj;
728
- }
729
- };
730
- /**
731
- * Fetches a class by its document ID.
732
- *
733
- * @param stack - The parent stack instance
734
- * @param classId - The class document ID
735
- * @returns The Class instance
736
- * @throws Error if the class is not found
737
- */
738
- Class.fetchById = async (stack, classId) => {
739
- try {
740
- let classModel = await stack.db.get(classId);
741
- const classObj = await _a.buildFromModel(stack, classModel);
742
- return classObj;
743
- }
744
- catch (error) {
745
- throw new Error(`Class not found: ${classId}`);
746
- }
747
- };
748
- /**
749
- * Fetches a class by its name.
750
- * This is the most common way to retrieve an existing class.
751
- *
752
- * @param stack - The parent stack instance
753
- * @param className - The class name to fetch
754
- * @returns The Class instance, or `null` if not found
755
- *
756
- * @example
757
- * ```typescript
758
- * const taskClass = await Class.fetch(stack, 'Task');
759
- * if (taskClass) {
760
- * const tasks = await taskClass.getCards();
761
- * }
762
- * ```
763
- */
764
- Class.fetch = async (stack, className) => {
765
- let classModel = await stack.getClassModel(className);
766
- if (classModel) {
767
- return _a.buildFromModel(stack, classModel);
768
- }
769
- else {
770
- return null;
771
- }
772
- };
773
- export default Class;
774
- //# sourceMappingURL=class.js.map