@arcote.tech/arc 0.0.26 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/collection/collection.d.ts +28 -48
  2. package/dist/collection/queries/abstract-collection-query.d.ts +4 -6
  3. package/dist/collection/queries/{abstract-many-items.d.ts → find.d.ts} +8 -8
  4. package/dist/collection/queries/one-item.d.ts +1 -18
  5. package/dist/collection/query-builders/find-by-id.d.ts +2 -0
  6. package/dist/collection/query-builders/find-one.d.ts +2 -0
  7. package/dist/collection/query-builders/find.d.ts +13 -0
  8. package/dist/command/command.d.ts +29 -0
  9. package/dist/command/index.d.ts +2 -0
  10. package/dist/context/context.d.ts +34 -18
  11. package/dist/context/element.d.ts +36 -6
  12. package/dist/context/event.d.ts +39 -0
  13. package/dist/context/index.d.ts +4 -0
  14. package/dist/context/query-builder-context.d.ts +15 -0
  15. package/dist/context/query-builders.d.ts +11 -2
  16. package/dist/context/query-cache.d.ts +9 -0
  17. package/dist/context/query.d.ts +5 -3
  18. package/dist/context/reactive-query.d.ts +23 -0
  19. package/dist/context/serializable-query.d.ts +11 -0
  20. package/dist/data-storage/data-storage-master.d.ts +9 -1
  21. package/dist/data-storage/store-state-fork.d.ts +2 -3
  22. package/dist/data-storage/store-state-master.d.ts +2 -5
  23. package/dist/data-storage/store-state.abstract.d.ts +6 -3
  24. package/dist/data-storage/types.d.ts +28 -0
  25. package/dist/db/index.d.ts +1 -0
  26. package/dist/db/interface.d.ts +2 -17
  27. package/dist/db/sqliteAdapter.d.ts +39 -0
  28. package/dist/dist/index.d.ts +513 -0
  29. package/dist/elements/abstract-primitive.d.ts +2 -3
  30. package/dist/elements/abstract.d.ts +18 -1
  31. package/dist/elements/array.d.ts +61 -3
  32. package/dist/elements/boolean.d.ts +1 -1
  33. package/dist/elements/branded.d.ts +4 -3
  34. package/dist/elements/class.d.ts +2 -0
  35. package/dist/elements/date.d.ts +35 -2
  36. package/dist/elements/default.d.ts +1 -0
  37. package/dist/elements/element.d.ts +1 -0
  38. package/dist/elements/index.d.ts +2 -0
  39. package/dist/elements/number.d.ts +36 -2
  40. package/dist/elements/object.d.ts +38 -5
  41. package/dist/elements/optional.d.ts +3 -2
  42. package/dist/elements/or.d.ts +2 -0
  43. package/dist/elements/record.d.ts +16 -4
  44. package/dist/elements/string-enum.d.ts +17 -3
  45. package/dist/elements/string.d.ts +89 -2
  46. package/dist/elements/tests/example.d.ts +6 -0
  47. package/dist/elements/tests/test.d.ts +2 -0
  48. package/dist/elements/utils/type-validator-builder.d.ts +8 -0
  49. package/dist/index.d.ts +3 -0
  50. package/dist/index.js +1528 -708
  51. package/dist/model/index.d.ts +2 -0
  52. package/dist/model/model.d.ts +44 -38
  53. package/dist/state/query-builder.d.ts +1 -8
  54. package/dist/state/query.d.ts +1 -14
  55. package/dist/state/state.d.ts +1 -31
  56. package/dist/tests/context/context.test.d.ts +2 -0
  57. package/dist/tests/pipe.d.ts +2 -0
  58. package/dist/tests/query/advance-query.test.d.ts +2 -0
  59. package/dist/tests/query/collection-all.test.d.ts +2 -0
  60. package/dist/tests/utils/expect-not-false.d.ts +2 -0
  61. package/dist/tests/utils/sqlite-adapter.d.ts +3 -0
  62. package/dist/tests/utils/test-model.d.ts +26 -0
  63. package/dist/tests/validations/array.test.d.ts +2 -0
  64. package/dist/tests/validations/date.test.d.ts +2 -0
  65. package/dist/tests/validations/number.test.d.ts +2 -0
  66. package/dist/tests/validations/record.test.d.ts +2 -0
  67. package/dist/tests/validations/string-enum.test.d.ts +2 -0
  68. package/dist/tests/validations/string.test.d.ts +2 -0
  69. package/dist/utils/arcObjectToStoreSchema.d.ts +4 -0
  70. package/dist/utils/murmur-hash.d.ts +2 -0
  71. package/dist/utils.d.ts +4 -4
  72. package/dist/view/view.d.ts +49 -0
  73. package/package.json +1 -1
  74. package/dist/collection/collection-change.d.ts +0 -18
  75. package/dist/collection/db.d.ts +0 -17
  76. package/dist/collection/queries/all-items.d.ts +0 -7
  77. package/dist/collection/queries/indexed.d.ts +0 -13
  78. package/dist/collection/query-builders/abstract-many-items.d.ts +0 -11
  79. package/dist/collection/query-builders/all-items.d.ts +0 -9
  80. package/dist/collection/query-builders/indexed.d.ts +0 -11
  81. package/dist/collection/query-builders/one-item.d.ts +0 -11
  82. package/dist/collection/utils/index-query.d.ts +0 -6
  83. package/dist/data-storage/DataStorage.d.ts +0 -11
  84. package/dist/data-storage/ForkStoreState.d.ts +0 -32
  85. package/dist/data-storage/StoreState.d.ts +0 -39
  86. package/dist/data-storage/data-storage.d.ts +0 -2
  87. package/dist/data-storage/data-storage.interface.d.ts +0 -46
  88. package/dist/data-storage/master-store-state.d.ts +0 -30
  89. package/dist/data-storage/store-state.d.ts +0 -39
  90. package/dist/elements/object copy.d.ts +0 -29
  91. package/dist/rtc/deserializeChanges.d.ts +0 -3
  92. package/dist/state/db.d.ts +0 -15
  93. package/dist/state/state-change.d.ts +0 -14
  94. package/dist/state/util.d.ts +0 -3
  95. package/dist/tests/query-notification-optimization.test.d.ts +0 -2
  96. package/dist/utils/deep-merge.d.ts +0 -6
  97. /package/dist/{elements/tests → tests/validations}/object.test.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,6 +1,13 @@
1
1
  // context/element.ts
2
2
  class ArcContextElement {
3
3
  $event;
4
+ name;
5
+ commandContext;
6
+ commandClient;
7
+ observer;
8
+ }
9
+
10
+ class ArcContextElementWithStore extends ArcContextElement {
4
11
  }
5
12
 
6
13
  // elements/optional.ts
@@ -24,6 +31,11 @@ class ArcOptional {
24
31
  return null;
25
32
  return this.parent.deserialize(value);
26
33
  }
34
+ validate(value) {
35
+ if (!value)
36
+ return false;
37
+ return this.parent.validate(value);
38
+ }
27
39
  }
28
40
 
29
41
  // elements/branded.ts
@@ -46,6 +58,9 @@ class ArcBranded {
46
58
  optional() {
47
59
  return new ArcOptional(this);
48
60
  }
61
+ validate(value) {
62
+ return this.parent.validate(value);
63
+ }
49
64
  }
50
65
 
51
66
  // elements/default.ts
@@ -56,6 +71,9 @@ class ArcDefault {
56
71
  this.parent = parent;
57
72
  this.defaultValueOrCallback = defaultValueOrCallback;
58
73
  }
74
+ validate(value) {
75
+ throw new Error("Method not implemented.");
76
+ }
59
77
  parse(value) {
60
78
  if (value)
61
79
  return this.parent.parse(value);
@@ -79,6 +97,10 @@ class ArcDefault {
79
97
 
80
98
  // elements/abstract.ts
81
99
  class ArcAbstract {
100
+ validations;
101
+ constructor(validations = []) {
102
+ this.validations = validations;
103
+ }
82
104
  default(defaultValueOrCallback) {
83
105
  return new ArcDefault(this, defaultValueOrCallback);
84
106
  }
@@ -88,13 +110,37 @@ class ArcAbstract {
88
110
  branded(name) {
89
111
  return new ArcBranded(this, name);
90
112
  }
113
+ clone() {
114
+ const Constructor = this.constructor;
115
+ const newInstance = Object.assign(new Constructor, this);
116
+ return newInstance;
117
+ }
118
+ validate(value) {
119
+ const errors = this.validations.reduce((acc, { name, validator }) => {
120
+ try {
121
+ acc[name] = validator(value);
122
+ } catch (error) {
123
+ acc[name] = error;
124
+ }
125
+ return acc;
126
+ }, {});
127
+ if (Object.values(errors).some((result) => !!result)) {
128
+ return errors;
129
+ }
130
+ return false;
131
+ }
132
+ pipeValidation(name, validator) {
133
+ const newInstance = this.clone();
134
+ newInstance.validations = [...this.validations, { name, validator }];
135
+ return newInstance;
136
+ }
137
+ getValidations() {
138
+ return this.validations;
139
+ }
91
140
  }
92
141
 
93
142
  // elements/abstract-primitive.ts
94
143
  class ArcPrimitive extends ArcAbstract {
95
- constructor() {
96
- super();
97
- }
98
144
  serialize(value) {
99
145
  return value;
100
146
  }
@@ -106,8 +152,133 @@ class ArcPrimitive extends ArcAbstract {
106
152
  }
107
153
  }
108
154
 
155
+ // elements/utils/type-validator-builder.ts
156
+ function primitiveTypeComparatorStrategyFactory(type) {
157
+ return (value) => typeof value === type;
158
+ }
159
+ function typeValidatorBuilder(typeName, comparatorStrategy) {
160
+ const comparator = comparatorStrategy || primitiveTypeComparatorStrategyFactory(typeName);
161
+ return {
162
+ name: "type",
163
+ validator: (value) => {
164
+ const valueType = typeof value;
165
+ if (!comparator(value))
166
+ return { current: valueType, expected: typeName };
167
+ return false;
168
+ }
169
+ };
170
+ }
171
+
109
172
  // elements/string.ts
173
+ var stringValidator = typeValidatorBuilder("string");
174
+
110
175
  class ArcString extends ArcPrimitive {
176
+ constructor() {
177
+ super([stringValidator]);
178
+ }
179
+ minLength(min) {
180
+ return this.validation("minLength", (value) => {
181
+ if (value.length < min)
182
+ return {
183
+ currentLength: value.length,
184
+ minLength: min
185
+ };
186
+ });
187
+ }
188
+ maxLength(max) {
189
+ return this.validation("maxLength", (value) => {
190
+ if (value.length > max)
191
+ return {
192
+ currentLength: value.length,
193
+ maxLength: max
194
+ };
195
+ });
196
+ }
197
+ length(number) {
198
+ return this.validation("length", (value) => {
199
+ if (value.length !== number) {
200
+ return {
201
+ currentLength: value.length,
202
+ length: number
203
+ };
204
+ }
205
+ });
206
+ }
207
+ includes(str) {
208
+ return this.validation("includes", (value) => {
209
+ if (!value.includes(str)) {
210
+ return {
211
+ currentValue: value,
212
+ includes: str
213
+ };
214
+ }
215
+ });
216
+ }
217
+ startsWith(str) {
218
+ return this.validation("startsWith", (value) => {
219
+ if (!value.startsWith(str)) {
220
+ return {
221
+ currentValue: value,
222
+ startsWith: str
223
+ };
224
+ }
225
+ });
226
+ }
227
+ endsWith(str) {
228
+ return this.validation("endsWith", (value) => {
229
+ if (!value.endsWith(str)) {
230
+ return {
231
+ currentValue: value,
232
+ endsWith: str
233
+ };
234
+ }
235
+ });
236
+ }
237
+ regex(regex) {
238
+ return this.validation("regex", (value) => {
239
+ if (!regex.test(value)) {
240
+ return {
241
+ currentValue: value,
242
+ regex
243
+ };
244
+ }
245
+ });
246
+ }
247
+ email() {
248
+ const regex = /^(?:(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+)*)|(?:"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f])*"))@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$|(?:\[(?:\d{1,3}\.){3}\d{1,3}\])$/;
249
+ return this.validation("email", (value) => {
250
+ if (!regex.test(value)) {
251
+ return {
252
+ currentEmail: value
253
+ };
254
+ }
255
+ });
256
+ }
257
+ url() {
258
+ const regex = /^(https?):\/\/(?![-0-9])(?!www\.[0-9])(?:[a-zA-Z0-9-]+(?::[a-zA-Z0-9-]+)?@)?(?:localhost|\b(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b|[a-zA-Z0-9-]+\.)?[a-zA-Z0-9-]+\.(?:[a-zA-Z]{2,}|[a-zA-Z]{2}\.[a-zA-Z]{2})(?::\d{1,5})?(?!\/\/)(?:\/[a-zA-Z0-9-._~:?#\[\]@!$&'()*+,;=]*)*(?!\/{2})(?:;[a-zA-Z0-9-._~:?#\[\]@!$&'()*+,;=]*)*(\?(?!=)[a-zA-Z0-9&=;]*)?(\#[a-zA-Z0-9-]*)?$|^(https?):\/\/(localhost|\b(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b)(?::\d{1,5})?(?!\/\/)(?:\/[a-zA-Z0-9-._~:?#\[\]@!$&'()*+,;=]*)*(?!\/{2})(?:;[a-zA-Z0-9-._~:?#\[\]@!$&'()*+,;=]*)*(\?(?!=)[a-zA-Z0-9&=;]*)?(\#[a-zA-Z0-9-]*)?$/;
259
+ return this.validation("url", (value) => {
260
+ if (!regex.test(value)) {
261
+ return {
262
+ currentUrl: value
263
+ };
264
+ }
265
+ });
266
+ }
267
+ ip() {
268
+ const IPv4regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
269
+ const IPv6regex = /^(?:([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|:(:[0-9a-fA-F]{1,4}){1,7}|([0-9a-fA-F]{1,4}:){1,6}:([0-9a-fA-F]{1,4}:){1,6}[0-9a-fA-F]{1,4})$/;
270
+ return this.validation("ip", (value) => {
271
+ if (!(IPv4regex.test(value) || IPv6regex.test(value))) {
272
+ return {
273
+ currentIP: value
274
+ };
275
+ }
276
+ });
277
+ }
278
+ validation(name, validator) {
279
+ const instance = this.pipeValidation(name, validator);
280
+ return instance;
281
+ }
111
282
  }
112
283
  function string() {
113
284
  return new ArcString;
@@ -143,283 +314,571 @@ function customId(name, createFn) {
143
314
  return new ArcCustomId(name, createFn);
144
315
  }
145
316
 
146
- // context/query.ts
147
- class ArcQuery {
148
- lastResult;
149
- listener;
150
- }
317
+ // elements/object.ts
318
+ var objectValidator = typeValidatorBuilder("object");
151
319
 
152
- // collection/queries/abstract-collection-query.ts
153
- class ArcCollectionQuery extends ArcQuery {
154
- collection;
155
- bindedChangeHandler = this.changeHandler.bind(this);
156
- store;
157
- constructor(collection) {
158
- super();
159
- this.collection = collection;
160
- }
161
- async run(dataStorage, listener) {
162
- const store = dataStorage.getStore(this.collection.name);
163
- this.store = store;
164
- const result = await this.fetch(store);
165
- this.lastResult = result;
166
- if (listener)
167
- this.listener = listener;
168
- return result;
169
- }
170
- changeHandler(changes) {
171
- let resultChanged = false;
172
- for (const change of changes) {
173
- const response = this.onChange(change);
174
- if (response !== false) {
175
- this.lastResult = response;
176
- resultChanged = true;
320
+ class ArcObject extends ArcAbstract {
321
+ rawShape;
322
+ constructor(rawShape) {
323
+ super([
324
+ objectValidator,
325
+ {
326
+ name: "schema",
327
+ validator: (value) => {
328
+ const errors = Object.entries(this.rawShape).reduce((acc, [key, element]) => {
329
+ if (!element.validate) {
330
+ return acc;
331
+ }
332
+ acc[key] = element.validate(value[key]);
333
+ return acc;
334
+ }, {});
335
+ if (Object.values(errors).some((result) => !!result)) {
336
+ return errors;
337
+ }
338
+ return false;
339
+ }
177
340
  }
178
- }
179
- if (resultChanged)
180
- this.nextResult(this.lastResult);
181
- }
182
- unsubscribe() {
183
- this.store.unsubscribe(this.bindedChangeHandler);
341
+ ]);
342
+ this.rawShape = rawShape;
184
343
  }
185
- nextResult(result) {
186
- this.lastResult = result;
187
- this.listener?.(result);
344
+ parse(value) {
345
+ return Object.entries(this.rawShape).reduce((acc, [key, element]) => {
346
+ acc[key] = element.parse(value[key]);
347
+ return acc;
348
+ }, {});
188
349
  }
189
- }
190
-
191
- // collection/queries/abstract-many-items.ts
192
- class QueryCollectionResult {
193
- result;
194
- constructor(result) {
195
- this.result = result;
350
+ serialize(value) {
351
+ return Object.entries(value).reduce((acc, [key, value2]) => {
352
+ if (!this.rawShape[key]) {
353
+ acc[key] = value2;
354
+ } else {
355
+ acc[key] = this.rawShape[key].serialize(value2);
356
+ }
357
+ return acc;
358
+ }, {});
196
359
  }
197
- get(id2) {
198
- return id2 ? this.result.find((r) => r._id === id2) : undefined;
360
+ deserialize(value) {
361
+ return Object.fromEntries(Object.entries(this.rawShape).map(([key, element]) => [
362
+ key,
363
+ element.deserialize(value[key])
364
+ ]));
199
365
  }
200
- map(callbackfn) {
201
- return this.result.map(callbackfn);
366
+ deserializePath(path, value) {
367
+ if (path.length === 0) {
368
+ return this.deserialize(value);
369
+ }
370
+ const [key, ...restPath] = path;
371
+ const element = this.rawShape[key];
372
+ if (!element) {
373
+ console.warn(`No element found for key: ${key}`);
374
+ return value;
375
+ }
376
+ if (element instanceof ArcObject || element instanceof ArcArray) {
377
+ return element.deserializePath(restPath, value);
378
+ }
379
+ return element.deserialize(value);
202
380
  }
203
- toArray() {
204
- return this.result;
381
+ parsePartial(value) {
382
+ return Object.entries(value).reduce((acc, [key, value2]) => {
383
+ acc[key] = this.rawShape[key].parse(value2);
384
+ return acc;
385
+ }, {});
205
386
  }
206
- }
207
-
208
- class ArcManyItemsQuery extends ArcCollectionQuery {
209
- filterFn;
210
- sortFn;
211
- constructor(collection, filterFn, sortFn) {
212
- super(collection);
213
- this.filterFn = filterFn;
214
- this.sortFn = sortFn;
387
+ deserializePartial(value) {
388
+ return Object.entries(value).reduce((acc, [key, value2]) => {
389
+ acc[key] = this.rawShape[key].deserialize(value2);
390
+ return acc;
391
+ }, {});
215
392
  }
216
- onChange(change) {
217
- const lastResult = this.lastResult;
218
- const lastResultAsArray = lastResult?.toArray() || [];
219
- const index = lastResultAsArray.findIndex((e) => e._id === (change.type === "delete" ? change.id : change.id));
220
- const isInLastResult = index !== -1;
221
- const shouldBeInTheResult = change.type !== "delete" && this.checkItem(change.item);
222
- if (isInLastResult && shouldBeInTheResult)
223
- return this.createResult(lastResultAsArray.toSpliced(index, 1, change.item));
224
- else if (isInLastResult && (change.type === "delete" || !shouldBeInTheResult))
225
- return this.createResult(lastResultAsArray.toSpliced(index, 1));
226
- else if (!isInLastResult && shouldBeInTheResult)
227
- return this.createResult(lastResultAsArray.concat(change.item));
228
- return false;
393
+ serializePartial(value) {
394
+ return Object.entries(value).reduce((acc, [key, value2]) => {
395
+ acc[key] = this.rawShape[key].serialize(value2);
396
+ return acc;
397
+ }, {});
229
398
  }
230
- createResult(result) {
231
- if (this.sortFn)
232
- return new QueryCollectionResult(result.sort(this.sortFn));
233
- return new QueryCollectionResult(result);
399
+ pick(...keys) {
400
+ return new ArcObject(Object.fromEntries(keys.map((key) => [key, this.rawShape[key]])));
234
401
  }
235
- createFiltredResult(result) {
236
- if (this.filterFn)
237
- return this.createResult(result.filter(this.filterFn));
238
- return this.createResult(result);
402
+ omit(...keys) {
403
+ return new ArcObject(Object.fromEntries(Object.entries(this.rawShape).filter(([key]) => !keys.includes(key))));
239
404
  }
240
- checkItem(item) {
241
- if (this.filterFn)
242
- return this.filterFn(item);
243
- return true;
405
+ entries() {
406
+ return Object.entries(this.rawShape);
244
407
  }
245
408
  }
246
-
247
- // collection/queries/all-items.ts
248
- class ArcAllItemsQuery extends ArcManyItemsQuery {
249
- async fetch(store) {
250
- const results = await store.findAll(this.bindedChangeHandler);
251
- return this.createFiltredResult(results);
252
- }
409
+ function object(element) {
410
+ return new ArcObject(element);
253
411
  }
254
412
 
255
- // context/query-builders.ts
256
- class ArcQueryBuilder {
257
- }
413
+ // elements/array.ts
414
+ var arrayValidator = typeValidatorBuilder("array", Array.isArray);
258
415
 
259
- // collection/query-builders/abstract-many-items.ts
260
- function sortComparatorBuilder(comparator) {
261
- if (typeof comparator === "function") {
262
- return comparator;
263
- } else if (Array.isArray(comparator)) {
264
- return (a, b) => {
265
- for (const [key, order] of comparator) {
266
- if (a[key] < b[key])
267
- return order === "ASC" ? -1 : 1;
268
- if (a[key] > b[key])
269
- return order === "ASC" ? 1 : -1;
416
+ class ArcArray extends ArcAbstract {
417
+ parent;
418
+ constructor(parent) {
419
+ super([
420
+ arrayValidator,
421
+ {
422
+ name: "schema",
423
+ validator: (values) => {
424
+ const errors = values.reduce((acc, value, index) => {
425
+ const error = parent.validate(value);
426
+ if (error)
427
+ acc[index] = error;
428
+ return acc;
429
+ }, {});
430
+ if (Object.values(errors).some((result) => !!result)) {
431
+ return errors;
432
+ }
433
+ return false;
434
+ }
270
435
  }
271
- return 0;
272
- };
436
+ ]);
437
+ this.parent = parent;
273
438
  }
274
- throw new Error("Invalid comparator type");
275
- }
276
-
277
- class ArcManyItemsQueryBuilder extends ArcQueryBuilder {
278
- filterFn;
279
- sortFn;
280
- filter(callback) {
281
- this.filterFn = callback;
282
- return this;
439
+ minLength(min) {
440
+ return this.validation("minLength", (value) => {
441
+ if (value.length < min)
442
+ return {
443
+ currentLength: value.length,
444
+ minLength: min
445
+ };
446
+ });
283
447
  }
284
- sort(comparator) {
285
- this.sortFn = sortComparatorBuilder(comparator);
286
- return this;
448
+ maxLength(max) {
449
+ return this.validation("maxLength", (value) => {
450
+ if (value.length > max)
451
+ return {
452
+ currentLength: value.length,
453
+ maxLength: max
454
+ };
455
+ });
287
456
  }
288
- }
289
-
290
- // collection/query-builders/all-items.ts
291
- class ArcAllItemsQueryBuilder extends ArcManyItemsQueryBuilder {
292
- collection;
293
- constructor(collection) {
294
- super();
295
- this.collection = collection;
296
- if (collection.options.sort)
297
- this.sortFn = collection.options.sort;
457
+ length(number) {
458
+ return this.validation("length", (value) => {
459
+ if (value.length !== number) {
460
+ return {
461
+ currentLength: value.length,
462
+ length: number
463
+ };
464
+ }
465
+ });
298
466
  }
299
- toQuery() {
300
- return new ArcAllItemsQuery(this.collection, this.filterFn, this.sortFn);
467
+ nonEmpty() {
468
+ return this.validation("nonEmpty", (value) => {
469
+ if (value.length === 0)
470
+ return { msg: "array is empty" };
471
+ });
301
472
  }
302
- }
303
-
304
- // db/index-query.ts
305
- function indexQueryPredicate(item, query) {
306
- if (!("$gt" in query) && !("$gte" in query) && !("$lt" in query) && !("$lte" in query)) {
307
- return Object.entries(query).every(([key, value]) => item[key] === value);
308
- }
309
- if (query.$gt) {
310
- const isGreaterThan = Object.entries(query.$gt).every(([key, value]) => item[key] > value);
311
- if (!isGreaterThan)
312
- return false;
473
+ parse(value) {
474
+ return value.map((v) => this.parent.parse(v));
313
475
  }
314
- if (query.$gte) {
315
- const isGreaterThanOrEqual = Object.entries(query.$gte).every(([key, value]) => item[key] >= value);
316
- if (!isGreaterThanOrEqual)
317
- return false;
476
+ serialize(value) {
477
+ return value.map((v) => this.parent.serialize(v));
318
478
  }
319
- if (query.$lt) {
320
- const isLessThan = Object.entries(query.$lt).every(([key, value]) => item[key] < value);
321
- if (!isLessThan)
322
- return false;
479
+ deserialize(value) {
480
+ if (!Array.isArray(value))
481
+ return [];
482
+ return value.map((v) => this.parent.deserialize(v));
323
483
  }
324
- if (query.$lte) {
325
- const isLessThanOrEqual = Object.entries(query.$lte).every(([key, value]) => item[key] <= value);
326
- if (!isLessThanOrEqual)
327
- return false;
484
+ deserializePath(path, value) {
485
+ if (path.length === 0) {
486
+ return this.deserialize(value);
487
+ }
488
+ if (this.parent instanceof ArcObject || this.parent instanceof ArcArray) {
489
+ return this.parent.deserializePath(path, value);
490
+ }
491
+ return this.parent.deserialize(value);
328
492
  }
329
- return true;
493
+ validation(name, validator) {
494
+ const instance = this.pipeValidation(name, validator);
495
+ return instance;
496
+ }
497
+ }
498
+ function array(element) {
499
+ return new ArcArray(element);
330
500
  }
501
+ // elements/boolean.ts
502
+ class ArcBoolean extends ArcPrimitive {
503
+ }
504
+ function boolean() {
505
+ return new ArcBoolean;
506
+ }
507
+ // elements/date.ts
508
+ var dateValidator = typeValidatorBuilder("Date", (value) => value instanceof Date);
331
509
 
332
- // collection/queries/indexed.ts
333
- class ArcIndexedItemsQuery extends ArcManyItemsQuery {
334
- index;
335
- data;
336
- filterFn;
337
- sortFn;
338
- constructor(collection, index, data, filterFn, sortFn) {
339
- super(collection, filterFn, sortFn);
340
- this.index = index;
341
- this.data = data;
342
- this.filterFn = filterFn;
343
- this.sortFn = sortFn;
510
+ class ArcDate extends ArcAbstract {
511
+ constructor() {
512
+ super([dateValidator]);
344
513
  }
345
- checkItem(item) {
346
- if (!super.checkItem(item))
347
- return false;
348
- return indexQueryPredicate(item, this.data);
514
+ parse(value) {
515
+ return new Date(value);
349
516
  }
350
- async fetch(store) {
351
- const results = await store.findByIndex(this.index, this.data, this.bindedChangeHandler);
352
- return this.createFiltredResult(results);
517
+ serialize(value) {
518
+ return value.getTime();
519
+ }
520
+ deserialize(value) {
521
+ return new Date(value);
522
+ }
523
+ after(after) {
524
+ return this.validation("after", (value) => {
525
+ if (value <= after)
526
+ return { current: value, after };
527
+ });
528
+ }
529
+ before(before) {
530
+ return this.validation("before", (value) => {
531
+ if (value >= before)
532
+ return { current: value, before };
533
+ });
534
+ }
535
+ validation(name, validator) {
536
+ const instance = this.pipeValidation(name, validator);
537
+ return instance;
353
538
  }
354
539
  }
540
+ function date() {
541
+ return new ArcDate;
542
+ }
543
+ // elements/number.ts
544
+ var numberValidator = typeValidatorBuilder("number");
355
545
 
356
- // collection/query-builders/indexed.ts
357
- class ArcIndexedItemsQueryBuilder extends ArcManyItemsQueryBuilder {
358
- collection;
359
- index;
360
- data;
361
- constructor(collection, index, data) {
546
+ class ArcNumber extends ArcPrimitive {
547
+ constructor() {
548
+ super([numberValidator]);
549
+ }
550
+ min(min) {
551
+ return this.validation("min", (value) => {
552
+ if (value < min)
553
+ return { current: value, min };
554
+ });
555
+ }
556
+ max(max) {
557
+ return this.validation("max", (value) => {
558
+ if (value > max)
559
+ return { current: value, max };
560
+ });
561
+ }
562
+ validation(name, validator) {
563
+ const instance = this.pipeValidation(name, validator);
564
+ return instance;
565
+ }
566
+ }
567
+ function number() {
568
+ return new ArcNumber;
569
+ }
570
+ // elements/record.ts
571
+ class ArcRecord extends ArcAbstract {
572
+ key;
573
+ element;
574
+ constructor(key, element) {
575
+ super([
576
+ {
577
+ name: "schema",
578
+ validator: (value) => {
579
+ const errors = Object.entries(value).reduce((acc, [key2, element2]) => {
580
+ const error = this.element.validate(element2);
581
+ if (error) {
582
+ acc[key2] = error;
583
+ }
584
+ return acc;
585
+ }, {});
586
+ if (Object.entries(errors).some(([key2, element2]) => !!(key2 || element2))) {
587
+ return errors;
588
+ }
589
+ return false;
590
+ }
591
+ }
592
+ ]);
593
+ this.key = key;
594
+ this.element = element;
595
+ }
596
+ parse(value) {
597
+ if (!value)
598
+ return {};
599
+ return Object.entries(value).reduce((acc, [key, recordValue]) => {
600
+ acc[key] = this.element.parse(recordValue);
601
+ return acc;
602
+ }, {});
603
+ }
604
+ serialize(value) {
605
+ if (!value)
606
+ return {};
607
+ return Object.entries(value).reduce((acc, [key, recordValue]) => {
608
+ acc[key] = this.element.serialize(recordValue);
609
+ return acc;
610
+ }, {});
611
+ }
612
+ deserialize(value) {
613
+ if (!value)
614
+ return {};
615
+ return Object.entries(value).reduce((acc, [key, recordValue]) => {
616
+ acc[key] = this.element.deserialize(recordValue);
617
+ return acc;
618
+ }, {});
619
+ }
620
+ }
621
+ function record(key, element) {
622
+ return new ArcRecord(key, element);
623
+ }
624
+ // elements/string-enum.ts
625
+ class ArcStringEnum extends ArcAbstract {
626
+ values;
627
+ constructor(values) {
628
+ super([
629
+ {
630
+ name: "schema",
631
+ validator: (value) => {
632
+ if (this.values.includes(value))
633
+ return false;
634
+ return { expect: values, current: value };
635
+ }
636
+ }
637
+ ]);
638
+ this.values = values;
639
+ }
640
+ parse(value) {
641
+ return value;
642
+ }
643
+ serialize(value) {
644
+ return value;
645
+ }
646
+ deserialize(value) {
647
+ return value;
648
+ }
649
+ getEnumerators() {
650
+ return this.values;
651
+ }
652
+ }
653
+ function stringEnum(...values) {
654
+ return new ArcStringEnum(values);
655
+ }
656
+ // utils/arcObjectToStoreSchema.ts
657
+ function getSQLiteType(element) {
658
+ if (element instanceof ArcDate) {
659
+ return "TEXT";
660
+ }
661
+ if (element instanceof ArcArray || element instanceof ArcObject) {
662
+ return "TEXT";
663
+ }
664
+ if (element instanceof ArcBoolean) {
665
+ return "INTEGER";
666
+ }
667
+ if (element instanceof ArcNumber) {
668
+ return "NUMBER";
669
+ }
670
+ return "TEXT";
671
+ }
672
+ function arcObjectToStoreSchema(tableName, schema) {
673
+ const columns = schema.entries().map(([name, element]) => ({
674
+ name,
675
+ type: getSQLiteType(element),
676
+ isOptional: element instanceof ArcOptional
677
+ }));
678
+ columns.unshift({
679
+ name: "_id",
680
+ type: "TEXT",
681
+ isOptional: false
682
+ }, {
683
+ name: "deleted",
684
+ type: "INTEGER",
685
+ isOptional: false,
686
+ default: 0
687
+ }, {
688
+ name: "lastUpdate",
689
+ type: "TEXT",
690
+ isOptional: false
691
+ });
692
+ return {
693
+ tables: [
694
+ {
695
+ name: tableName,
696
+ columns,
697
+ primaryKey: "_id"
698
+ }
699
+ ]
700
+ };
701
+ }
702
+
703
+ // context/query.ts
704
+ class ArcQuery {
705
+ lastResult;
706
+ listeners = new Set;
707
+ subscribe(listener) {
708
+ this.listeners.add(listener);
709
+ }
710
+ unsubscribe(listener) {
711
+ this.listeners.delete(listener);
712
+ }
713
+ nextResult(result) {
714
+ this.lastResult = result;
715
+ this.listeners.forEach((listener) => listener(result));
716
+ }
717
+ }
718
+
719
+ // context/serializable-query.ts
720
+ class ArcSerializableQuery extends ArcQuery {
721
+ params;
722
+ static key;
723
+ constructor(params) {
362
724
  super();
725
+ this.params = params;
726
+ }
727
+ serialize() {
728
+ return {
729
+ key: this.constructor.key,
730
+ params: this.params
731
+ };
732
+ }
733
+ }
734
+
735
+ // collection/queries/abstract-collection-query.ts
736
+ class ArcCollectionQuery extends ArcSerializableQuery {
737
+ collection;
738
+ bindedChangeHandler = this.changeHandler.bind(this);
739
+ store;
740
+ constructor(collection, params) {
741
+ super(params);
363
742
  this.collection = collection;
364
- this.index = index;
365
- this.data = data;
366
- if (collection.options.sort)
367
- this.sortFn = collection.options.sort;
368
743
  }
369
- toQuery() {
370
- return new ArcIndexedItemsQuery(this.collection, this.index, this.data, this.filterFn, this.sortFn);
744
+ async run(dataStorage) {
745
+ const store = dataStorage.getStore(this.collection.name);
746
+ this.store = store;
747
+ const result = await this.fetch(store);
748
+ this.lastResult = result;
749
+ return result;
750
+ }
751
+ changeHandler(changes) {
752
+ let resultChanged = false;
753
+ for (const change of changes) {
754
+ const response = this.onChange(change);
755
+ if (response !== false) {
756
+ this.lastResult = response;
757
+ resultChanged = true;
758
+ }
759
+ }
760
+ if (resultChanged)
761
+ this.nextResult(this.lastResult);
762
+ }
763
+ }
764
+
765
+ // collection/queries/find.ts
766
+ class QueryCollectionResult {
767
+ result;
768
+ constructor(result) {
769
+ this.result = result;
770
+ }
771
+ get(id3) {
772
+ return id3 ? this.result.find((r) => r._id === id3) : undefined;
773
+ }
774
+ map(callbackfn) {
775
+ return this.result.map(callbackfn);
776
+ }
777
+ toArray() {
778
+ return this.result;
371
779
  }
372
780
  }
373
781
 
374
- // collection/queries/one-item.ts
375
- class ArcOneItemQuery extends ArcCollectionQuery {
376
- id2;
377
- constructor(collection, id2) {
378
- super(collection);
379
- this.id = id2;
782
+ class ArcFindQuery extends ArcCollectionQuery {
783
+ params;
784
+ constructor(collection, params) {
785
+ super(collection, params);
786
+ this.params = params;
787
+ }
788
+ async fetch(store) {
789
+ const results = await store.find(this.params, this.bindedChangeHandler);
790
+ return this.createResult(results);
791
+ }
792
+ checkItem(item) {
793
+ if (!this.params.where)
794
+ return true;
795
+ return Object.entries(this.params.where).every(([key, condition]) => {
796
+ const value = item[key];
797
+ if (typeof condition !== "object" || condition === null) {
798
+ return value === condition;
799
+ }
800
+ return Object.entries(condition).every(([operator, operatorValue]) => {
801
+ switch (operator) {
802
+ case "$eq":
803
+ return value === operatorValue;
804
+ case "$ne":
805
+ return value !== operatorValue;
806
+ case "$gt":
807
+ return typeof value === "number" && typeof operatorValue === "number" && value > operatorValue;
808
+ case "$gte":
809
+ return typeof value === "number" && typeof operatorValue === "number" && value >= operatorValue;
810
+ case "$lt":
811
+ return typeof value === "number" && typeof operatorValue === "number" && value < operatorValue;
812
+ case "$lte":
813
+ return typeof value === "number" && typeof operatorValue === "number" && value <= operatorValue;
814
+ case "$in":
815
+ return Array.isArray(operatorValue) && operatorValue.includes(value);
816
+ case "$nin":
817
+ return Array.isArray(operatorValue) && !operatorValue.includes(value);
818
+ case "$exists":
819
+ return typeof operatorValue === "boolean" ? operatorValue ? value !== undefined : value === undefined : true;
820
+ default:
821
+ return true;
822
+ }
823
+ });
824
+ });
380
825
  }
381
826
  onChange(change) {
382
- if (change.id !== this.id)
383
- return false;
384
- if (change.type === "delete")
385
- return null;
386
- if (change.type === "set")
387
- return change.item;
827
+ const lastResult = this.lastResult;
828
+ const lastResultAsArray = lastResult?.toArray() || [];
829
+ const index = lastResultAsArray.findIndex((e) => e._id === (change.type === "delete" ? change.id : change.id));
830
+ const isInLastResult = index !== -1;
831
+ const shouldBeInTheResult = change.type !== "delete" && this.checkItem(change.item);
832
+ if (isInLastResult && shouldBeInTheResult)
833
+ return this.createResult(lastResultAsArray.toSpliced(index, 1, change.item));
834
+ else if (isInLastResult && (change.type === "delete" || !shouldBeInTheResult))
835
+ return this.createResult(lastResultAsArray.toSpliced(index, 1));
836
+ else if (!isInLastResult && shouldBeInTheResult)
837
+ return this.createResult(lastResultAsArray.concat(change.item));
388
838
  return false;
389
839
  }
390
- async fetch(store) {
391
- const result = await store.findById(this.id, this.bindedChangeHandler);
392
- return result;
840
+ createResult(result) {
841
+ return new QueryCollectionResult(result);
393
842
  }
394
843
  }
395
844
 
396
- // collection/query-builders/one-item.ts
397
- class ArcOneItemQueryBuilder extends ArcQueryBuilder {
845
+ // collection/query-builders/find.ts
846
+ class ArcFindQueryBuilder {
398
847
  collection;
399
- id2;
400
- constructor(collection, id2) {
401
- super();
848
+ queryContext;
849
+ options;
850
+ constructor(collection, queryContext, options) {
402
851
  this.collection = collection;
403
- this.id = id2;
852
+ this.queryContext = queryContext;
853
+ this.options = options;
404
854
  }
405
855
  toQuery() {
406
- return new ArcOneItemQuery(this.collection, this.id);
856
+ return this.queryContext.cacheQuery(ArcFindQuery, [
857
+ this.collection,
858
+ this.options
859
+ ]);
860
+ }
861
+ run() {
862
+ return this.queryContext.runQuery(this.toQuery());
407
863
  }
408
864
  }
409
865
 
410
866
  // collection/collection.ts
411
- class ArcCollection extends ArcContextElement {
867
+ class ArcCollection extends ArcContextElementWithStore {
412
868
  name;
413
- id2;
869
+ id;
414
870
  schema;
415
871
  options;
416
- constructor(name, id2, schema, options) {
872
+ constructor(name, id3, schema, options) {
417
873
  super();
418
874
  this.name = name;
419
- this.id = id2;
875
+ this.id = id3;
420
876
  this.schema = schema;
421
877
  this.options = options;
422
878
  }
879
+ storeSchema() {
880
+ return arcObjectToStoreSchema(this.name, this.schema);
881
+ }
423
882
  serialize(data) {
424
883
  return {
425
884
  _id: this.id.serialize(data._id),
@@ -432,22 +891,22 @@ class ArcCollection extends ArcContextElement {
432
891
  ...this.schema.deserialize(data)
433
892
  };
434
893
  }
435
- queryBuilder() {
894
+ queryBuilder = (context) => {
436
895
  return {
437
- all: () => new ArcAllItemsQueryBuilder(this),
438
- one: (id2) => new ArcOneItemQueryBuilder(this, id2)
896
+ find: (options) => new ArcFindQueryBuilder(this, context, options || {})
439
897
  };
440
- }
441
- commandContext(dataStorage, publishEvent) {
898
+ };
899
+ commandContext = (dataStorage, publishEvent) => {
442
900
  const store = dataStorage.getStore(this.name);
443
901
  return {
444
902
  add: async (data) => {
445
903
  if (this.id instanceof ArcCustomId)
446
904
  throw new Error("Collection with custom id not support 'add' method");
447
- const id2 = this.id.generate();
905
+ const id3 = this.id.generate();
448
906
  const parsed = this.schema.parse(data);
449
907
  const body = {
450
- _id: id2,
908
+ _id: id3,
909
+ lastUpdate: new Date().toISOString(),
451
910
  ...parsed
452
911
  };
453
912
  await store.set(body);
@@ -455,16 +914,16 @@ class ArcCollection extends ArcContextElement {
455
914
  type: "set",
456
915
  to: body
457
916
  });
458
- return { id: id2 };
917
+ return { id: id3 };
459
918
  },
460
- remove: async (id2) => {
461
- await store.remove(id2);
919
+ remove: async (id3) => {
920
+ await store.remove(id3);
462
921
  return { success: true };
463
922
  },
464
- set: async (id2, data) => {
923
+ set: async (id3, data) => {
465
924
  const parsed = this.schema.parse(data);
466
925
  const body = {
467
- _id: id2,
926
+ _id: id3,
468
927
  ...parsed
469
928
  };
470
929
  await store.set(body);
@@ -474,15 +933,19 @@ class ArcCollection extends ArcContextElement {
474
933
  });
475
934
  return { success: true };
476
935
  },
477
- all: async () => {
478
- return store.findAll();
936
+ find: async (options) => {
937
+ return store.find(options);
479
938
  },
480
- one: async (id2) => {
481
- return store.findById(id2);
939
+ findOne: async (where) => {
940
+ const result = await store.find({
941
+ where,
942
+ limit: 1
943
+ });
944
+ return result[0];
482
945
  },
483
- modify: async (id2, data) => {
946
+ modify: async (id3, data) => {
484
947
  const deserialized = this.schema.serializePartial(data);
485
- const { from, to } = await store.modify(id2, deserialized);
948
+ const { from, to } = await store.modify(id3, deserialized);
486
949
  await publishEvent({
487
950
  type: "modify",
488
951
  changes: deserialized,
@@ -490,8 +953,8 @@ class ArcCollection extends ArcContextElement {
490
953
  to
491
954
  });
492
955
  },
493
- edit: async (id2, editCallback) => {
494
- const { from, to } = await store.mutate(id2, editCallback);
956
+ edit: async (id3, editCallback) => {
957
+ const { from, to } = await store.mutate(id3, editCallback);
495
958
  await publishEvent({
496
959
  type: "mutate",
497
960
  from,
@@ -499,129 +962,396 @@ class ArcCollection extends ArcContextElement {
499
962
  });
500
963
  }
501
964
  };
502
- }
503
- indexBy(indexes) {
504
- return new ArcIndexedCollection(this.name, this.id, this.schema, this.options, indexes);
505
- }
965
+ };
506
966
  }
507
-
508
- class ArcIndexedCollection extends ArcCollection {
509
- indexes;
510
- constructor(name, id2, schema, options, indexes) {
511
- super(name, id2, schema, options);
512
- this.indexes = indexes;
513
- }
514
- commandContext(dataStorage, publishEvent) {
515
- const superContext = super.commandContext(dataStorage, publishEvent);
516
- return new Proxy(superContext, {
517
- get: (target, name) => {
518
- if (name in target) {
519
- return target[name];
520
- }
521
- if (!(name in this.indexes)) {
522
- throw new Error(`Index "${name}" not found in collection "${this.name}"`);
523
- }
524
- return (data) => dataStorage.getStore(this.name).findByIndex(name, data);
525
- }
526
- });
967
+ function collection(name, id3, schema, options = {}) {
968
+ return new ArcCollection(name, id3, schema, options);
969
+ }
970
+ // command/command.ts
971
+ class ArcCommand extends ArcContextElement {
972
+ name;
973
+ _description;
974
+ _params;
975
+ _result;
976
+ _elements;
977
+ _handler;
978
+ constructor(name) {
979
+ super();
980
+ this.name = name;
527
981
  }
528
- queryBuilder() {
529
- const superQueryBuilder = super.queryBuilder();
530
- return new Proxy({}, {
531
- get: (target, name) => {
532
- if (name in superQueryBuilder)
533
- return superQueryBuilder[name];
534
- if (!(name in this.indexes)) {
535
- throw new Error(`Index "${name}" not found in collection "${this.name}"`);
536
- }
537
- return (data) => new ArcIndexedItemsQueryBuilder(this, name, data);
538
- }
539
- });
982
+ use(elements) {
983
+ const clone = this.clone();
984
+ clone._elements = elements;
985
+ return clone;
986
+ }
987
+ description(description) {
988
+ const clone = this.clone();
989
+ clone._description = description;
990
+ return clone;
991
+ }
992
+ withParams(schema) {
993
+ const clone = this.clone();
994
+ clone._params = schema instanceof ArcObject ? schema : object(schema);
995
+ return clone;
996
+ }
997
+ withResult(schema) {
998
+ const clone = this.clone();
999
+ clone._result = object(schema);
1000
+ return clone;
1001
+ }
1002
+ handle(handler) {
1003
+ const clone = this.clone();
1004
+ clone._handler = handler;
1005
+ return clone;
1006
+ }
1007
+ commandClient = (ctx) => {
1008
+ return Object.assign(async (params) => {
1009
+ if (this._handler)
1010
+ return this._handler?.(ctx, params);
1011
+ }, { params: this._params });
1012
+ };
1013
+ clone() {
1014
+ const clone = new ArcCommand(this.name);
1015
+ clone._description = this._description;
1016
+ clone._params = this._params;
1017
+ clone._result = this._result;
1018
+ clone._handler = this._handler;
1019
+ clone._elements = this._elements;
1020
+ return clone;
540
1021
  }
541
1022
  }
542
- function collection(name, id2, schema, options = {}) {
543
- return new ArcCollection(name, id2, schema, options);
1023
+ function command(name) {
1024
+ return new ArcCommand(name);
544
1025
  }
545
1026
  // context/context.ts
546
1027
  class ArcContext {
547
- version;
548
1028
  elements;
549
- commands;
550
- listeners;
551
- elementsMap;
552
- constructor(version, elements, commands, listeners) {
553
- this.version = version;
1029
+ eventListeners;
1030
+ constructor(elements) {
554
1031
  this.elements = elements;
555
- this.commands = commands;
556
- this.listeners = listeners;
557
- this.elementsMap = Object.fromEntries(elements.map((element) => [element.name, element]));
1032
+ this.eventListeners = new Map;
1033
+ elements.forEach((element) => {
1034
+ if (element.observer) {
1035
+ const handlers = element.observer();
1036
+ Object.entries(handlers).forEach(([alias, handler]) => {
1037
+ const listeners = this.eventListeners.get(alias) || [];
1038
+ listeners.push(handler);
1039
+ this.eventListeners.set(alias, listeners);
1040
+ });
1041
+ }
1042
+ });
1043
+ }
1044
+ pipe(newElements) {
1045
+ return new ArcContext([
1046
+ ...this.elements,
1047
+ ...newElements.filter(Boolean)
1048
+ ]);
558
1049
  }
559
- queryBuilder() {
1050
+ queryBuilder(queryContext) {
560
1051
  return new Proxy({}, {
561
1052
  get: (target, name) => {
562
- const element = this.elementsMap[name];
1053
+ const element = this.elements.find((element2) => element2.name === name);
563
1054
  if (!element) {
564
- throw new Error(`Collection "${name}" not found`);
1055
+ throw new Error(`Element "${String(name)}" not found`);
565
1056
  }
566
- return element.queryBuilder();
1057
+ if (!element.queryBuilder) {
1058
+ throw new Error(`Element "${String(name)}" does not have a query builder`);
1059
+ }
1060
+ return element.queryBuilder(queryContext);
567
1061
  }
568
1062
  });
569
1063
  }
570
- commandContext(client, dataStorage, publishEvent) {
1064
+ commandContext(client, dataStorage) {
571
1065
  return new Proxy({}, {
572
1066
  get: (target, name) => {
573
1067
  if (name === "$client") {
574
1068
  return client;
575
1069
  }
576
- const element = this.elementsMap[name];
577
- return element.commandContext(dataStorage, (event) => publishEvent({
578
- element: name,
579
- ...event
580
- }));
1070
+ const element = this.elements.find((element2) => element2.name === name);
1071
+ if (!element) {
1072
+ throw new Error(`Element "${String(name)}" not found`);
1073
+ }
1074
+ if (!element.commandContext) {
1075
+ throw new Error(`Element "${String(name)}" does not have a command context`);
1076
+ }
1077
+ return element.commandContext(dataStorage, async (event) => {
1078
+ const listeners = this.eventListeners.get(event.type) || [];
1079
+ await Promise.all(listeners.map((listener) => listener(event, dataStorage)));
1080
+ });
581
1081
  }
582
1082
  });
583
1083
  }
584
- commandsClient(client, dataStorage, catchErrorCallback) {
1084
+ commandsClient(client, queryContext, dataStorage, catchErrorCallback) {
585
1085
  return new Proxy({}, {
586
1086
  get: (_, name) => {
587
- if (name in this.commands) {
588
- return async (...args) => {
589
- const forkedDataStorage = dataStorage.fork();
590
- const commandContext = this.commandContext(client, forkedDataStorage, async (data) => {
591
- if (!this.listeners)
592
- return;
593
- await Promise.all(this.listeners?.map((listener) => listener(data, commandContext)));
594
- });
595
- try {
596
- const result = await this.commands[name](commandContext, ...args);
597
- await forkedDataStorage.merge();
598
- return result;
599
- } catch (error) {
600
- console.log("error", error);
601
- catchErrorCallback(error);
602
- return error;
603
- }
604
- };
1087
+ const element = this.elements.find((element2) => element2.name === name);
1088
+ if (!element) {
1089
+ throw new Error(`Element "${String(name)}" not found`);
605
1090
  }
606
- console.warn(`Command '${name}' not found in the context.`);
607
- return;
1091
+ if (!element.commandClient) {
1092
+ throw new Error(`Element "${String(name)}" does not have a command client`);
1093
+ }
1094
+ return async (arg) => {
1095
+ const forkedDataStorage = dataStorage.fork();
1096
+ const commandContext = this.commandContext(client, forkedDataStorage);
1097
+ try {
1098
+ const result = await element.commandClient(commandContext)(arg);
1099
+ await forkedDataStorage.merge();
1100
+ return result;
1101
+ } catch (error) {
1102
+ console.log("error", error);
1103
+ catchErrorCallback(error);
1104
+ return error;
1105
+ }
1106
+ };
608
1107
  }
609
1108
  });
610
1109
  }
611
1110
  }
612
- function context(version, elements, commands, listeners) {
613
- return new ArcContext(version, elements, commands, listeners);
1111
+ async function context(elementsPromise) {
1112
+ const elements = await Promise.all(elementsPromise.map(async (element) => {
1113
+ if (element instanceof Promise) {
1114
+ return (await element).default;
1115
+ }
1116
+ return element;
1117
+ })).then((elements2) => elements2.filter(Boolean));
1118
+ return new ArcContext(elements);
1119
+ }
1120
+ // context/event.ts
1121
+ var eventValidator = typeValidatorBuilder("object");
1122
+ var eventStoreSchema = {
1123
+ tables: [
1124
+ {
1125
+ name: "events",
1126
+ primaryKey: "id",
1127
+ columns: [
1128
+ {
1129
+ name: "id",
1130
+ type: "string"
1131
+ },
1132
+ {
1133
+ name: "type",
1134
+ type: "string"
1135
+ },
1136
+ {
1137
+ name: "payload",
1138
+ type: "object"
1139
+ },
1140
+ {
1141
+ name: "createdAt",
1142
+ type: "datetime"
1143
+ }
1144
+ ]
1145
+ }
1146
+ ]
1147
+ };
1148
+ var eventId = id("event");
1149
+
1150
+ class ArcEvent extends ArcContextElementWithStore {
1151
+ name;
1152
+ payload;
1153
+ storeSchema = () => eventStoreSchema;
1154
+ constructor(name, payload) {
1155
+ super();
1156
+ this.name = name;
1157
+ this.payload = payload;
1158
+ }
1159
+ commandContext = (dataStorage, publishEvent) => {
1160
+ return {
1161
+ emit: async (payload) => {
1162
+ const event = {
1163
+ id: eventId.generate(),
1164
+ type: this.name,
1165
+ payload,
1166
+ createdAt: new Date().toISOString()
1167
+ };
1168
+ await dataStorage.getStore("events").set(event);
1169
+ await publishEvent(event);
1170
+ }
1171
+ };
1172
+ };
1173
+ }
1174
+ function event(name, payload) {
1175
+ return new ArcEvent(name, payload ? new ArcObject(payload) : undefined);
614
1176
  }
615
- // data-storage/data-storage.abstract.ts
616
- class DataStorage {
617
- async commitChanges(changes) {
618
- await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
1177
+ // context/query-builder-context.ts
1178
+ class QueryBuilderContext {
1179
+ queryCache;
1180
+ dataStorage;
1181
+ usedQueries = new Set;
1182
+ constructor(queryCache, dataStorage) {
1183
+ this.queryCache = queryCache;
1184
+ this.dataStorage = dataStorage;
1185
+ }
1186
+ cacheQuery(QueryConstructor, args) {
1187
+ return new QueryConstructor(...args);
1188
+ }
1189
+ runQuery(query) {
1190
+ this.usedQueries.add(query);
1191
+ return query.run(this.dataStorage);
1192
+ }
1193
+ getUsedQueries() {
1194
+ const queries = Array.from(this.usedQueries);
1195
+ this.usedQueries.clear();
1196
+ return queries;
619
1197
  }
620
1198
  }
1199
+ // context/query-builders.ts
1200
+ class ArcQueryBuilder {
1201
+ queryContext;
1202
+ constructor(queryContext) {
1203
+ this.queryContext = queryContext;
1204
+ }
1205
+ run() {
1206
+ const query = this.toQuery();
1207
+ return this.queryContext.runQuery(query);
1208
+ }
1209
+ }
1210
+ // utils/murmur-hash.ts
1211
+ function murmurHash(key, seed = 0) {
1212
+ var remainder, bytes, h1, h1b, c1, c1b, c2, c2b, k1, i;
1213
+ remainder = key.length & 3;
1214
+ bytes = key.length - remainder;
1215
+ h1 = seed;
1216
+ c1 = 3432918353;
1217
+ c2 = 461845907;
1218
+ i = 0;
1219
+ while (i < bytes) {
1220
+ k1 = key.charCodeAt(i) & 255 | (key.charCodeAt(++i) & 255) << 8 | (key.charCodeAt(++i) & 255) << 16 | (key.charCodeAt(++i) & 255) << 24;
1221
+ ++i;
1222
+ k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
1223
+ k1 = k1 << 15 | k1 >>> 17;
1224
+ k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
1225
+ h1 ^= k1;
1226
+ h1 = h1 << 13 | h1 >>> 19;
1227
+ h1b = (h1 & 65535) * 5 + (((h1 >>> 16) * 5 & 65535) << 16) & 4294967295;
1228
+ h1 = (h1b & 65535) + 27492 + (((h1b >>> 16) + 58964 & 65535) << 16);
1229
+ }
1230
+ k1 = 0;
1231
+ switch (remainder) {
1232
+ case 3:
1233
+ k1 ^= (key.charCodeAt(i + 2) & 255) << 16;
1234
+ case 2:
1235
+ k1 ^= (key.charCodeAt(i + 1) & 255) << 8;
1236
+ case 1:
1237
+ k1 ^= key.charCodeAt(i) & 255;
1238
+ k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
1239
+ k1 = k1 << 15 | k1 >>> 17;
1240
+ k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
1241
+ h1 ^= k1;
1242
+ }
1243
+ h1 ^= key.length;
1244
+ h1 ^= h1 >>> 16;
1245
+ h1 = (h1 & 65535) * 2246822507 + (((h1 >>> 16) * 2246822507 & 65535) << 16) & 4294967295;
1246
+ h1 ^= h1 >>> 13;
1247
+ h1 = (h1 & 65535) * 3266489909 + (((h1 >>> 16) * 3266489909 & 65535) << 16) & 4294967295;
1248
+ h1 ^= h1 >>> 16;
1249
+ return h1 >>> 0;
1250
+ }
1251
+
1252
+ // context/query-cache.ts
1253
+ class QueryCache {
1254
+ cache = new Map;
1255
+ getIndexHash(value) {
1256
+ if (typeof value === "number" || typeof value === "string" || typeof value === "function" || value === null || value === undefined) {
1257
+ return value;
1258
+ }
1259
+ return murmurHash(value);
1260
+ }
1261
+ set(index, query) {
1262
+ let current = this.cache;
1263
+ for (let i = 0;i < index.length - 1; i++) {
1264
+ const hashedIndex = this.getIndexHash(index[i]);
1265
+ if (!current.has(hashedIndex)) {
1266
+ current.set(hashedIndex, new Map);
1267
+ }
1268
+ current = current.get(hashedIndex);
1269
+ }
1270
+ const lastHashedIndex = this.getIndexHash(index[index.length - 1]);
1271
+ current.set(lastHashedIndex, query);
1272
+ }
1273
+ get(index) {
1274
+ let current = this.cache;
1275
+ for (let i = 0;i < index.length - 1; i++) {
1276
+ const hashedIndex = this.getIndexHash(index[i]);
1277
+ if (!current.has(hashedIndex)) {
1278
+ return;
1279
+ }
1280
+ current = current.get(hashedIndex);
1281
+ }
1282
+ const lastHashedIndex = this.getIndexHash(index[index.length - 1]);
1283
+ return current.get(lastHashedIndex);
1284
+ }
1285
+ debug() {
1286
+ return this.cache;
1287
+ }
1288
+ }
1289
+ // context/reactive-query.ts
1290
+ class ReactiveQuery extends ArcQuery {
1291
+ queryContext;
1292
+ queryBuilder;
1293
+ fn;
1294
+ queries = [];
1295
+ constructor(queryContext, queryBuilder, fn) {
1296
+ super();
1297
+ this.queryContext = queryContext;
1298
+ this.queryBuilder = queryBuilder;
1299
+ this.fn = fn;
1300
+ }
1301
+ run() {
1302
+ const promise = new Promise(async (resolve) => {
1303
+ const value = await this.runQuery();
1304
+ resolve(value);
1305
+ });
1306
+ return promise;
1307
+ }
1308
+ onChangeHandler = this.onChange.bind(this);
1309
+ async onChange() {
1310
+ const value = await this.runQuery();
1311
+ await this.nextResult(value);
1312
+ }
1313
+ async runQuery() {
1314
+ const value = await this.fn(this.queryBuilder);
1315
+ const queries = this.queryContext.getUsedQueries();
1316
+ this.queries.forEach((query) => {
1317
+ if (!queries.includes(query)) {
1318
+ query.unsubscribe(this.onChangeHandler);
1319
+ }
1320
+ });
1321
+ queries.forEach((query) => {
1322
+ if (!this.queries.includes(query)) {
1323
+ query.subscribe(this.onChangeHandler);
1324
+ }
1325
+ });
1326
+ this.queries = queries;
1327
+ return value;
1328
+ }
1329
+ }
1330
+
1331
+ class ReactiveQueryBuilder {
1332
+ queryBuilder;
1333
+ fn;
1334
+ constructor(queryBuilder, fn) {
1335
+ this.queryBuilder = queryBuilder;
1336
+ this.fn = fn;
1337
+ }
1338
+ toQuery(context2) {
1339
+ return new ReactiveQuery(context2, this.queryBuilder, this.fn);
1340
+ }
1341
+ }
1342
+ function reactive(fn) {
1343
+ return (context2) => new ReactiveQueryBuilder(context2, fn);
1344
+ }
1345
+ // data-storage/data-storage.abstract.ts
1346
+ class DataStorage {
1347
+ async commitChanges(changes) {
1348
+ await Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
1349
+ }
1350
+ }
1351
+
1352
+ // data-storage/store-state-fork.ts
1353
+ import { apply } from "mutative";
621
1354
 
622
- // data-storage/store-state-fork.ts
623
- import { apply } from "mutative";
624
-
625
1355
  // data-storage/deep-merge.ts
626
1356
  function deepMerge(target, source) {
627
1357
  const output = { ...target };
@@ -664,35 +1394,39 @@ class StoreState {
664
1394
  };
665
1395
  await this.applyChanges([change]);
666
1396
  }
667
- async remove(id2) {
1397
+ async remove(id3) {
668
1398
  const change = {
669
1399
  type: "delete",
670
- id: id2
1400
+ id: id3
671
1401
  };
672
1402
  await this.applyChanges([change]);
673
1403
  }
674
- async modify(id2, data) {
1404
+ async modify(id3, data) {
675
1405
  const change = {
676
1406
  type: "modify",
677
- id: id2,
1407
+ id: id3,
678
1408
  data
679
1409
  };
680
1410
  const { from, to } = await this.applyChange(change);
681
1411
  return { from, to };
682
1412
  }
683
- async mutate(id2, editCallback) {
684
- const object = await this.findById(id2);
685
- const [draft, finalize] = create(object || {}, { enablePatches: true });
1413
+ async mutate(id3, editCallback) {
1414
+ const result = await this.find({ where: { _id: id3 } });
1415
+ const object3 = result[0];
1416
+ const [draft, finalize] = create(object3 || {}, { enablePatches: true });
686
1417
  await editCallback(draft);
687
1418
  const [_, patches] = finalize();
688
1419
  const change = {
689
1420
  type: "mutate",
690
- id: id2,
1421
+ id: id3,
691
1422
  patches
692
1423
  };
693
1424
  const { from, to } = await this.applyChange(change);
694
1425
  return { from, to };
695
1426
  }
1427
+ applySerializedChanges(changes) {
1428
+ return Promise.all(changes.map((change) => this.applyChange(change)));
1429
+ }
696
1430
  unsubscribe(listener) {
697
1431
  this.listeners.delete(listener);
698
1432
  }
@@ -728,10 +1462,10 @@ class ForkedStoreState extends StoreState {
728
1462
  };
729
1463
  }
730
1464
  if (change.type === "delete") {
731
- const from = await this.findById(change.id);
1465
+ const from = await this.find({ where: { _id: change.id } }).then((results) => results[0] || null);
732
1466
  this.changedItems.set(change.id, null);
733
1467
  return {
734
- from: from || null,
1468
+ from,
735
1469
  to: null,
736
1470
  event: {
737
1471
  type: "delete",
@@ -741,7 +1475,9 @@ class ForkedStoreState extends StoreState {
741
1475
  };
742
1476
  }
743
1477
  if (change.type === "modify") {
744
- const existing = await this.findById(change.id);
1478
+ const existing = await this.find({
1479
+ where: { _id: change.id }
1480
+ }).then((results) => results[0]);
745
1481
  const updated = existing ? deepMerge(existing, change.data) : { _id: change.id, ...change.data };
746
1482
  const item = this.deserialize ? this.deserialize(updated) : updated;
747
1483
  this.changedItems.set(change.id, item);
@@ -756,7 +1492,9 @@ class ForkedStoreState extends StoreState {
756
1492
  };
757
1493
  }
758
1494
  if (change.type === "mutate") {
759
- const existing = await this.findById(change.id);
1495
+ const existing = await this.find({
1496
+ where: { _id: change.id }
1497
+ }).then((results) => results[0]);
760
1498
  const updated = apply(existing || {}, change.patches);
761
1499
  const item = this.deserialize ? this.deserialize(updated) : updated;
762
1500
  this.changedItems.set(change.id, item);
@@ -773,59 +1511,42 @@ class ForkedStoreState extends StoreState {
773
1511
  throw new Error("Unknown change type");
774
1512
  }
775
1513
  async applyChange(change) {
776
- const { event, from, to } = await this.applyChangeAndReturnEvent(change);
777
- this.notifyListeners([event]);
1514
+ const { event: event3, from, to } = await this.applyChangeAndReturnEvent(change);
1515
+ this.notifyListeners([event3]);
778
1516
  return { from, to };
779
1517
  }
780
1518
  async applyChanges(changes) {
781
1519
  const events = [];
782
1520
  for (const change of changes) {
783
- const { event } = await this.applyChangeAndReturnEvent(change);
784
- if (event)
785
- events.push(event);
1521
+ const { event: event3 } = await this.applyChangeAndReturnEvent(change);
1522
+ if (event3)
1523
+ events.push(event3);
786
1524
  }
787
1525
  if (events.length > 0) {
788
1526
  this.notifyListeners(events);
789
1527
  }
790
1528
  }
791
- async findById(id2, listener) {
792
- if (listener)
793
- this.listeners.set(listener, { callback: listener, id: id2 });
794
- if (this.changedItems.has(id2))
795
- return this.changedItems.get(id2);
796
- return await this.master.findById(id2);
797
- }
798
- async findByIndex(index, data, listener) {
799
- if (listener)
1529
+ async find(options, listener) {
1530
+ if (listener) {
800
1531
  this.listeners.set(listener, { callback: listener });
801
- const parentResult = await this.master.findByIndex(index, data);
1532
+ }
1533
+ const parentResults = await this.master.find(options);
802
1534
  const results = new Map;
803
- parentResult.forEach((item) => results.set(item._id, item));
804
- for (const [id2, changedItem] of this.changedItems) {
1535
+ parentResults.forEach((item) => results.set(item._id, item));
1536
+ for (const [id3, changedItem] of this.changedItems) {
805
1537
  if (changedItem === null) {
806
- results.delete(id2);
1538
+ results.delete(id3);
807
1539
  continue;
808
1540
  }
809
- const matches = Object.entries(data).every(([key, value]) => changedItem[key] === value);
1541
+ const matches = !options.where || Object.entries(options.where).every(([key, value]) => changedItem[key] === value);
810
1542
  if (matches) {
811
- results.set(id2, changedItem);
1543
+ results.set(id3, changedItem);
812
1544
  } else {
813
- results.delete(id2);
1545
+ results.delete(id3);
814
1546
  }
815
1547
  }
816
1548
  return Array.from(results.values());
817
1549
  }
818
- async findAll(listener) {
819
- if (listener)
820
- this.listeners.set(listener, { callback: listener });
821
- const parentResult = await this.master.findAll();
822
- return parentResult.map((item) => {
823
- const id2 = item._id;
824
- if (this.changedItems.has(id2))
825
- return this.changedItems.get(id2);
826
- return item;
827
- });
828
- }
829
1550
  }
830
1551
 
831
1552
  // data-storage/data-storage-forked.ts
@@ -864,8 +1585,6 @@ class ForkedDataStorage extends DataStorage {
864
1585
  // data-storage/store-state-master.ts
865
1586
  import { apply as apply2 } from "mutative";
866
1587
  class MasterStoreState extends StoreState {
867
- items = new Map;
868
- isComplete = false;
869
1588
  constructor(storeName, dataStorage, deserialize) {
870
1589
  super(storeName, dataStorage, deserialize);
871
1590
  }
@@ -873,7 +1592,6 @@ class MasterStoreState extends StoreState {
873
1592
  if (change.type === "set") {
874
1593
  await transaction.set(this.storeName, change.data);
875
1594
  const item = this.deserialize ? this.deserialize(change.data) : change.data;
876
- this.items.set(change.data._id, item);
877
1595
  return {
878
1596
  from: null,
879
1597
  to: item,
@@ -886,7 +1604,6 @@ class MasterStoreState extends StoreState {
886
1604
  }
887
1605
  if (change.type === "delete") {
888
1606
  await transaction.remove(this.storeName, change.id);
889
- this.items.set(change.id, null);
890
1607
  return {
891
1608
  from: null,
892
1609
  to: null,
@@ -898,11 +1615,10 @@ class MasterStoreState extends StoreState {
898
1615
  };
899
1616
  }
900
1617
  if (change.type === "modify") {
901
- const existing = await transaction.findById(this.storeName, change.id);
1618
+ const existing = await transaction.find(this.storeName, { where: { _id: change.id } }).then((results) => results[0]);
902
1619
  const updated = existing ? deepMerge(existing, change.data) : { _id: change.id, ...change.data };
903
1620
  await transaction.set(this.storeName, updated);
904
1621
  const item = this.deserialize ? this.deserialize(updated) : updated;
905
- this.items.set(change.id, item);
906
1622
  return {
907
1623
  from: null,
908
1624
  to: item,
@@ -914,11 +1630,10 @@ class MasterStoreState extends StoreState {
914
1630
  };
915
1631
  }
916
1632
  if (change.type === "mutate") {
917
- const existing = await transaction.findById(this.storeName, change.id);
918
- const updated = apply2(existing, change.patches);
1633
+ const existing = await transaction.find(this.storeName, { where: { _id: change.id } }).then((results) => results[0]);
1634
+ const updated = apply2(existing || {}, change.patches);
919
1635
  await transaction.set(this.storeName, updated);
920
1636
  const item = this.deserialize ? this.deserialize(updated) : updated;
921
- this.items.set(change.id, item);
922
1637
  return {
923
1638
  from: null,
924
1639
  to: item,
@@ -933,77 +1648,31 @@ class MasterStoreState extends StoreState {
933
1648
  }
934
1649
  async applyChange(change) {
935
1650
  const transaction = await this.dataStorage.getReadWriteTransaction();
936
- const { event, from, to } = await this.applyChangeAndReturnEvent(transaction, change);
937
- this.notifyListeners([event]);
1651
+ const { event: event3, from, to } = await this.applyChangeAndReturnEvent(transaction, change);
1652
+ await transaction.commit();
1653
+ this.notifyListeners([event3]);
938
1654
  return { from, to };
939
1655
  }
940
1656
  async applyChanges(changes) {
941
1657
  const transaction = await this.dataStorage.getReadWriteTransaction();
942
1658
  const events = [];
943
1659
  for (const change of changes) {
944
- const { event } = await this.applyChangeAndReturnEvent(transaction, change);
945
- if (event)
946
- events.push(event);
1660
+ const { event: event3 } = await this.applyChangeAndReturnEvent(transaction, change);
1661
+ if (event3)
1662
+ events.push(event3);
947
1663
  }
948
1664
  await transaction.commit();
949
1665
  if (events.length > 0) {
950
1666
  this.notifyListeners(events);
951
1667
  }
952
1668
  }
953
- async findById(id2, listener) {
954
- if (!id2)
955
- return;
956
- if (listener)
957
- this.listeners.set(listener, { callback: listener, id: id2 });
958
- if (this.items.has(id2))
959
- return this.items.get(id2);
960
- const transaction = await this.dataStorage.getReadTransaction();
961
- const result = await transaction.findById(this.storeName, id2);
962
- const item = result && this.deserialize ? this.deserialize(result) : result;
963
- if (!item)
964
- return;
965
- this.items.set(id2, item);
966
- return item;
967
- }
968
- async findByIndex(index, data, listener) {
969
- if (listener)
1669
+ async find(options, listener) {
1670
+ if (listener) {
970
1671
  this.listeners.set(listener, { callback: listener });
971
- if (this.isComplete) {
972
- const results2 = Array.from(this.items.values()).filter((item) => {
973
- if (!item)
974
- return false;
975
- return indexQueryPredicate(item, data);
976
- });
977
- return results2;
978
1672
  }
979
1673
  const transaction = await this.dataStorage.getReadTransaction();
980
- const dbResults = await transaction.findByIndex(this.storeName, index, data);
981
- const results = dbResults.map((item) => {
982
- const id2 = item._id;
983
- if (this.items.has(id2))
984
- return this.items.get(id2);
985
- const processedItem = this.deserialize ? this.deserialize(item) : item;
986
- return processedItem;
987
- });
988
- return results;
989
- }
990
- async findAll(listener) {
991
- if (listener)
992
- this.listeners.set(listener, { callback: listener });
993
- if (this.isComplete)
994
- return Array.from(this.items.values()).filter((e) => !!e);
995
- const transaction = await this.dataStorage.getReadTransaction();
996
- const dbResults = await transaction.findAll(this.storeName);
997
- const items = dbResults.map((item) => {
998
- const id2 = item._id;
999
- if (this.items.has(id2))
1000
- return this.items.get(id2);
1001
- const processedItem = this.deserialize ? this.deserialize(item) : item;
1002
- this.items.set(processedItem._id, processedItem);
1003
- return processedItem;
1004
- });
1005
- this.isComplete = true;
1006
- return items;
1674
+ const results = await transaction.find(this.storeName, options);
1675
+ return results.map((item) => this.deserialize ? this.deserialize(item) : item);
1007
1676
  }
1008
1677
  }
1009
1678
 
@@ -1027,16 +1696,19 @@ class MasterDataStorage extends DataStorage {
1027
1696
  }
1028
1697
  getStore(storeName) {
1029
1698
  if (!this.stores.has(storeName)) {
1030
- const contextElement = this.arcContext.elementsMap[storeName];
1699
+ const contextElement = this.arcContext.elements.find((element) => element.name === storeName);
1031
1700
  if (!contextElement)
1032
1701
  console.log(`Can't find ${storeName} as context element`);
1033
- this.stores.set(storeName, new MasterStoreState(storeName, this, contextElement && contextElement.deserialize ? (a) => contextElement.deserialize(a) : undefined));
1702
+ this.stores.set(storeName, new MasterStoreState(storeName, this, contextElement && "deserialize" in contextElement && typeof contextElement.deserialize === "function" ? (a) => contextElement.deserialize(a) : undefined));
1034
1703
  }
1035
1704
  return this.stores.get(storeName);
1036
1705
  }
1037
1706
  async applyChanges(changes) {
1038
1707
  return Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applyChanges(changes2)));
1039
1708
  }
1709
+ applySerializedChanges(changes) {
1710
+ return Promise.all(changes.map(({ store, changes: changes2 }) => this.getStore(store).applySerializedChanges(changes2)));
1711
+ }
1040
1712
  async commitChanges(changes) {
1041
1713
  await Promise.all([
1042
1714
  this.applyChanges(changes),
@@ -1050,192 +1722,350 @@ class MasterDataStorage extends DataStorage {
1050
1722
  await this.rtcAdapter.sync(progressCallback);
1051
1723
  }
1052
1724
  }
1053
- // elements/object.ts
1054
- class ArcObject extends ArcAbstract {
1055
- rawShape;
1056
- constructor(rawShape) {
1057
- super();
1058
- this.rawShape = rawShape;
1059
- }
1060
- parse(value) {
1061
- return Object.entries(this.rawShape).reduce((acc, [key, element]) => {
1062
- acc[key] = element.parse(value[key]);
1063
- return acc;
1064
- }, {});
1065
- }
1066
- serialize(value) {
1067
- return Object.entries(value).reduce((acc, [key, value2]) => {
1068
- if (!this.rawShape[key]) {
1069
- acc[key] = value2;
1725
+ // db/sqliteAdapter.ts
1726
+ class SQLiteReadTransaction {
1727
+ db;
1728
+ tables;
1729
+ constructor(db, tables) {
1730
+ this.db = db;
1731
+ this.tables = tables;
1732
+ }
1733
+ getId(store, id3) {
1734
+ return id3;
1735
+ }
1736
+ buildWhereClause(where) {
1737
+ if (!where) {
1738
+ return { sql: "deleted != 1", params: [] };
1739
+ }
1740
+ const conditions = ["deleted != 1"];
1741
+ const params = [];
1742
+ Object.entries(where).forEach(([key, value]) => {
1743
+ if (typeof value === "object" && value !== null) {
1744
+ Object.entries(value).forEach(([operator, operand]) => {
1745
+ switch (operator) {
1746
+ case "$eq":
1747
+ case "$ne":
1748
+ case "$gt":
1749
+ case "$gte":
1750
+ case "$lt":
1751
+ case "$lte":
1752
+ conditions.push(`${key} ${this.getOperatorSymbol(operator)} ?`);
1753
+ params.push(operand);
1754
+ break;
1755
+ case "$in":
1756
+ case "$nin":
1757
+ if (Array.isArray(operand)) {
1758
+ conditions.push(`${key} ${operator === "$in" ? "IN" : "NOT IN"} (${operand.map(() => "?").join(", ")})`);
1759
+ params.push(...operand);
1760
+ }
1761
+ break;
1762
+ case "$exists":
1763
+ if (typeof operand === "boolean") {
1764
+ conditions.push(operand ? `${key} IS NOT NULL` : `${key} IS NULL`);
1765
+ }
1766
+ break;
1767
+ }
1768
+ });
1070
1769
  } else {
1071
- acc[key] = this.rawShape[key].serialize(value2);
1770
+ conditions.push(`${key} = ?`);
1771
+ params.push(value);
1072
1772
  }
1073
- return acc;
1074
- }, {});
1773
+ });
1774
+ return {
1775
+ sql: conditions.join(" AND "),
1776
+ params
1777
+ };
1075
1778
  }
1076
- deserialize(value) {
1077
- return Object.fromEntries(Object.entries(this.rawShape).map(([key, element]) => [
1078
- key,
1079
- element.deserialize(value[key])
1080
- ]));
1779
+ getOperatorSymbol(operator) {
1780
+ const operators = {
1781
+ $eq: "=",
1782
+ $ne: "!=",
1783
+ $gt: ">",
1784
+ $gte: ">=",
1785
+ $lt: "<",
1786
+ $lte: "<="
1787
+ };
1788
+ return operators[operator] || "=";
1789
+ }
1790
+ buildOrderByClause(orderBy) {
1791
+ if (!orderBy)
1792
+ return "";
1793
+ const orderClauses = Object.entries(orderBy).map(([key, direction]) => `${key} ${direction.toUpperCase()}`).join(", ");
1794
+ return orderClauses ? `ORDER BY ${orderClauses}` : "";
1795
+ }
1796
+ async find(store, options) {
1797
+ const { where, limit, offset, orderBy } = options || {};
1798
+ const whereClause = this.buildWhereClause(where);
1799
+ const orderByClause = this.buildOrderByClause(orderBy);
1800
+ const query2 = `
1801
+ SELECT *
1802
+ FROM ${store}
1803
+ WHERE ${whereClause.sql}
1804
+ ${orderByClause}
1805
+ ${limit ? `LIMIT ${limit}` : ""}
1806
+ ${offset ? `OFFSET ${offset}` : ""}
1807
+ `;
1808
+ return await this.db.exec(query2, whereClause.params);
1081
1809
  }
1082
- deserializePath(path, value) {
1083
- if (path.length === 0) {
1084
- return this.deserialize(value);
1810
+ }
1811
+
1812
+ class SQLiteReadWriteTransaction extends SQLiteReadTransaction {
1813
+ async remove(store, id3) {
1814
+ const table = this.tables.get(store);
1815
+ if (!table) {
1816
+ throw new Error(`Store ${store} not found`);
1085
1817
  }
1086
- const [key, ...restPath] = path;
1087
- const element = this.rawShape[key];
1088
- if (!element) {
1089
- console.warn(`No element found for key: ${key}`);
1090
- return value;
1818
+ const query2 = `UPDATE ${store} SET deleted = 1, lastUpdate = ? WHERE ${table.primaryKey} = ?`;
1819
+ await this.db.exec(query2, [new Date().toISOString(), id3]);
1820
+ }
1821
+ async set(store, item) {
1822
+ const schema = this.tables.get(store);
1823
+ if (!schema) {
1824
+ throw new Error(`Store ${store} not found`);
1091
1825
  }
1092
- if (element instanceof ArcObject || element instanceof ArcArray) {
1093
- return element.deserializePath(restPath, value);
1826
+ const now = new Date().toISOString();
1827
+ const columnNames = schema.columns.map((col) => col.name);
1828
+ const values = schema.columns.map((column) => {
1829
+ let value = item[column.name];
1830
+ if (value === undefined && column.default !== undefined) {
1831
+ value = column.default;
1832
+ }
1833
+ return this.serializeValue(value);
1834
+ });
1835
+ const placeholders = columnNames.map(() => "?").join(", ");
1836
+ const sql = `
1837
+ INSERT OR REPLACE INTO ${schema.name}
1838
+ (${columnNames.join(", ")})
1839
+ VALUES (${placeholders})
1840
+ `;
1841
+ await this.db.exec(sql, values);
1842
+ }
1843
+ async commit() {
1844
+ return Promise.resolve();
1845
+ }
1846
+ serializeValue(value) {
1847
+ if (value === null || value === undefined)
1848
+ return null;
1849
+ if (value instanceof Date) {
1850
+ return value.toISOString();
1094
1851
  }
1095
- return element.deserialize(value);
1096
- }
1097
- parsePartial(value) {
1098
- return Object.entries(value).reduce((acc, [key, value2]) => {
1099
- acc[key] = this.rawShape[key].parse(value2);
1100
- return acc;
1101
- }, {});
1102
- }
1103
- deserializePartial(value) {
1104
- return Object.entries(value).reduce((acc, [key, value2]) => {
1105
- acc[key] = this.rawShape[key].deserialize(value2);
1106
- return acc;
1107
- }, {});
1108
- }
1109
- serializePartial(value) {
1110
- return Object.entries(value).reduce((acc, [key, value2]) => {
1111
- acc[key] = this.rawShape[key].serialize(value2);
1112
- return acc;
1113
- }, {});
1852
+ if (Array.isArray(value) || typeof value === "object") {
1853
+ return JSON.stringify(value);
1854
+ }
1855
+ return value;
1114
1856
  }
1115
1857
  }
1116
- function object(element) {
1117
- return new ArcObject(element);
1118
- }
1119
1858
 
1120
- // elements/array.ts
1121
- class ArcArray extends ArcAbstract {
1122
- parent;
1123
- constructor(parent) {
1124
- super();
1125
- this.parent = parent;
1126
- }
1127
- parse(value) {
1128
- return value.map((v) => this.parent.parse(v));
1129
- }
1130
- serialize(value) {
1131
- return value.map((v) => this.parent.serialize(v));
1132
- }
1133
- deserialize(value) {
1134
- return value.map((v) => this.parent.deserialize(v));
1859
+ class SQLiteAdapter {
1860
+ db;
1861
+ context;
1862
+ tables = new Map;
1863
+ constructor(db, context3) {
1864
+ this.db = db;
1865
+ this.context = context3;
1866
+ this.context.elements.forEach((element) => {
1867
+ if ("storeSchema" in element && typeof element.storeSchema === "function") {
1868
+ element.storeSchema().tables.forEach((table) => {
1869
+ this.tables.set(table.name, table);
1870
+ });
1871
+ }
1872
+ });
1135
1873
  }
1136
- deserializePath(path, value) {
1137
- if (path.length === 0) {
1138
- return this.deserialize(value);
1874
+ async initialize() {
1875
+ const stores = new Set;
1876
+ for (const element of this.context.elements) {
1877
+ if ("storeSchema" in element && typeof element.storeSchema === "function") {
1878
+ const schema = element.storeSchema();
1879
+ stores.add(schema);
1880
+ }
1139
1881
  }
1140
- if (this.parent instanceof ArcObject || this.parent instanceof ArcArray) {
1141
- return this.parent.deserializePath(path, value);
1882
+ for (const schema of stores) {
1883
+ for (const table of schema.tables) {
1884
+ await this.createTableIfNotExists(table);
1885
+ }
1142
1886
  }
1143
- return this.parent.deserialize(value);
1144
- }
1145
- }
1146
- function array(element) {
1147
- return new ArcArray(element);
1148
- }
1149
- // elements/boolean.ts
1150
- class ArcBoolean extends ArcPrimitive {
1151
- }
1152
- function boolean() {
1153
- return new ArcBoolean;
1154
- }
1155
- // elements/date.ts
1156
- class ArcDate extends ArcAbstract {
1157
- constructor() {
1158
- super();
1159
1887
  }
1160
- parse(value) {
1161
- return new Date(value);
1888
+ async createTableIfNotExists(table) {
1889
+ const columns = table.columns.map((column) => {
1890
+ const constraints = [];
1891
+ if (!column.isOptional) {
1892
+ constraints.push("NOT NULL");
1893
+ }
1894
+ if (column.default !== undefined) {
1895
+ constraints.push(`DEFAULT ${JSON.stringify(column.default)}`);
1896
+ }
1897
+ if (column.name === table.primaryKey) {
1898
+ constraints.push("PRIMARY KEY");
1899
+ }
1900
+ return `"${column.name}" ${column.type} ${constraints.join(" ")}`.trim();
1901
+ });
1902
+ const createTableSQL = `
1903
+ CREATE TABLE IF NOT EXISTS ${table.name} (
1904
+ ${columns.join(`,
1905
+ `)}
1906
+ )
1907
+ `;
1908
+ await this.db.exec(createTableSQL);
1162
1909
  }
1163
- serialize(value) {
1164
- return value.getTime();
1910
+ readWriteTransaction(stores) {
1911
+ return new SQLiteReadWriteTransaction(this.db, this.tables);
1165
1912
  }
1166
- deserialize(value) {
1167
- return new Date(value);
1913
+ readTransaction(stores) {
1914
+ return new SQLiteReadTransaction(this.db, this.tables);
1168
1915
  }
1169
1916
  }
1170
- function date() {
1171
- return new ArcDate;
1172
- }
1173
- // elements/number.ts
1174
- class ArcNumber extends ArcPrimitive {
1175
- }
1176
- function number() {
1177
- return new ArcNumber;
1917
+ var createSQLiteAdapterFactory = (db) => {
1918
+ return async (context3) => {
1919
+ const adapter = new SQLiteAdapter(db, context3);
1920
+ await adapter.initialize();
1921
+ return adapter;
1922
+ };
1923
+ };
1924
+ // model/model.ts
1925
+ class ModelBase {
1178
1926
  }
1179
- // elements/record.ts
1180
- class ArcRecord extends ArcAbstract {
1181
- key;
1182
- element;
1183
- constructor(key, element) {
1927
+
1928
+ class Model extends ModelBase {
1929
+ context;
1930
+ dataStorage;
1931
+ client;
1932
+ catchErrorCallback;
1933
+ queryCache = new QueryCache;
1934
+ constructor(context3, dataStorage, client, catchErrorCallback) {
1184
1935
  super();
1185
- this.key = key;
1186
- this.element = element;
1936
+ this.context = context3;
1937
+ this.dataStorage = dataStorage;
1938
+ this.client = client;
1939
+ this.catchErrorCallback = catchErrorCallback;
1940
+ }
1941
+ async query(queryBuilderFn) {
1942
+ const queryContext = new QueryBuilderContext(this.queryCache, this.dataStorage);
1943
+ const queryBuilder = this.context.queryBuilder(queryContext);
1944
+ const query2 = queryBuilderFn(queryBuilder).toQuery(queryContext);
1945
+ return query2.run(this.dataStorage);
1946
+ }
1947
+ subscribe(queryBuilderFn, callback) {
1948
+ const queryContext = new QueryBuilderContext(this.queryCache, this.dataStorage);
1949
+ const queryBuilder = this.context.queryBuilder(queryContext);
1950
+ const query2 = queryBuilderFn(queryBuilder).toQuery(queryContext);
1951
+ query2.subscribe(callback);
1952
+ const runPromise = query2.run(this.dataStorage);
1953
+ runPromise.then((result) => {
1954
+ callback(result);
1955
+ });
1956
+ return {
1957
+ unsubscribe: () => {
1958
+ query2.unsubscribe(callback);
1959
+ },
1960
+ result: runPromise
1961
+ };
1187
1962
  }
1188
- parse(value) {
1189
- if (!value)
1190
- return {};
1191
- return Object.entries(value).reduce((acc, [key, recordValue]) => {
1192
- acc[key] = this.element.parse(recordValue);
1193
- return acc;
1194
- }, {});
1963
+ commands() {
1964
+ const queryContext = new QueryBuilderContext(this.queryCache, this.dataStorage);
1965
+ return this.context.commandsClient(this.client, queryContext, this.dataStorage, this.catchErrorCallback);
1195
1966
  }
1196
- serialize(value) {
1197
- if (!value)
1198
- return {};
1199
- return Object.entries(value).reduce((acc, [key, recordValue]) => {
1200
- acc[key] = this.element.serialize(recordValue);
1201
- return acc;
1202
- }, {});
1967
+ fork() {
1968
+ return new ForkedModel(this.context, this.dataStorage.fork(), this.client, this.catchErrorCallback);
1203
1969
  }
1204
- deserialize(value) {
1205
- if (!value)
1206
- return {};
1207
- return Object.entries(value).reduce((acc, [key, recordValue]) => {
1208
- acc[key] = this.element.deserialize(recordValue);
1209
- return acc;
1210
- }, {});
1970
+ get $debug() {
1971
+ return {};
1211
1972
  }
1212
1973
  }
1213
- function record(key, element) {
1214
- return new ArcRecord(key, element);
1974
+
1975
+ class ForkedModel extends Model {
1976
+ constructor(context3, dataStorage, client, catchErrorCallback) {
1977
+ super(context3, dataStorage, client, catchErrorCallback);
1978
+ }
1979
+ merge() {}
1215
1980
  }
1216
- // elements/string-enum.ts
1217
- class ArcStringEnum extends ArcAbstract {
1218
- values;
1219
- constructor(values) {
1981
+
1982
+ class RemoteModelClient extends ModelBase {
1983
+ context;
1984
+ apiBaseUrl;
1985
+ client;
1986
+ catchErrorCallback;
1987
+ constructor(context3, apiBaseUrl, client, catchErrorCallback) {
1220
1988
  super();
1221
- this.values = values;
1222
- }
1223
- parse(value) {
1224
- return value;
1225
- }
1226
- serialize(value) {
1227
- return value;
1989
+ this.context = context3;
1990
+ this.apiBaseUrl = apiBaseUrl;
1991
+ this.client = client;
1992
+ this.catchErrorCallback = catchErrorCallback;
1993
+ }
1994
+ async query(queryBuilderFn) {
1995
+ const queryTracking = {
1996
+ element: null,
1997
+ queryType: null,
1998
+ params: null
1999
+ };
2000
+ const queryContext = new QueryBuilderContext(new QueryCache, null);
2001
+ const originalQueryBuilder = this.context.queryBuilder(queryContext);
2002
+ const queryBuilderProxy = new Proxy(originalQueryBuilder, {
2003
+ get: (target, prop) => {
2004
+ queryTracking.element = prop;
2005
+ const originalElement = Reflect.get(target, prop);
2006
+ return new Proxy(originalElement, {
2007
+ get: (elementTarget, methodProp) => {
2008
+ queryTracking.queryType = methodProp;
2009
+ const originalMethod = Reflect.get(elementTarget, methodProp);
2010
+ return (...args) => {
2011
+ queryTracking.params = args;
2012
+ return originalMethod(...args);
2013
+ };
2014
+ }
2015
+ });
2016
+ }
2017
+ });
2018
+ const query2 = queryBuilderFn(queryBuilderProxy).toQuery(queryContext);
2019
+ const response = await fetch(`${this.apiBaseUrl}/query`, {
2020
+ method: "POST",
2021
+ headers: { "Content-Type": "application/json" },
2022
+ body: JSON.stringify({
2023
+ query: {
2024
+ element: queryTracking.element,
2025
+ queryType: queryTracking.queryType,
2026
+ params: queryTracking.params
2027
+ }
2028
+ })
2029
+ });
2030
+ if (!response.ok) {
2031
+ throw new Error(`Query failed: ${response.statusText}`);
2032
+ }
2033
+ const { result } = await response.json();
2034
+ return result;
1228
2035
  }
1229
- deserialize(value) {
1230
- return value;
2036
+ subscribe(queryBuilderFn, callback) {
2037
+ const result = this.query(queryBuilderFn);
2038
+ result.then((initialResult) => {
2039
+ callback(initialResult);
2040
+ }).catch(this.catchErrorCallback);
2041
+ return {
2042
+ unsubscribe: () => {},
2043
+ result
2044
+ };
1231
2045
  }
1232
- getEnumerators() {
1233
- return this.values;
2046
+ commands() {
2047
+ const commandsProxy = new Proxy({}, {
2048
+ get: (target, prop) => {
2049
+ const element = this.context.elements.find((e) => e.name === prop);
2050
+ if (!element) {
2051
+ throw new Error(`Command ${String(prop)} not found`);
2052
+ }
2053
+ return Object.assign(async (argument) => {
2054
+ const response = await fetch(`${this.apiBaseUrl}/command/${String(prop)}`, {
2055
+ method: "POST",
2056
+ headers: { "Content-Type": "application/json" },
2057
+ body: JSON.stringify(argument)
2058
+ });
2059
+ if (!response.ok) {
2060
+ throw new Error(`Command ${String(prop)} failed: ${response.statusText}`);
2061
+ }
2062
+ return response.json();
2063
+ }, { params: element._params });
2064
+ }
2065
+ });
2066
+ return commandsProxy;
1234
2067
  }
1235
2068
  }
1236
- function stringEnum(...values) {
1237
- return new ArcStringEnum(values);
1238
- }
1239
2069
  // rtc/client.ts
1240
2070
  class RTCClient {
1241
2071
  storage;
@@ -1259,41 +2089,9 @@ class RTCClient {
1259
2089
  }
1260
2090
  async performSync() {
1261
2091
  this.connectWebSocket();
1262
- const arcState = await this.storage.getStore("state").findById("$arc", (a) => a);
1263
- const response = await fetch(`/ws/sync?lastSync=${arcState?.lastSyncDate || ""}`, {
1264
- method: "GET",
1265
- headers: {
1266
- "Content-Type": "application/json",
1267
- Authorization: `Bearer ${this.token}`
1268
- }
1269
- });
1270
- if (!response.ok) {
1271
- throw new Error("Sync failed");
1272
- }
1273
- const { results, syncDate } = await response.json();
1274
- const pendingStoreChanges = [];
1275
- const transaction = await this.storage.getReadWriteTransaction();
1276
- for (const { store, items } of results) {
1277
- this.syncProgressCallback?.({ store, size: items.length });
1278
- for (const item of items) {
1279
- if (item.deleted) {
1280
- await transaction.remove(store, item._id);
1281
- } else {
1282
- await transaction.set(store, item);
1283
- }
1284
- }
1285
- }
1286
- await transaction.commit();
1287
- const stateStorage = this.storage.getStore("state");
1288
- await stateStorage.applyChanges([
1289
- {
1290
- type: "set",
1291
- data: { _id: "$arc", lastSyncDate: syncDate }
1292
- }
1293
- ]);
1294
2092
  }
1295
2093
  async connectWebSocket() {
1296
- this._socket = new WebSocket(`wss://${window.location.host}/ws?token=${this.token}`);
2094
+ this._socket = new WebSocket(`wss://${window.location.host}/api/ws?token=${this.token}`);
1297
2095
  this.openSocket = new Promise((resolve) => {
1298
2096
  this._socket.addEventListener("open", () => {
1299
2097
  this.reconnectAttempts = 0;
@@ -1343,138 +2141,160 @@ class RTCClient {
1343
2141
  var rtcClientFactory = (token) => (storage) => {
1344
2142
  return new RTCClient(storage, token);
1345
2143
  };
1346
- // state/query.ts
1347
- class ArcStateQuery extends ArcQuery {
1348
- state;
1349
- bindedChangeHandler = this.changeHandler.bind(this);
1350
- store;
1351
- constructor(state) {
1352
- super();
1353
- this.state = state;
1354
- }
1355
- async run(dataStorage, listener) {
1356
- this.store = dataStorage.getStore("state");
1357
- const result = await this.store.findById(this.state.name, this.bindedChangeHandler);
1358
- this.lastResult = this.state.deserialize(result);
1359
- if (listener)
1360
- this.listener = listener;
1361
- return this.lastResult;
1362
- }
1363
- onChange(change) {
1364
- if (change.type === "set")
1365
- return change.item;
1366
- return false;
1367
- }
1368
- changeHandler(changes) {
1369
- for (const change of changes) {
1370
- const response = this.onChange(change);
1371
- if (response !== false)
1372
- this.lastResult = this.state.deserialize(response);
1373
- }
1374
- if (this.lastResult)
1375
- this.nextResult(this.lastResult);
1376
- }
1377
- unsubscribe() {
1378
- this.store.unsubscribe(this.bindedChangeHandler);
1379
- }
1380
- nextResult(result) {
1381
- this.lastResult = result;
1382
- this.listener?.(result);
1383
- }
1384
- }
1385
-
1386
- // state/query-builder.ts
1387
- class ArcStateQueryBuilder extends ArcQueryBuilder {
1388
- state;
1389
- constructor(state) {
1390
- super();
1391
- this.state = state;
1392
- }
1393
- toQuery() {
1394
- return new ArcStateQuery(this.state);
1395
- }
1396
- }
1397
-
1398
- // state/state.ts
1399
- class ArcState extends ArcContextElement {
2144
+ // view/view.ts
2145
+ class ArcView extends ArcContextElementWithStore {
1400
2146
  name;
2147
+ id;
1401
2148
  schema;
1402
- constructor(name, schema) {
2149
+ _description;
2150
+ _elements;
2151
+ _handler;
2152
+ constructor(name, id3, schema) {
1403
2153
  super();
1404
2154
  this.name = name;
2155
+ this.id = id3;
1405
2156
  this.schema = schema;
1406
2157
  }
1407
- serialize(data) {
2158
+ storeSchema = () => {
2159
+ return arcObjectToStoreSchema(this.name, this.schema);
2160
+ };
2161
+ use(elements) {
2162
+ const clone = this.clone();
2163
+ clone._elements = elements;
2164
+ return clone;
2165
+ }
2166
+ description(description) {
2167
+ const clone = this.clone();
2168
+ clone._description = description;
2169
+ return clone;
2170
+ }
2171
+ handle(handler) {
2172
+ const clone = this.clone();
2173
+ clone._handler = handler;
2174
+ return clone;
2175
+ }
2176
+ queryBuilder = (context3) => {
1408
2177
  return {
1409
- ...this.schema.serialize(data),
1410
- _id: this.name
2178
+ find: (options) => {
2179
+ throw new Error("Not implemented");
2180
+ }
1411
2181
  };
1412
- }
1413
- deserialize(data) {
1414
- return this.schema.deserialize(data || {});
1415
- }
1416
- queryBuilder() {
1417
- return new ArcStateQueryBuilder(this);
1418
- }
1419
- commandContext(dataStorage, publishEvent) {
1420
- const store = dataStorage.getStore("state");
2182
+ };
2183
+ commandContext = (dataStorage, publishEvent) => {
2184
+ const store = dataStorage.getStore(this.name);
1421
2185
  return {
1422
- get: async () => {
1423
- return store.findById(this.name);
2186
+ find: async (options) => {
2187
+ return store.find(options);
1424
2188
  },
1425
- modify: async (data) => {
1426
- const serialized = this.serialize(data);
1427
- const { from, to } = await store.modify(this.name, serialized);
1428
- await publishEvent({
1429
- type: "modify",
1430
- changes: data,
1431
- from,
1432
- to
2189
+ findOne: async (where) => {
2190
+ const result = await store.find({
2191
+ where,
2192
+ limit: 1
1433
2193
  });
1434
- },
1435
- edit: async (editCallback) => {
1436
- const { from, to } = await store.mutate(this.name, editCallback);
2194
+ return result[0];
1437
2195
  }
1438
2196
  };
2197
+ };
2198
+ observer = () => {
2199
+ return Object.entries(this._handler ?? {}).reduce((acc, [key, value]) => {
2200
+ acc[key] = (event3, dataStorage) => {
2201
+ const store = dataStorage.getStore(this.name);
2202
+ const ctx = {
2203
+ remove: async (id3) => {
2204
+ await store.remove(id3);
2205
+ return { success: true };
2206
+ },
2207
+ set: async (id3, data) => {
2208
+ const parsed = this.schema.parse(data);
2209
+ const body = {
2210
+ _id: id3,
2211
+ lastUpdate: new Date().toISOString(),
2212
+ ...parsed
2213
+ };
2214
+ await store.set(body);
2215
+ return { success: true };
2216
+ },
2217
+ find: async (options) => {
2218
+ return store.find(options);
2219
+ },
2220
+ findOne: async (where) => {
2221
+ const result = await store.find({
2222
+ where,
2223
+ limit: 1
2224
+ });
2225
+ return result[0];
2226
+ },
2227
+ modify: async (id3, data) => {
2228
+ const deserialized = this.schema.serializePartial(data);
2229
+ const { from, to } = await store.modify(id3, {
2230
+ ...deserialized,
2231
+ lastUpdate: new Date().toISOString()
2232
+ });
2233
+ }
2234
+ };
2235
+ value(ctx, event3);
2236
+ };
2237
+ return acc;
2238
+ }, {});
2239
+ };
2240
+ clone() {
2241
+ const clone = new ArcView(this.name, this.id, this.schema);
2242
+ clone._description = this._description;
2243
+ clone._elements = this._elements;
2244
+ clone._handler = this._handler;
2245
+ return clone;
1439
2246
  }
1440
2247
  }
1441
- function state(name, schema) {
1442
- return new ArcState(name, schema);
2248
+ function view(name, id3, schema) {
2249
+ return new ArcView(name, id3, schema);
1443
2250
  }
1444
2251
  export {
2252
+ view,
1445
2253
  stringEnum,
1446
2254
  string,
1447
- state,
1448
2255
  rtcClientFactory,
1449
2256
  record,
2257
+ reactive,
1450
2258
  object,
1451
2259
  number,
1452
2260
  id,
2261
+ event,
1453
2262
  date,
1454
2263
  customId,
2264
+ createSQLiteAdapterFactory,
1455
2265
  context,
2266
+ command,
1456
2267
  collection,
1457
2268
  boolean,
1458
2269
  array,
1459
2270
  StoreState,
2271
+ SQLiteAdapter,
2272
+ RemoteModelClient,
2273
+ QueryCache,
2274
+ QueryBuilderContext,
2275
+ ModelBase,
2276
+ Model,
1460
2277
  MasterStoreState,
1461
2278
  MasterDataStorage,
1462
2279
  ForkedStoreState,
2280
+ ForkedModel,
1463
2281
  ForkedDataStorage,
1464
2282
  DataStorage,
2283
+ ArcView,
1465
2284
  ArcStringEnum,
1466
2285
  ArcString,
1467
- ArcState,
1468
2286
  ArcRecord,
1469
2287
  ArcQueryBuilder,
1470
2288
  ArcQuery,
1471
2289
  ArcOptional,
1472
2290
  ArcObject,
1473
2291
  ArcNumber,
1474
- ArcIndexedCollection,
1475
2292
  ArcId,
2293
+ ArcEvent,
1476
2294
  ArcDate,
1477
2295
  ArcCustomId,
2296
+ ArcContext,
2297
+ ArcCommand,
1478
2298
  ArcCollectionQuery,
1479
2299
  ArcCollection,
1480
2300
  ArcBranded,