@webda/core 3.6.0 → 3.8.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 (109) hide show
  1. package/lib/application.d.ts +7 -1
  2. package/lib/application.js.map +1 -1
  3. package/lib/core.d.ts +9 -0
  4. package/lib/core.js +44 -1
  5. package/lib/core.js.map +1 -1
  6. package/lib/core.spec.js +5 -4
  7. package/lib/core.spec.js.map +1 -1
  8. package/lib/index.d.ts +5 -4
  9. package/lib/index.js +5 -4
  10. package/lib/index.js.map +1 -1
  11. package/lib/models/coremodel.d.ts +103 -12
  12. package/lib/models/coremodel.js +230 -33
  13. package/lib/models/coremodel.js.map +1 -1
  14. package/lib/models/coremodel.spec.js +21 -4
  15. package/lib/models/coremodel.spec.js.map +1 -1
  16. package/lib/models/ident.d.ts +2 -6
  17. package/lib/models/ident.js.map +1 -1
  18. package/lib/models/ident.spec.js.map +1 -1
  19. package/lib/models/relations.d.ts +24 -14
  20. package/lib/models/relations.js +36 -8
  21. package/lib/models/relations.js.map +1 -1
  22. package/lib/models/relations.spec.d.ts +12 -0
  23. package/lib/models/relations.spec.js +223 -0
  24. package/lib/models/relations.spec.js.map +1 -0
  25. package/lib/models/user.d.ts +2 -2
  26. package/lib/models/user.js.map +1 -1
  27. package/lib/services/asyncevents.d.ts +4 -3
  28. package/lib/services/asyncevents.js +17 -4
  29. package/lib/services/asyncevents.js.map +1 -1
  30. package/lib/services/authentication.js +1 -1
  31. package/lib/services/authentication.js.map +1 -1
  32. package/lib/services/binary.d.ts +26 -2
  33. package/lib/services/binary.js +160 -63
  34. package/lib/services/binary.js.map +1 -1
  35. package/lib/services/binary.spec.js +3 -1
  36. package/lib/services/binary.spec.js.map +1 -1
  37. package/lib/services/cloudbinary.d.ts +0 -18
  38. package/lib/services/cloudbinary.js +0 -94
  39. package/lib/services/cloudbinary.js.map +1 -1
  40. package/lib/services/cloudbinary.spec.js +18 -11
  41. package/lib/services/cloudbinary.spec.js.map +1 -1
  42. package/lib/services/domainservice.d.ts +2 -1
  43. package/lib/services/domainservice.js +13 -22
  44. package/lib/services/domainservice.js.map +1 -1
  45. package/lib/services/filebinary.js +1 -1
  46. package/lib/services/filebinary.js.map +1 -1
  47. package/lib/services/filebinary.spec.d.ts +1 -0
  48. package/lib/services/filebinary.spec.js +24 -2
  49. package/lib/services/filebinary.spec.js.map +1 -1
  50. package/lib/services/invitationservice.spec.js +3 -1
  51. package/lib/services/invitationservice.spec.js.map +1 -1
  52. package/lib/services/prometheus.js +1 -0
  53. package/lib/services/prometheus.js.map +1 -1
  54. package/lib/services/service.d.ts +0 -5
  55. package/lib/services/service.js +3 -34
  56. package/lib/services/service.js.map +1 -1
  57. package/lib/services/service.spec.js +2 -2
  58. package/lib/services/service.spec.js.map +1 -1
  59. package/lib/stores/aliasstore.js +5 -1
  60. package/lib/stores/aliasstore.js.map +1 -1
  61. package/lib/stores/file.js.map +1 -1
  62. package/lib/stores/mapper.d.ts +4 -4
  63. package/lib/stores/mapper.spec.js +1 -1
  64. package/lib/stores/mapper.spec.js.map +1 -1
  65. package/lib/stores/memory.spec.d.ts +1 -0
  66. package/lib/stores/memory.spec.js +28 -1
  67. package/lib/stores/memory.spec.js.map +1 -1
  68. package/lib/stores/modelmapper.d.ts +61 -0
  69. package/lib/stores/modelmapper.js +199 -0
  70. package/lib/stores/modelmapper.js.map +1 -0
  71. package/lib/stores/store.d.ts +33 -11
  72. package/lib/stores/store.js +155 -95
  73. package/lib/stores/store.js.map +1 -1
  74. package/lib/stores/store.spec.js +2 -2
  75. package/lib/stores/store.spec.js.map +1 -1
  76. package/lib/test.js +1 -1
  77. package/lib/test.js.map +1 -1
  78. package/lib/utils/case.d.ts +7 -0
  79. package/lib/utils/case.js +43 -0
  80. package/lib/utils/case.js.map +1 -0
  81. package/lib/utils/case.spec.d.ts +1 -0
  82. package/lib/utils/case.spec.js +50 -0
  83. package/lib/utils/case.spec.js.map +1 -0
  84. package/lib/utils/context.d.ts +3 -2
  85. package/lib/utils/context.js +6 -2
  86. package/lib/utils/context.js.map +1 -1
  87. package/lib/utils/cookie.spec.js +2 -2
  88. package/lib/utils/cookie.spec.js.map +1 -1
  89. package/lib/utils/esm.d.ts +9 -0
  90. package/lib/utils/esm.js +9 -0
  91. package/lib/utils/esm.js.map +1 -1
  92. package/lib/utils/httpcontext.d.ts +1 -1
  93. package/lib/utils/httpcontext.js +1 -0
  94. package/lib/utils/httpcontext.js.map +1 -1
  95. package/lib/utils/logger.spec.js +5 -2
  96. package/lib/utils/logger.spec.js.map +1 -1
  97. package/lib/utils/serializers.js +8 -1
  98. package/lib/utils/serializers.js.map +1 -1
  99. package/lib/utils/serializers.spec.js +6 -0
  100. package/lib/utils/serializers.spec.js.map +1 -1
  101. package/lib/utils/session.spec.js +1 -1
  102. package/lib/utils/session.spec.js.map +1 -1
  103. package/lib/utils/throttler.d.ts +22 -2
  104. package/lib/utils/throttler.js +35 -3
  105. package/lib/utils/throttler.js.map +1 -1
  106. package/lib/utils/throttler.spec.js +10 -2
  107. package/lib/utils/throttler.spec.js.map +1 -1
  108. package/package.json +10 -10
  109. package/webda.module.json +60 -26
@@ -1,8 +1,10 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from "events";
1
3
  import { JSONSchema7 } from "json-schema";
2
4
  import { ModelGraph, ModelsTree } from "../application.js";
3
5
  import { Core } from "../core.js";
4
6
  import { Service } from "../services/service.js";
5
- import { Store } from "../stores/store.js";
7
+ import { Store, StoreEvents } from "../stores/store.js";
6
8
  import { OperationContext } from "../utils/context.js";
7
9
  import { HttpMethodType } from "../utils/httpcontext.js";
8
10
  import { ModelActions, RawModel } from "./relations.js";
@@ -15,10 +17,18 @@ import { ModelActions, RawModel } from "./relations.js";
15
17
  * @returns
16
18
  */
17
19
  export declare function Expose(params?: Partial<ExposeParameters>): (target: CoreModelDefinition) => void;
20
+ /**
21
+ * Attribute of an object
22
+ *
23
+ * Filter out methods
24
+ */
25
+ export type Attributes<T extends object> = {
26
+ [K in keyof T]: T[K] extends Function ? never : K;
27
+ }[keyof T];
18
28
  /**
19
29
  * Filter type keys by type
20
30
  */
21
- export type FilterKeys<T extends CoreModel, K> = {
31
+ export type FilterAttributes<T extends CoreModel, K> = {
22
32
  [L in keyof T]: T[L] extends K ? L : never;
23
33
  }[keyof T];
24
34
  /**
@@ -107,7 +117,7 @@ export interface CoreModelDefinition<T extends CoreModel = CoreModel> {
107
117
  * @param object to load data from
108
118
  * @param context if the data is unsafe from http
109
119
  */
110
- factory(model: new () => T, object: any, context?: OperationContext): T;
120
+ factory<T extends CoreModel>(this: Constructor<T>, object: Partial<T>, context?: OperationContext): T;
111
121
  /**
112
122
  * Get the model actions
113
123
  */
@@ -172,10 +182,17 @@ export interface CoreModelDefinition<T extends CoreModel = CoreModel> {
172
182
  results: T[];
173
183
  continuationToken?: string;
174
184
  }>;
185
+ on<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, listener: (evt: StoreEvents[Key]) => any, async?: boolean): void;
186
+ onAsync<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, listener: (evt: StoreEvents[Key]) => any): any;
187
+ emit<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): any;
188
+ emitSync<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): Promise<void>;
175
189
  }
176
190
  export type Constructor<T, K extends Array<any> = []> = new (...args: K) => T;
177
191
  /**
178
192
  * Make a property hidden from json
193
+ *
194
+ * This property will not be saved in the store
195
+ *
179
196
  * @param target
180
197
  * @param propertyKey
181
198
  */
@@ -200,18 +217,18 @@ export declare class ModelRef<T extends CoreModel> {
200
217
  toString(): string;
201
218
  toJSON(): string;
202
219
  getUuid(): string;
203
- deleteItemFromCollection(prop: FilterKeys<T, any[]>, index: number, itemWriteCondition: any, itemWriteConditionField?: string): Promise<void>;
204
- upsertItemToCollection(prop: FilterKeys<T, any[]>, item: any, index?: number, itemWriteCondition?: any, itemWriteConditionField?: string): Promise<void>;
220
+ deleteItemFromCollection(prop: FilterAttributes<T, any[]>, index: number, itemWriteCondition: any, itemWriteConditionField?: string): Promise<this>;
221
+ upsertItemToCollection(prop: FilterAttributes<T, any[]>, item: any, index?: number, itemWriteCondition?: any, itemWriteConditionField?: string): Promise<this>;
205
222
  exists(): Promise<boolean>;
206
223
  delete(): Promise<void>;
207
224
  conditionalPatch(updates: Partial<T>, conditionField: any, condition: any): Promise<boolean>;
208
225
  patch(updates: Partial<T>): Promise<boolean>;
209
- setAttribute(attribute: keyof T, value: any): Promise<void>;
210
- removeAttribute(attribute: keyof T, itemWriteCondition?: any, itemWriteConditionField?: keyof T): Promise<void>;
226
+ setAttribute(attribute: keyof T, value: any): Promise<this>;
227
+ removeAttribute(attribute: keyof T, itemWriteCondition?: any, itemWriteConditionField?: keyof T): Promise<this>;
211
228
  incrementAttributes(info: {
212
- property: FilterKeys<T, number>;
229
+ property: FilterAttributes<T, number>;
213
230
  value: number;
214
- }[]): Promise<any[]>;
231
+ }[]): Promise<this>;
215
232
  }
216
233
  export declare class ModelRefWithCreate<T extends CoreModel> extends ModelRef<T> {
217
234
  /**
@@ -240,6 +257,7 @@ export declare class ModelRefCustom<T extends CoreModel> extends ModelRef<T> {
240
257
  getUuid(): string;
241
258
  }
242
259
  export type ModelRefCustomProperties<T extends CoreModel, K> = ModelRefCustom<T> & K;
260
+ export declare const Emitters: WeakMap<Constructor<CoreModel>, EventEmitter>;
243
261
  /**
244
262
  * Basic Object in Webda
245
263
  *
@@ -254,7 +272,7 @@ declare class CoreModel {
254
272
  /**
255
273
  * Class reference to the object
256
274
  */
257
- __class: CoreModelDefinition;
275
+ __class: CoreModelDefinition<this>;
258
276
  /**
259
277
  * Type name
260
278
  */
@@ -291,6 +309,33 @@ declare class CoreModel {
291
309
  */
292
310
  __deleted: boolean;
293
311
  constructor();
312
+ /**
313
+ * Listen to events on the model
314
+ * @param event
315
+ * @param listener
316
+ * @param async
317
+ */
318
+ static on<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, listener: (evt: StoreEvents[Key]) => any, async?: boolean): void;
319
+ /**
320
+ * Emit an event for this class
321
+ * @param this
322
+ * @param event
323
+ * @param evt
324
+ */
325
+ static emit<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): void;
326
+ /**
327
+ * Emit an event for this class and wait for all listeners to finish
328
+ * @param this
329
+ * @param event
330
+ * @param evt
331
+ */
332
+ static emitSync<T extends CoreModel, Key extends keyof StoreEvents>(this: Constructor<T>, event: Key, evt: StoreEvents[Key]): Promise<void>;
333
+ /**
334
+ * Listen to events on the model asynchronously
335
+ * @param event
336
+ * @param listener
337
+ */
338
+ static onAsync<Key extends keyof StoreEvents>(event: Key, listener: (evt: StoreEvents[Key]) => any): void;
294
339
  /**
295
340
  *
296
341
  * @returns
@@ -383,6 +428,22 @@ declare class CoreModel {
383
428
  * @param prefix
384
429
  */
385
430
  static flat(target: any, data: any, split?: string, prefix?: string): any;
431
+ /**
432
+ * Complete the query with __type/__types
433
+ * @param query
434
+ * @param includeSubclass
435
+ * @returns
436
+ */
437
+ protected static completeQuery(query: string, includeSubclass?: boolean): string;
438
+ /**
439
+ * Iterate through the model
440
+ * @param this
441
+ * @param query
442
+ * @param includeSubclass
443
+ * @param context
444
+ * @returns
445
+ */
446
+ static iterate<T extends CoreModel>(this: Constructor<T>, query?: string, includeSubclass?: boolean, context?: OperationContext): AsyncGenerator<T>;
386
447
  /**
387
448
  * Query for models
388
449
  * @param this
@@ -444,7 +505,7 @@ declare class CoreModel {
444
505
  * Create an object
445
506
  * @returns
446
507
  */
447
- static factory(model: new () => CoreModel, object: any, context?: OperationContext): CoreModel;
508
+ static factory<T extends CoreModel>(this: Constructor<T>, object: Partial<T>, context?: OperationContext): T;
448
509
  /**
449
510
  * Detect what looks like a CoreModel but can be from different version
450
511
  * @param object
@@ -485,7 +546,7 @@ declare class CoreModel {
485
546
  * @param raw data
486
547
  * @param secure if false will ignore any _ variable
487
548
  */
488
- load(raw: RawModel<this>, secure?: boolean): this;
549
+ load(raw: RawModel<this>, secure?: boolean, relations?: boolean): this;
489
550
  /**
490
551
  * Patch every attribute that is based on a relation
491
552
  * to add all the helpers
@@ -608,6 +669,36 @@ declare class CoreModel {
608
669
  * Called when object is updated
609
670
  */
610
671
  _onUpdated(): Promise<void>;
672
+ /**
673
+ * Set attribute on the object and database
674
+ * @param property
675
+ * @param value
676
+ */
677
+ setAttribute(property: keyof this, value: any): Promise<void>;
678
+ /**
679
+ * Remove attribute from both the object and db
680
+ * @param property
681
+ */
682
+ removeAttribute(property: keyof this): Promise<void>;
683
+ /**
684
+ * Increment an attribute both in store and object
685
+ * @param property
686
+ * @param value
687
+ */
688
+ incrementAttribute(property: FilterAttributes<this, number>, value: number): Promise<void>;
689
+ /**
690
+ * Return a model ref
691
+ * @returns
692
+ */
693
+ getRef<T extends this>(): ModelRef<T>;
694
+ /**
695
+ * Increment a attributes both in store and object
696
+ * @param info
697
+ */
698
+ incrementAttributes(info: {
699
+ property: string;
700
+ value: number;
701
+ }[]): Promise<void>;
611
702
  }
612
703
  /**
613
704
  * CoreModel with a uuid
@@ -4,9 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
+ import { EventEmitter } from "events";
7
8
  import util from "util";
8
9
  import { v4 as uuidv4 } from "uuid";
9
- import { Core } from "../core.js";
10
+ import { Core, EventEmitterUtils } from "../core.js";
10
11
  import { WebdaError } from "../errors.js";
11
12
  import { BinariesImpl, Binary } from "../services/binary.js";
12
13
  import { Throttler } from "../utils/throttler.js";
@@ -68,23 +69,29 @@ class CoreModelQuery {
68
69
  async forEach(callback, query, context, parallelism = 3) {
69
70
  const throttler = new Throttler();
70
71
  throttler.setConcurrency(parallelism);
71
- let continuationToken;
72
- do {
73
- const result = await this.query(query + continuationToken ? "OFFSET " + continuationToken : "", context);
74
- continuationToken = result.continuationToken;
75
- for (const model of result.results) {
76
- throttler.queue(() => callback(model));
77
- }
78
- await throttler.waitForCompletion();
79
- } while (continuationToken);
72
+ for await (const model of this.iterate(query, context)) {
73
+ throttler.execute(() => callback(model));
74
+ }
75
+ return throttler.wait();
80
76
  }
81
77
  /**
82
- * Get all objects linked
78
+ * Iterate through all
83
79
  * @param context
84
80
  * @returns
85
81
  */
86
- async getAll(query, context) {
87
- return Core.get().getModelStore(this.getTargetModel()).queryAll(this.completeQuery(query), context);
82
+ iterate(query, context) {
83
+ return Core.get().getModelStore(this.getTargetModel()).iterate(this.completeQuery(query), context);
84
+ }
85
+ /**
86
+ * Get all the objects
87
+ * @returns
88
+ */
89
+ async getAll(context) {
90
+ let res = [];
91
+ for await (const item of this.iterate(this.completeQuery(), context)) {
92
+ res.push(item);
93
+ }
94
+ return res;
88
95
  }
89
96
  }
90
97
  __decorate([
@@ -101,6 +108,9 @@ __decorate([
101
108
  ], CoreModelQuery.prototype, "targetModel", void 0);
102
109
  /**
103
110
  * Make a property hidden from json
111
+ *
112
+ * This property will not be saved in the store
113
+ *
104
114
  * @param target
105
115
  * @param propertyKey
106
116
  */
@@ -151,6 +161,7 @@ export class ModelRef {
151
161
  }
152
162
  set(id) {
153
163
  this.uuid = id instanceof CoreModel ? id.getUuid() : id;
164
+ this.parent?.__dirty.add(Object.keys(this.parent).find(k => this.parent[k] === this));
154
165
  }
155
166
  toString() {
156
167
  return this.uuid;
@@ -161,11 +172,36 @@ export class ModelRef {
161
172
  getUuid() {
162
173
  return this.uuid;
163
174
  }
164
- deleteItemFromCollection(prop, index, itemWriteCondition, itemWriteConditionField) {
165
- return this.store.deleteItemFromCollection(this.uuid, prop, index, itemWriteCondition, itemWriteConditionField);
175
+ async deleteItemFromCollection(prop, index, itemWriteCondition, itemWriteConditionField) {
176
+ const updateDate = await this.store.deleteItemFromCollection(this.uuid, prop, index, itemWriteCondition, itemWriteConditionField);
177
+ await this.model.emitSync("Store.PartialUpdated", {
178
+ object_id: this.uuid,
179
+ store: this.store,
180
+ updateDate,
181
+ partial_update: {
182
+ deleteItem: {
183
+ property: prop,
184
+ index: index
185
+ }
186
+ }
187
+ });
188
+ return this;
166
189
  }
167
- upsertItemToCollection(prop, item, index, itemWriteCondition, itemWriteConditionField) {
168
- return this.store.upsertItemToCollection(this.uuid, prop, item, index, itemWriteCondition, itemWriteConditionField);
190
+ async upsertItemToCollection(prop, item, index, itemWriteCondition, itemWriteConditionField) {
191
+ const updateDate = await this.store.upsertItemToCollection(this.uuid, prop, item, index, itemWriteCondition, itemWriteConditionField);
192
+ await this.model.emitSync("Store.PartialUpdated", {
193
+ object_id: this.uuid,
194
+ store: this.store,
195
+ updateDate,
196
+ partial_update: {
197
+ addItem: {
198
+ value: item,
199
+ property: prop,
200
+ index: index
201
+ }
202
+ }
203
+ });
204
+ return this;
169
205
  }
170
206
  exists() {
171
207
  return this.store.exists(this.uuid);
@@ -179,14 +215,32 @@ export class ModelRef {
179
215
  patch(updates) {
180
216
  return this.store.conditionalPatch(this.uuid, updates, null, undefined);
181
217
  }
182
- setAttribute(attribute, value) {
183
- return this.store.setAttribute(this.uuid, attribute, value);
218
+ async setAttribute(attribute, value) {
219
+ await this.store.setAttribute(this.uuid, attribute, value);
220
+ return this;
184
221
  }
185
- removeAttribute(attribute, itemWriteCondition, itemWriteConditionField) {
186
- return this.store.removeAttribute(this.uuid, attribute, itemWriteCondition, itemWriteConditionField);
222
+ async removeAttribute(attribute, itemWriteCondition, itemWriteConditionField) {
223
+ await this.store.removeAttribute(this.uuid, attribute, itemWriteCondition, itemWriteConditionField);
224
+ await this.model?.emitSync("Store.PartialUpdated", {
225
+ object_id: this.uuid,
226
+ store: this.store,
227
+ partial_update: {
228
+ deleteAttribute: attribute
229
+ }
230
+ });
231
+ return this;
187
232
  }
188
- incrementAttributes(info) {
189
- return this.store.incrementAttributes(this.uuid, info);
233
+ async incrementAttributes(info) {
234
+ const updateDate = await this.store.incrementAttributes(this.uuid, info);
235
+ await this.model.emitSync("Store.PartialUpdated", {
236
+ object_id: this.uuid,
237
+ store: this.store,
238
+ updateDate,
239
+ partial_update: {
240
+ increments: info
241
+ }
242
+ });
243
+ return this;
190
244
  }
191
245
  }
192
246
  __decorate([
@@ -239,6 +293,7 @@ export class ModelRefCustom extends ModelRef {
239
293
  return this.uuid;
240
294
  }
241
295
  }
296
+ export const Emitters = new WeakMap();
242
297
  /**
243
298
  * Basic Object in Webda
244
299
  *
@@ -262,6 +317,78 @@ class CoreModel {
262
317
  ?.getApplication()
263
318
  .getShortId(Core.get()?.getApplication().getModelFromInstance(this));
264
319
  }
320
+ /**
321
+ * Listen to events on the model
322
+ * @param event
323
+ * @param listener
324
+ * @param async
325
+ */
326
+ static on(event, listener, async = false) {
327
+ if (!Emitters.has(this)) {
328
+ Emitters.set(this, new EventEmitter());
329
+ }
330
+ // TODO Manage async
331
+ if (async) {
332
+ Core.get()
333
+ .getService("AsyncEvents")
334
+ .bindAsyncListener(this, event, listener);
335
+ }
336
+ else {
337
+ Emitters.get(this).on(event, listener);
338
+ }
339
+ }
340
+ /**
341
+ * Emit an event for this class
342
+ * @param this
343
+ * @param event
344
+ * @param evt
345
+ */
346
+ static emit(event, evt) {
347
+ let clazz = this;
348
+ // @ts-ignore
349
+ while (clazz) {
350
+ // Emit for all parent class
351
+ if (Emitters.has(clazz)) {
352
+ EventEmitterUtils.emit(Emitters.get(clazz), event, evt);
353
+ }
354
+ // @ts-ignore
355
+ if (clazz === CoreModel) {
356
+ break;
357
+ }
358
+ clazz = Object.getPrototypeOf(clazz);
359
+ }
360
+ }
361
+ /**
362
+ * Emit an event for this class and wait for all listeners to finish
363
+ * @param this
364
+ * @param event
365
+ * @param evt
366
+ */
367
+ static async emitSync(event, evt) {
368
+ let clazz = this;
369
+ let p = [];
370
+ // @ts-ignore
371
+ while (clazz) {
372
+ // Emit for all parent class
373
+ if (Emitters.has(clazz)) {
374
+ p.push(EventEmitterUtils.emitSync(Emitters.get(clazz), event, evt));
375
+ }
376
+ // @ts-ignore
377
+ if (clazz === CoreModel) {
378
+ break;
379
+ }
380
+ clazz = Object.getPrototypeOf(clazz);
381
+ }
382
+ await Promise.all(p);
383
+ }
384
+ /**
385
+ * Listen to events on the model asynchronously
386
+ * @param event
387
+ * @param listener
388
+ */
389
+ static onAsync(event, listener) {
390
+ this.on(event, listener, true);
391
+ }
265
392
  /**
266
393
  *
267
394
  * @returns
@@ -407,12 +534,12 @@ class CoreModel {
407
534
  }
408
535
  }
409
536
  /**
410
- * Query for models
411
- * @param this
412
- * @param id
537
+ * Complete the query with __type/__types
538
+ * @param query
539
+ * @param includeSubclass
413
540
  * @returns
414
541
  */
415
- static async query(query = "", includeSubclass = true, context) {
542
+ static completeQuery(query, includeSubclass = true) {
416
543
  if (!query.includes("__type")) {
417
544
  if (query.trim() !== "") {
418
545
  query = ` AND ${query}`;
@@ -426,8 +553,29 @@ class CoreModel {
426
553
  query = `__type = "${name}"${query}`;
427
554
  }
428
555
  }
556
+ return query;
557
+ }
558
+ /**
559
+ * Iterate through the model
560
+ * @param this
561
+ * @param query
562
+ * @param includeSubclass
563
+ * @param context
564
+ * @returns
565
+ */
566
+ static iterate(query = "", includeSubclass = true, context) {
567
+ // @ts-ignore
568
+ return this.store().iterate(this.completeQuery(query, includeSubclass), context);
569
+ }
570
+ /**
571
+ * Query for models
572
+ * @param this
573
+ * @param id
574
+ * @returns
575
+ */
576
+ static async query(query = "", includeSubclass = true, context) {
429
577
  // @ts-ignore
430
- return this.store().query(query, context);
578
+ return this.store().query(this.completeQuery(query, includeSubclass), context);
431
579
  }
432
580
  /**
433
581
  * Return a proxy to the object to detect if dirty
@@ -553,8 +701,8 @@ class CoreModel {
553
701
  * Create an object
554
702
  * @returns
555
703
  */
556
- static factory(model, object, context) {
557
- return new model().setContext(context).load(object, context === undefined);
704
+ static factory(object, context) {
705
+ return object instanceof this ? object : new this().setContext(context).load(object, context === undefined);
558
706
  }
559
707
  /**
560
708
  * Detect what looks like a CoreModel but can be from different version
@@ -614,7 +762,7 @@ class CoreModel {
614
762
  * @param raw data
615
763
  * @param secure if false will ignore any _ variable
616
764
  */
617
- load(raw, secure = false) {
765
+ load(raw, secure = false, relations = true) {
618
766
  // Object assign with filter
619
767
  for (let prop in raw) {
620
768
  let val = raw[prop];
@@ -636,7 +784,9 @@ class CoreModel {
636
784
  if (!this.getUuid()) {
637
785
  this.setUuid(this.generateUid(raw));
638
786
  }
639
- this.handleRelations();
787
+ if (relations) {
788
+ this.handleRelations();
789
+ }
640
790
  return this;
641
791
  }
642
792
  /**
@@ -740,7 +890,7 @@ class CoreModel {
740
890
  * @throws Error if the object is not coming from a store
741
891
  */
742
892
  async delete() {
743
- return this.__store.delete(this.getUuid());
893
+ return this.__store.delete(this);
744
894
  }
745
895
  /**
746
896
  * Patch current object with this update
@@ -846,6 +996,9 @@ class CoreModel {
846
996
  if (value instanceof ModelRef) {
847
997
  obj[i] = value.toString();
848
998
  }
999
+ else if (value instanceof Binary) {
1000
+ obj[i] = value.toJSON();
1001
+ }
849
1002
  else {
850
1003
  obj[i] = value;
851
1004
  }
@@ -904,6 +1057,50 @@ class CoreModel {
904
1057
  async _onUpdated() {
905
1058
  // Empty to be overriden
906
1059
  }
1060
+ /**
1061
+ * Set attribute on the object and database
1062
+ * @param property
1063
+ * @param value
1064
+ */
1065
+ async setAttribute(property, value) {
1066
+ await this.getRef().setAttribute(property, value);
1067
+ this[property] = value;
1068
+ }
1069
+ /**
1070
+ * Remove attribute from both the object and db
1071
+ * @param property
1072
+ */
1073
+ async removeAttribute(property) {
1074
+ await this.getRef().removeAttribute(property);
1075
+ delete this[property];
1076
+ }
1077
+ /**
1078
+ * Increment an attribute both in store and object
1079
+ * @param property
1080
+ * @param value
1081
+ */
1082
+ async incrementAttribute(property, value) {
1083
+ return this.incrementAttributes([{ property, value }]);
1084
+ }
1085
+ /**
1086
+ * Return a model ref
1087
+ * @returns
1088
+ */
1089
+ getRef() {
1090
+ return new ModelRef(this.getUuid(), this.__class);
1091
+ }
1092
+ /**
1093
+ * Increment a attributes both in store and object
1094
+ * @param info
1095
+ */
1096
+ async incrementAttributes(info) {
1097
+ var _a;
1098
+ await this.getRef().incrementAttributes(info);
1099
+ for (let inc of info) {
1100
+ this[_a = inc.property] ?? (this[_a] = 0);
1101
+ this[inc.property] += inc.value;
1102
+ }
1103
+ }
907
1104
  }
908
1105
  __decorate([
909
1106
  NotEnumerable