nesoi 3.2.1 → 3.2.3

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 (46) hide show
  1. package/lib/compiler/elements/constants.element.js +1 -1
  2. package/lib/compiler/error.d.ts +1 -0
  3. package/lib/compiler/error.js +3 -0
  4. package/lib/compiler/stages/4_build_schemas_stage.js +14 -0
  5. package/lib/compiler/treeshake.js +3 -1
  6. package/lib/elements/blocks/job/internal/resource_job.js +1 -1
  7. package/lib/elements/blocks/resource/resource.builder.js +1 -1
  8. package/lib/elements/blocks/resource/resource.js +1 -0
  9. package/lib/elements/edge/externals/externals.builder.d.ts +2 -0
  10. package/lib/elements/edge/externals/externals.builder.js +6 -1
  11. package/lib/elements/edge/externals/externals.schema.d.ts +2 -1
  12. package/lib/elements/edge/externals/externals.schema.js +3 -1
  13. package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +2 -2
  14. package/lib/elements/entities/bucket/adapters/bucket_adapter.js +2 -2
  15. package/lib/elements/entities/bucket/adapters/memory.nql.d.ts +1 -1
  16. package/lib/elements/entities/bucket/adapters/memory.nql.js +9 -5
  17. package/lib/elements/entities/bucket/bucket.d.ts +15 -3
  18. package/lib/elements/entities/bucket/bucket.js +51 -15
  19. package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +14 -10
  20. package/lib/elements/entities/bucket/cache/bucket_cache.js +92 -58
  21. package/lib/elements/entities/bucket/graph/bucket_graph.d.ts +11 -0
  22. package/lib/elements/entities/bucket/graph/bucket_graph.js +57 -3
  23. package/lib/elements/entities/bucket/model/bucket_model.schema.js +16 -13
  24. package/lib/elements/entities/bucket/model/bucket_model_field.builder.d.ts +3 -4
  25. package/lib/elements/entities/bucket/query/nql_compiler.js +7 -1
  26. package/lib/elements/entities/bucket/query/nql_engine.d.ts +2 -2
  27. package/lib/elements/entities/bucket/query/nql_engine.js +8 -4
  28. package/lib/elements/entities/bucket/view/bucket_view.js +65 -12
  29. package/lib/elements/entities/constants/constants.schema.d.ts +2 -4
  30. package/lib/engine/apps/inline.app.js +1 -0
  31. package/lib/engine/module.d.ts +2 -2
  32. package/lib/engine/module.js +9 -2
  33. package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +5 -0
  34. package/lib/engine/transaction/nodes/bucket.trx_node.js +10 -0
  35. package/lib/engine/transaction/nodes/bucket_query.trx_node.d.ts +2 -0
  36. package/lib/engine/transaction/nodes/bucket_query.trx_node.js +15 -4
  37. package/lib/engine/transaction/trx_node.d.ts +1 -2
  38. package/lib/engine/util/log.d.ts +1 -1
  39. package/lib/engine/util/log.js +1 -0
  40. package/package.json +1 -1
  41. package/tools/joaquin/bucket.d.ts +23 -3
  42. package/tools/joaquin/bucket.js +48 -20
  43. package/tools/joaquin/job.js +4 -4
  44. package/tsconfig.build.tsbuildinfo +1 -1
  45. /package/lib/engine/apps/distributed/inc/{test.d.ts → sandbox.d.ts} +0 -0
  46. /package/lib/engine/apps/distributed/inc/{test.js → sandbox.js} +0 -0
@@ -4,16 +4,18 @@ exports.BucketCache = exports.BucketCacheEntry = void 0;
4
4
  const log_1 = require("../../../../engine/util/log");
5
5
  const memory_bucket_adapter_1 = require("../adapters/memory.bucket_adapter");
6
6
  const datetime_1 = require("../../../../engine/data/datetime");
7
+ const bucket_schema_1 = require("../bucket.schema");
8
+ const bucket_model_schema_1 = require("../model/bucket_model.schema");
9
+ const bucket_graph_schema_1 = require("../graph/bucket_graph.schema");
7
10
  /**
8
11
  * @category Elements
9
12
  * @subcategory Entity
10
13
  * */
11
14
  class BucketCacheEntry {
12
- constructor(id, obj, updateEpoch, syncEpoch) {
13
- this.id = id;
14
- this.obj = obj;
15
- this.updateEpoch = updateEpoch;
16
- this.syncEpoch = syncEpoch;
15
+ constructor(obj, __update_epoch, __sync_epoch) {
16
+ this.__update_epoch = __update_epoch;
17
+ this.__sync_epoch = __sync_epoch;
18
+ Object.assign(this, obj);
17
19
  }
18
20
  }
19
21
  exports.BucketCacheEntry = BucketCacheEntry;
@@ -22,28 +24,43 @@ exports.BucketCacheEntry = BucketCacheEntry;
22
24
  * @subcategory Entity
23
25
  * */
24
26
  class BucketCache {
25
- constructor(bucketName, outerAdapter, config) {
26
- this.bucketName = bucketName;
27
- this.outerAdapter = outerAdapter;
27
+ constructor(bucket, config) {
28
+ this.bucket = bucket;
28
29
  this.config = config;
29
- this.innerAdapter = this.config?.adapter || new memory_bucket_adapter_1.MemoryBucketAdapter({}, {});
30
+ const innerSchema = new bucket_schema_1.$Bucket(bucket.schema.module, bucket.schema.name, '[cache] ' + bucket.schema.alias, new bucket_model_schema_1.$BucketModel({
31
+ ...bucket.schema.model.fields,
32
+ __update_epoch: new bucket_model_schema_1.$BucketModelField('__update_epoch', '__update_epoch', 'int', '__update_epoch', true),
33
+ __sync_epoch: new bucket_model_schema_1.$BucketModelField('__sync_epoch', '__sync_epoch', 'int', '__sync_epoch', true),
34
+ }), new bucket_graph_schema_1.$BucketGraph(), {});
35
+ this.innerAdapter = this.config?.adapter || new memory_bucket_adapter_1.MemoryBucketAdapter(innerSchema, {});
36
+ this.outerAdapter = bucket.adapter;
30
37
  }
31
38
  async get(trx, id) {
32
39
  const mode = this.config?.mode?.get;
33
40
  if (mode === 'one') {
34
41
  const { action, sync } = await this.syncOne(trx, id);
35
- log_1.Log.debug('bucket', this.bucketName, `CACHE get.one, ${action}`);
36
- return sync?.obj;
42
+ log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE get.one, ${action}`);
43
+ if (!sync)
44
+ return undefined;
45
+ const { __update_epoch, __sync_epoch, ...obj } = sync;
46
+ return obj;
37
47
  }
38
48
  if (mode === 'past') {
39
49
  const { action, sync } = await this.syncOneAndPast(trx, id);
40
- log_1.Log.debug('bucket', this.bucketName, `CACHE get.past, ${action}`);
41
- return sync?.obj;
50
+ log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE get.past, ${action}`);
51
+ if (!sync)
52
+ return undefined;
53
+ const { __update_epoch, __sync_epoch, ...obj } = sync;
54
+ return obj;
42
55
  }
43
56
  if (mode === 'all') {
44
57
  const { action, sync } = await this.syncAll(trx);
45
- log_1.Log.debug('bucket', this.bucketName, `CACHE get.sync, ${action}`);
46
- return sync.find(s => s.obj.id === id)?.obj;
58
+ log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE get.all, ${action}`);
59
+ const one = sync.find(s => s.id === id);
60
+ if (!one)
61
+ return undefined;
62
+ const { __update_epoch, __sync_epoch, ...obj } = one;
63
+ return one;
47
64
  }
48
65
  return this.outerAdapter.get(trx, id);
49
66
  }
@@ -51,50 +68,69 @@ class BucketCache {
51
68
  const mode = this.config?.mode?.index;
52
69
  if (mode === 'all') {
53
70
  const { action, sync } = await this.syncAll(trx);
54
- log_1.Log.debug('bucket', this.bucketName, `CACHE index.sync, ${action}`);
55
- return sync.map(s => s.obj);
71
+ log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE index.all, ${action}`);
72
+ const data = [];
73
+ for (const e of sync) {
74
+ const { __update_epoch, __sync_epoch, ...obj } = e;
75
+ data.push(obj);
76
+ }
77
+ return data;
56
78
  }
57
79
  return this.outerAdapter.index(trx);
58
80
  }
59
- async query(trx, view, query, pagination) {
81
+ async query(trx, query, pagination, params, config) {
60
82
  const mode = this.config?.mode?.query;
83
+ let data;
61
84
  if (mode === 'incremental') {
62
- const { action, sync } = await this.syncQuery(trx, view, query, pagination);
63
- log_1.Log.debug('bucket', this.bucketName, `CACHE query.incremental, ${action}`);
64
- return sync.map(s => s.obj);
85
+ const { action, sync } = await this.syncQuery(trx, query, pagination, params);
86
+ log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.incremental, ${action}`);
87
+ data = sync;
65
88
  }
66
- if (mode === 'all') {
89
+ else if (mode === 'all') {
67
90
  const { action, sync } = await this.syncAll(trx);
68
- log_1.Log.debug('bucket', this.bucketName, `CACHE query.sync, ${action}`);
69
- return this.innerAdapter.query(trx, query);
91
+ log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.all, ${action}`);
92
+ const entries = (await this.innerAdapter.query(trx, query, pagination, params, undefined, this.innerAdapter.nql)).data;
93
+ data = [];
94
+ for (const e of entries) {
95
+ const { __update_epoch, __sync_epoch, ...obj } = e;
96
+ data.push(obj);
97
+ }
98
+ }
99
+ else {
100
+ data = (await this.outerAdapter.query(trx, query, pagination, params)).data;
101
+ }
102
+ for (const entry of data) {
103
+ delete entry['__update_epoch'];
104
+ delete entry['__sync_epoch'];
70
105
  }
71
- return this.outerAdapter.query(trx, query);
106
+ if (config?.view) {
107
+ data = await this.bucket.buildMany(trx, data, config.view);
108
+ }
109
+ return { data };
72
110
  }
73
111
  /* Cache modes */
74
112
  async syncOne(trx, id) {
75
- const localObj = await this.innerAdapter.get(trx, id);
113
+ let localObj = await this.innerAdapter.get(trx, id);
76
114
  if (!localObj) {
77
115
  const obj = await this.outerAdapter.get(trx, id);
78
116
  if (obj) {
79
- const entry = new BucketCacheEntry(obj.id, obj, this.outerAdapter.getUpdateEpoch(obj), this.lastSyncEpoch);
117
+ const entry = new BucketCacheEntry(obj, this.outerAdapter.getUpdateEpoch(obj), this.lastSyncEpoch);
80
118
  await this.innerAdapter.create(trx, entry);
81
119
  return { action: 'update', sync: entry };
82
120
  }
83
- return { action: 'keep' };
121
+ return { action: 'none' };
84
122
  }
85
- const sync = await this.outerAdapter.syncOne(trx, id, localObj.updateEpoch);
123
+ const sync = await this.outerAdapter.syncOne(trx, id, localObj.__update_epoch);
86
124
  if (sync === null) {
87
- return { action: 'keep', sync: localObj };
125
+ return { action: 'none', sync: localObj };
88
126
  }
89
127
  if (sync === 'deleted') {
90
128
  await this.innerAdapter.delete(trx, id);
91
129
  return { action: 'delete' };
92
130
  }
93
- localObj.obj = sync.obj;
94
- localObj.updateEpoch = sync.updateEpoch;
95
- localObj.syncEpoch = datetime_1.NesoiDatetime.now().epoch;
131
+ localObj = new BucketCacheEntry(sync.obj, sync.updateEpoch, datetime_1.NesoiDatetime.now().epoch);
96
132
  await this.innerAdapter.put(trx, localObj);
97
- return { action: 'update', sync };
133
+ return { action: 'update', sync: localObj };
98
134
  }
99
135
  async syncOneAndPast(trx, id) {
100
136
  const localObj = await this.innerAdapter.get(trx, id);
@@ -102,54 +138,52 @@ class BucketCache {
102
138
  const obj = await this.outerAdapter.get(trx, id);
103
139
  if (obj) {
104
140
  await this.innerAdapter.create(trx, obj);
105
- return { action: 'update', sync: {
106
- obj,
107
- updateEpoch: this.outerAdapter.getUpdateEpoch(obj)
108
- } };
141
+ return { action: 'update', sync: new BucketCacheEntry(obj, this.outerAdapter.getUpdateEpoch(obj), datetime_1.NesoiDatetime.now().epoch) };
109
142
  }
110
- return { action: 'keep' };
143
+ return { action: 'none' };
111
144
  }
112
- const sync = await this.outerAdapter.syncOneAndPast(trx, id, localObj.updateEpoch);
145
+ const sync = await this.outerAdapter.syncOneAndPast(trx, id, localObj.__update_epoch);
113
146
  if (sync === null) {
114
- return { action: 'keep', sync: localObj };
147
+ return { action: 'none', sync: localObj };
115
148
  }
116
149
  if (sync === 'deleted') {
117
150
  await this.innerAdapter.delete(trx, id);
118
151
  return { action: 'delete' };
119
152
  }
120
- await this.innerAdapter.putMany(trx, sync.map(s => s.obj));
121
- return { action: 'update', sync: sync.find(s => s.obj.id === id) };
153
+ const entries = sync.map(s => new BucketCacheEntry(s.obj, s.updateEpoch, datetime_1.NesoiDatetime.now().epoch));
154
+ await this.innerAdapter.putMany(trx, entries);
155
+ return { action: 'update', sync: entries.find(e => e.id === id) };
122
156
  }
123
157
  async syncAll(trx) {
124
158
  const sync = await this.outerAdapter.syncAll(trx, this.lastHash, this.lastUpdateEpoch);
125
159
  if (sync === null) {
126
160
  const all = await this.innerAdapter.index(trx);
127
- return { action: 'keep', sync: all };
161
+ return { action: 'none', sync: all };
128
162
  }
129
163
  this.lastUpdateEpoch = sync.updateEpoch;
130
164
  this.lastHash = sync.hash;
131
165
  this.lastSyncEpoch = datetime_1.NesoiDatetime.now().epoch;
132
- const entries = sync.sync.map(s => new BucketCacheEntry(s.obj.id, s.obj, s.updateEpoch, this.lastSyncEpoch));
166
+ const entries = sync.sync.map(s => new BucketCacheEntry(s.obj, s.updateEpoch, this.lastSyncEpoch));
133
167
  if (sync.reset) {
134
168
  await this.innerAdapter.deleteEverything(trx);
135
169
  await this.innerAdapter.putMany(trx, entries);
136
- return { action: 'reset', sync: sync.sync };
170
+ return { action: 'reset', sync: entries };
137
171
  }
138
172
  await this.innerAdapter.putMany(trx, entries);
139
- return { action: 'update', sync: sync.sync };
173
+ return { action: 'update', sync: entries };
140
174
  }
141
- async syncQuery(trx, view, query, pagination) {
175
+ async syncQuery(trx, query, pagination, params) {
142
176
  // 1. Query id and epoch from outer adapter
143
- const outerMetadata = await this.outerAdapter.query(trx, query, pagination, undefined, {
177
+ const outerMetadata = await this.outerAdapter.query(trx, query, pagination, params, {
144
178
  metadataOnly: true
145
179
  });
146
180
  if (!outerMetadata.data.length) {
147
- return { action: 'keep', sync: [] };
181
+ return { action: 'none', sync: [] };
148
182
  }
149
183
  // 2. Read ids from the inner adapter
150
184
  const innerData = await this.innerAdapter.query(trx, {
151
185
  'id in': outerMetadata.data.map(obj => obj.id)
152
- });
186
+ }, undefined, undefined, undefined, this.innerAdapter.nql);
153
187
  // 3. Filter modified query results
154
188
  const outerEpoch = {};
155
189
  for (const i in outerMetadata.data) {
@@ -159,18 +193,18 @@ class BucketCache {
159
193
  const queryResults = {};
160
194
  const modifiedIds = [];
161
195
  for (const i in innerData.data) {
162
- const obj = innerData.data[i];
163
- const epoch = outerEpoch[obj.id];
164
- if (!epoch || epoch > obj.updateEpoch) {
165
- modifiedIds.push(obj.id);
196
+ const entry = innerData.data[i];
197
+ const epoch = outerEpoch[entry.id];
198
+ if (!epoch || epoch > entry.__update_epoch) {
199
+ modifiedIds.push(entry.id);
166
200
  }
167
201
  else {
168
- queryResults[obj.id] = obj;
202
+ queryResults[entry.id] = entry;
169
203
  }
170
204
  }
171
205
  // 4. Nothing changed, return current data
172
206
  if (!modifiedIds.length) {
173
- return { action: 'keep', sync: innerData.data };
207
+ return { action: 'none', sync: innerData.data };
174
208
  }
175
209
  // 5. Query modified objects to outer adapter and merge them on results
176
210
  const outerData = await this.outerAdapter.query(trx, {
@@ -184,7 +218,7 @@ class BucketCache {
184
218
  updateEpoch
185
219
  };
186
220
  }
187
- return { action: 'update', sync: Object.values(queryResults) };
221
+ return { action: 'update', sync: Object.values(queryResults).map(r => new BucketCacheEntry(r.obj, r.updateEpoch, datetime_1.NesoiDatetime.now().epoch)) };
188
222
  }
189
223
  }
190
224
  exports.BucketCache = BucketCache;
@@ -22,6 +22,17 @@ export declare class BucketGraph<M extends $Module, $ extends $Bucket> {
22
22
  silent?: boolean;
23
23
  no_tenancy?: boolean;
24
24
  }): Promise<Obj | Obj[] | undefined>;
25
+ /**
26
+ * Read the data from a link
27
+ *
28
+ * - Options
29
+ * - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
30
+ * - `no_tenancy`: Don't apply tenancy rules (default: `false`)
31
+ */
32
+ readManyLinks<LinkName extends keyof $['graph']['links'], LinkBucketName extends $['graph']['links'][LinkName]['bucket']['refName'], LinkBucket extends M['buckets'][LinkBucketName], Obj = LinkBucket['#data']>(trx: AnyTrxNode, objs: $['#data'][], link: LinkName, options?: {
33
+ silent?: boolean;
34
+ no_tenancy?: boolean;
35
+ }): Promise<Obj[] | Obj[][]>;
25
36
  /**
26
37
  * Read the data from a link and build it with a given view
27
38
  *
@@ -4,6 +4,8 @@ exports.BucketGraph = void 0;
4
4
  const trx_node_1 = require("../../../../engine/transaction/trx_node");
5
5
  const log_1 = require("../../../../engine/util/log");
6
6
  const error_1 = require("../../../../engine/data/error");
7
+ const memory_bucket_adapter_1 = require("../adapters/memory.bucket_adapter");
8
+ const bucket_cache_1 = require("../cache/bucket_cache");
7
9
  /**
8
10
  * @category Elements
9
11
  * @subcategory Entity
@@ -30,12 +32,13 @@ class BucketGraph {
30
32
  : this.bucket.getTenancyQuery(trx);
31
33
  // Query
32
34
  const otherBucket = trx_node_1.TrxNode.getModule(trx).buckets[schema.bucket.refName];
33
- const links = await otherBucket.adapter.query(trx, {
35
+ const adapter = otherBucket.cache || otherBucket.adapter;
36
+ const links = await adapter.query(trx, {
34
37
  ...schema.query,
35
38
  '#and': tenancy
36
39
  }, {
37
40
  perPage: schema.many ? undefined : 1,
38
- }, { ...obj });
41
+ }, [{ ...obj }]);
39
42
  // Empty response
40
43
  if (!schema.many && !schema.optional && !links.data.length) {
41
44
  // silent = undefined
@@ -57,6 +60,57 @@ class BucketGraph {
57
60
  return links.data[0];
58
61
  }
59
62
  }
63
+ /**
64
+ * Read the data from a link
65
+ *
66
+ * - Options
67
+ * - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
68
+ * - `no_tenancy`: Don't apply tenancy rules (default: `false`)
69
+ */
70
+ async readManyLinks(trx, objs, link, options) {
71
+ log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
72
+ const schema = this.schema.links[link];
73
+ // Make tenancy query
74
+ const tenancy = (options?.no_tenancy)
75
+ ? undefined
76
+ : this.bucket.getTenancyQuery(trx);
77
+ // Query
78
+ const otherBucket = trx_node_1.TrxNode.getModule(trx).buckets[schema.bucket.refName];
79
+ // let tempData: Record<string, any> = {};
80
+ let tempAdapter;
81
+ if (otherBucket.adapter instanceof memory_bucket_adapter_1.MemoryBucketAdapter) {
82
+ tempAdapter = otherBucket.cache || otherBucket.adapter;
83
+ }
84
+ else {
85
+ const adapter = otherBucket.cache || otherBucket.adapter;
86
+ const allLinks = await adapter.query(trx, {
87
+ ...schema.query,
88
+ '#and': tenancy
89
+ }, undefined, objs.map(obj => ({ ...obj })));
90
+ const tempData = {};
91
+ for (const obj of allLinks.data)
92
+ tempData[obj.id] = obj;
93
+ tempAdapter = new memory_bucket_adapter_1.MemoryBucketAdapter(otherBucket.schema, tempData);
94
+ }
95
+ const links = [];
96
+ for (const obj of objs) {
97
+ const result = tempAdapter instanceof bucket_cache_1.BucketCache
98
+ ? await tempAdapter.query(trx, schema.query, {
99
+ perPage: schema.many ? undefined : 1,
100
+ }, [{ ...obj }], undefined)
101
+ : await tempAdapter.query(trx, schema.query, {
102
+ perPage: schema.many ? undefined : 1,
103
+ }, [{ ...obj }], undefined, tempAdapter.nql);
104
+ if (schema.many) {
105
+ links.push(result.data);
106
+ }
107
+ else {
108
+ links.push(result.data[0]);
109
+ }
110
+ }
111
+ // Empty response
112
+ return links;
113
+ }
60
114
  /**
61
115
  * Read the data from a link and build it with a given view
62
116
  *
@@ -102,7 +156,7 @@ class BucketGraph {
102
156
  '#and': tenancy
103
157
  }, {
104
158
  perPage: 1,
105
- }, { ...obj });
159
+ }, [{ ...obj }]);
106
160
  return !!links.data.length;
107
161
  }
108
162
  }
@@ -55,7 +55,6 @@ class $BucketModel {
55
55
  }
56
56
  // If it's a list or dict, or an object
57
57
  if (field.type === 'list' || field.type === 'dict') {
58
- // If not, iterate
59
58
  next.push({
60
59
  i: item.i + 1,
61
60
  field: field.children['#']
@@ -70,6 +69,10 @@ class $BucketModel {
70
69
  })));
71
70
  continue;
72
71
  }
72
+ if (field.type === 'unknown') {
73
+ results.push(field);
74
+ continue;
75
+ }
73
76
  const child = field.children[path];
74
77
  if (child) {
75
78
  next.push({
@@ -127,53 +130,53 @@ class $BucketModel {
127
130
  while (poll.length) {
128
131
  const next = [];
129
132
  for (const entry of poll) {
130
- const val = obj[entry.path];
133
+ const val = entry.obj[entry.path];
131
134
  if (val === undefined) {
132
135
  continue;
133
136
  }
134
137
  if (val === null) {
135
- copy[entry.path] = null;
138
+ entry.copy[entry.path] = null;
136
139
  continue;
137
140
  }
138
141
  if (entry.field.type === 'list') {
139
142
  if (!Array.isArray(val))
140
143
  continue;
141
- copy[entry.path] = [];
144
+ entry.copy[entry.path] = [];
142
145
  next.push(...val.map((_, i) => ({
143
146
  path: i.toString(),
144
147
  obj: val,
145
- copy: copy[entry.path],
146
- field: entry.field.children['*']
148
+ copy: entry.copy[entry.path],
149
+ field: entry.field.children['#']
147
150
  })));
148
151
  }
149
152
  else if (entry.field.type === 'dict') {
150
153
  if (typeof val !== 'object' || Array.isArray(val))
151
154
  continue;
152
- copy[entry.path] = {};
155
+ entry.copy[entry.path] = {};
153
156
  next.push(...Object.keys(val).map((path) => ({
154
157
  path,
155
158
  obj: val,
156
- copy: copy[entry.path],
157
- field: entry.field.children['*']
159
+ copy: entry.copy[entry.path],
160
+ field: entry.field.children['#']
158
161
  })));
159
162
  }
160
163
  else if (entry.field.type === 'obj') {
161
164
  if (typeof val !== 'object' || Array.isArray(val))
162
165
  continue;
163
- copy[entry.path] = {};
166
+ entry.copy[entry.path] = {};
164
167
  next.push(...Object.keys(entry.field.children).map(path => ({
165
168
  path: path,
166
169
  obj: val,
167
- copy: copy[entry.path],
170
+ copy: entry.copy[entry.path],
168
171
  field: entry.field.children[path]
169
172
  })));
170
173
  }
171
174
  else if (entry.field.type === 'union') {
172
175
  // TODO: ??????????
173
- copy[entry.path] = obj[entry.path];
176
+ entry.copy[entry.path] = entry.obj[entry.path];
174
177
  }
175
178
  else {
176
- copy[entry.path] = obj[entry.path];
179
+ entry.copy[entry.path] = entry.obj[entry.path];
177
180
  }
178
181
  }
179
182
  poll = next;
@@ -2,7 +2,6 @@ import { $Module, $Space } from "../../../../schema";
2
2
  import { $BucketModelField, $BucketModelFieldType, $BucketModelFields } from './bucket_model.schema';
3
3
  import { NesoiDate } from "../../../../engine/data/date";
4
4
  import { BucketModelpathObjInfer, BucketModelpathDictInfer, BucketModelpathListInfer, BucketModelObjInfer, BucketQuerypathDictInfer, BucketQuerypathListInfer, BucketQuerypathObjInfer, BucketModelpathUnionInfer } from './bucket_model.infer';
5
- import { EnumFromName, EnumName } from '../../constants/constants.schema';
6
5
  import { NesoiDecimal } from "../../../../engine/data/decimal";
7
6
  import { NesoiDatetime } from "../../../../engine/data/datetime";
8
7
  import { NesoiFile } from "../../../../engine/data/file";
@@ -49,10 +48,10 @@ export declare class BucketModelFieldFactory<Space extends $Space, Module extend
49
48
  }, {
50
49
  '': NesoiDecimal;
51
50
  }>;
52
- enum<Enums extends EnumName<Space>, Options extends (keyof Enums & string) | (readonly string[])>(options: Options): BucketModelFieldBuilder<Module, Options extends string ? keyof EnumFromName<Space, Options>["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options], Options extends string ? keyof EnumFromName<Space, Options>["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options], [false, false], {
53
- '': Options extends string ? keyof EnumFromName<Space, Options>["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options];
51
+ enum<Enums extends Module['constants']['enums'], Options extends (keyof Enums & string) | (readonly string[])>(options: Options): BucketModelFieldBuilder<Module, Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options], Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options], [false, false], {
52
+ '': Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options];
54
53
  }, {
55
- '': Options extends string ? keyof EnumFromName<Space, Options>["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options];
54
+ '': Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options];
56
55
  }>;
57
56
  get int(): BucketModelFieldBuilder<Module, number, number, [false, false], {
58
57
  '': number;
@@ -91,6 +91,8 @@ class NQL_RuleTree {
91
91
  let by = value['by'];
92
92
  if (by) {
93
93
  for (const key of by) {
94
+ if (Object.values(bucket.adapter.config.meta).includes(key))
95
+ continue;
94
96
  const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, key);
95
97
  if (!fields.length) {
96
98
  throw new Error(`Field '${key}' not found on bucket '${bucket.schema.name}'`);
@@ -148,6 +150,10 @@ class NQL_RuleTree {
148
150
  throw new Error(`Invalid term '${key}'`);
149
151
  }
150
152
  const [_, or, fieldpath, not, case_i, op] = term;
153
+ if (Object.values(bucket.adapter.config.meta).includes(fieldpath)) {
154
+ const _op = this.parseOp(bucket.schema.name, [{ type: 'datetime', name: fieldpath }], op);
155
+ return { type: 'fieldpath', or: !!or, fieldpath, not: !!not, case_i: !!case_i, op: _op };
156
+ }
151
157
  const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, fieldpath);
152
158
  if (!fields.length) {
153
159
  throw new Error(`Field '${fieldpath}' not found on bucket '${bucket.schema.name}'`);
@@ -242,7 +248,7 @@ class NQL_RuleTree {
242
248
  };
243
249
  for (const key in value) {
244
250
  if (key.startsWith('@') || key.startsWith('or @')) {
245
- const refField = key.match(/(or )?@(\w+)\.(.*)/);
251
+ const refField = key.match(/(or )?@([\w:]+)\.(.*)/);
246
252
  if (!refField) {
247
253
  throw new Error(`Invalid bucket field '${key}'`);
248
254
  }
@@ -15,7 +15,7 @@ export type NQL_Result<T = Obj> = {
15
15
  * @category NQL
16
16
  * */
17
17
  export declare abstract class NQLRunner {
18
- abstract run(trx: AnyTrxNode, part: NQL_Part, params: Record<string, any>, pagination?: NQL_Pagination, view?: $BucketView): Promise<NQL_Result>;
18
+ abstract run(trx: AnyTrxNode, part: NQL_Part, params: Record<string, any>[], pagination?: NQL_Pagination, view?: $BucketView): Promise<NQL_Result>;
19
19
  }
20
20
  /**
21
21
  * @category NQL
@@ -24,7 +24,7 @@ export declare class NQL_Engine {
24
24
  private module;
25
25
  private runners;
26
26
  constructor(module: AnyModule);
27
- run(trx: AnyTrxNode, query: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>, view?: $BucketView): Promise<NQL_Result>;
27
+ run(trx: AnyTrxNode, query: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], view?: $BucketView, runner?: NQLRunner): Promise<NQL_Result>;
28
28
  linkExternal(bucket: AnyBucket): void;
29
29
  }
30
30
  export {};
@@ -22,7 +22,9 @@ class NQL_Engine {
22
22
  }
23
23
  }
24
24
  }
25
- async run(trx, query, pagination, params = {}, view) {
25
+ async run(trx, query, pagination, params = [{}], view, runner) {
26
+ if (!params.length)
27
+ params = [{}];
26
28
  let result = {
27
29
  data: []
28
30
  };
@@ -30,8 +32,8 @@ class NQL_Engine {
30
32
  const part_i = query.execOrder[i];
31
33
  const part = query.parts[part_i];
32
34
  // Run part
33
- const runner = this.runners[part.union.meta.scope];
34
- const out = await runner.run(trx, part, params, pagination, view);
35
+ const _runner = runner || this.runners[part.union.meta.scope];
36
+ const out = await _runner.run(trx, part, params, pagination, view);
35
37
  result = out;
36
38
  // Part failed, return
37
39
  // Failure here is only when a single value is expected,
@@ -43,7 +45,9 @@ class NQL_Engine {
43
45
  }
44
46
  }
45
47
  // Fill part params
46
- params[`%__${part_i}__%`] = part.many ? result.data : result.data[0];
48
+ for (const paramGroup of params) {
49
+ paramGroup[`%__${part_i}__%`] = part.many ? result.data : result.data[0];
50
+ }
47
51
  }
48
52
  return result;
49
53
  }