nesoi 3.3.20 → 3.3.21

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 (44) hide show
  1. package/lib/elements/edge/controller/adapters/controller_adapter.d.ts +4 -1
  2. package/lib/elements/edge/controller/adapters/controller_adapter.js +8 -4
  3. package/lib/elements/edge/controller/controller.js +3 -3
  4. package/lib/elements/edge/controller/controller.schema.d.ts +2 -1
  5. package/lib/elements/edge/controller/controller.schema.js +3 -1
  6. package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +25 -3
  7. package/lib/elements/entities/bucket/adapters/bucket_adapter.js +21 -2
  8. package/lib/elements/entities/bucket/adapters/memory.nql.js +80 -44
  9. package/lib/elements/entities/bucket/adapters/test.bucket_adapter.d.ts +22 -0
  10. package/lib/elements/entities/bucket/adapters/test.bucket_adapter.js +23 -0
  11. package/lib/elements/entities/bucket/bucket.js +2 -2
  12. package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +16 -1
  13. package/lib/elements/entities/bucket/cache/bucket_cache.js +36 -15
  14. package/lib/elements/entities/bucket/graph/bucket_graph.js +28 -18
  15. package/lib/elements/entities/bucket/query/nql.schema.d.ts +3 -0
  16. package/lib/elements/entities/bucket/query/nql_compiler.d.ts +10 -4
  17. package/lib/elements/entities/bucket/query/nql_compiler.js +42 -35
  18. package/lib/elements/entities/bucket/query/nql_engine.d.ts +4 -1
  19. package/lib/elements/entities/bucket/query/nql_engine.js +3 -5
  20. package/lib/elements/entities/message/template/message_template_field.builder.d.ts +2 -0
  21. package/lib/elements/entities/message/template/message_template_field.builder.js +5 -0
  22. package/lib/engine/daemon.d.ts +19 -0
  23. package/lib/engine/daemon.js +40 -2
  24. package/lib/engine/data/tree.d.ts +1 -2
  25. package/lib/engine/data/tree.js +6 -94
  26. package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +1 -1
  27. package/lib/engine/transaction/nodes/bucket.trx_node.js +15 -15
  28. package/lib/engine/transaction/nodes/bucket_query.trx_node.js +2 -2
  29. package/lib/engine/transaction/nodes/external.trx_node.d.ts +3 -1
  30. package/lib/engine/transaction/nodes/external.trx_node.js +54 -4
  31. package/lib/engine/transaction/nodes/job.trx_node.js +3 -2
  32. package/lib/engine/transaction/nodes/machine.trx_node.js +1 -1
  33. package/lib/engine/transaction/nodes/queue.trx_node.js +1 -1
  34. package/lib/engine/transaction/nodes/resource.trx_node.js +1 -1
  35. package/lib/engine/transaction/nodes/topic.trx_node.js +1 -1
  36. package/lib/engine/transaction/trx.d.ts +7 -1
  37. package/lib/engine/transaction/trx.js +15 -1
  38. package/lib/engine/transaction/trx_engine.config.d.ts +6 -1
  39. package/lib/engine/transaction/trx_engine.d.ts +5 -5
  40. package/lib/engine/transaction/trx_engine.js +59 -36
  41. package/lib/engine/transaction/trx_node.d.ts +1 -1
  42. package/lib/engine/transaction/trx_node.js +1 -1
  43. package/package.json +1 -1
  44. package/tsconfig.build.tsbuildinfo +1 -1
@@ -13,6 +13,7 @@ export type NQL_Union = {
13
13
  inters: NQL_Intersection[];
14
14
  sort?: {
15
15
  key: string;
16
+ key_is_deep: boolean;
16
17
  dir: ('asc' | 'desc');
17
18
  }[];
18
19
  _debug_id?: number;
@@ -25,6 +26,7 @@ export type NQL_Intersection = {
25
26
  export type NQL_Rule = {
26
27
  meta: NQL_QueryMeta;
27
28
  fieldpath: string;
29
+ fieldpath_is_deep: boolean;
28
30
  op: NQL_Operation;
29
31
  case_i: boolean;
30
32
  not: boolean;
@@ -32,6 +34,7 @@ export type NQL_Rule = {
32
34
  static: any | any[];
33
35
  } | {
34
36
  param: string | string[];
37
+ param_is_deep: boolean;
35
38
  } | {
36
39
  param_with_$: string;
37
40
  } | {
@@ -1,6 +1,6 @@
1
1
  import { NQL_AnyQuery, NQL_Union, NQL_Part, NQL_Node } from './nql.schema';
2
2
  import { AnyDaemon } from "../../../../engine/daemon";
3
- import { BucketMetadata } from "../../../../engine/transaction/trx_engine";
3
+ import { NQLRunner } from './nql_engine';
4
4
  /**
5
5
  * @category NQL
6
6
  * */
@@ -9,11 +9,14 @@ export declare class NQL_RuleTree {
9
9
  private module;
10
10
  private bucketName;
11
11
  private query;
12
- private customMetadata?;
12
+ private customBuckets;
13
13
  private debug;
14
14
  private static OpByType;
15
15
  root: NQL_Union;
16
- constructor(daemon: AnyDaemon, module: string, bucketName: string, query: NQL_AnyQuery, customMetadata?: BucketMetadata | undefined, debug?: boolean);
16
+ constructor(daemon: AnyDaemon, module: string, bucketName: string, query: NQL_AnyQuery, customBuckets?: Record<string, {
17
+ scope: string;
18
+ nql: NQLRunner;
19
+ }>, debug?: boolean);
17
20
  parse(): Promise<void>;
18
21
  private parseUnion;
19
22
  private parseSort;
@@ -39,7 +42,10 @@ export declare class NQL_RuleTree {
39
42
  * @category NQL
40
43
  * */
41
44
  export declare class NQL_Compiler {
42
- static build(daemon: AnyDaemon, module: string, bucketName: string, query: NQL_AnyQuery, customMetadata?: BucketMetadata): Promise<NQL_CompiledQuery>;
45
+ static build(daemon: AnyDaemon, module: string, bucketName: string, query: NQL_AnyQuery, customBuckets?: Record<string, {
46
+ scope: string;
47
+ nql: NQLRunner;
48
+ }>): Promise<NQL_CompiledQuery>;
43
49
  static buildTree(tree: NQL_RuleTree): Promise<NQL_CompiledQuery>;
44
50
  }
45
51
  /**
@@ -13,7 +13,7 @@ class NQL_RuleTree {
13
13
  module;
14
14
  bucketName;
15
15
  query;
16
- customMetadata;
16
+ customBuckets;
17
17
  debug;
18
18
  static OpByType = {
19
19
  'boolean': ['==', 'in', 'present'],
@@ -34,18 +34,19 @@ class NQL_RuleTree {
34
34
  'unknown': ['==', 'contains', 'contains_any', 'in', 'present']
35
35
  };
36
36
  root;
37
- constructor(daemon, module, bucketName, query, customMetadata, debug = false) {
37
+ constructor(daemon, module, bucketName, query, customBuckets = {}, debug = false) {
38
38
  this.daemon = daemon;
39
39
  this.module = module;
40
40
  this.bucketName = bucketName;
41
41
  this.query = query;
42
- this.customMetadata = customMetadata;
42
+ this.customBuckets = customBuckets;
43
43
  this.debug = debug;
44
44
  }
45
45
  async parse() {
46
46
  const tag = dependency_1.Tag.fromNameOrShort(this.module, 'bucket', this.bucketName);
47
- const bucket = this.customMetadata || await daemon_1.Daemon.getBucketMetadata(this.daemon, tag);
48
- this.root = await this.parseUnion(bucket, this.query);
47
+ const meta = await daemon_1.Daemon.getBucketMetadata(this.daemon, tag);
48
+ meta.scope = this.customBuckets[tag.short]?.scope || meta.scope;
49
+ this.root = await this.parseUnion(meta, this.query);
49
50
  if (this.debug) {
50
51
  console.log(this.describe());
51
52
  }
@@ -56,10 +57,10 @@ class NQL_RuleTree {
56
57
  }
57
58
  }
58
59
  // Parse NQL
59
- async parseUnion(bucket, query, select) {
60
+ async parseUnion(meta, query, select) {
60
61
  const union = {
61
62
  meta: {
62
- ...bucket,
63
+ ...meta,
63
64
  avgTime: 0
64
65
  },
65
66
  inters: [
@@ -68,16 +69,17 @@ class NQL_RuleTree {
68
69
  };
69
70
  for (const key in query) {
70
71
  const value = query[key];
71
- const parsedKey = await this.parseKey(bucket, key);
72
+ const parsedKey = await this.parseKey(meta, key);
72
73
  // Fieldpath term -> Condition
73
74
  if (parsedKey.type === 'fieldpath') {
74
- const parsed = await this.parseValue(value, parsedKey, bucket, select);
75
+ const parsed = await this.parseValue(value, parsedKey, meta, select);
75
76
  const rule = ('subquery' in parsed)
76
77
  ? parsed.subquery.union
77
78
  : {
78
- meta: { ...bucket },
79
+ meta: { ...meta },
79
80
  select,
80
81
  fieldpath: parsedKey.fieldpath,
82
+ fieldpath_is_deep: parsedKey.fieldpath.includes('.'),
81
83
  value: parsed,
82
84
  op: parsedKey.op,
83
85
  case_i: parsedKey.case_i,
@@ -102,15 +104,15 @@ class NQL_RuleTree {
102
104
  throw new Error('Graph Link not supported yet');
103
105
  }
104
106
  else if (parsedKey.type === 'and') {
105
- const subInter = await this.parseUnion(bucket, value, select);
107
+ const subInter = await this.parseUnion(meta, value, select);
106
108
  union.inters[0].rules.push(subInter);
107
109
  }
108
110
  else if (parsedKey.type === 'or') {
109
- const subInter = await this.parseUnion(bucket, value, select);
111
+ const subInter = await this.parseUnion(meta, value, select);
110
112
  union.inters.push({ meta: {}, rules: [subInter] });
111
113
  }
112
114
  else if (parsedKey.type === 'sort') {
113
- union.sort = await this.parseSort(bucket, value);
115
+ union.sort = await this.parseSort(meta, value);
114
116
  }
115
117
  }
116
118
  if (!union.inters[0]?.rules.length) {
@@ -118,7 +120,7 @@ class NQL_RuleTree {
118
120
  }
119
121
  return union;
120
122
  }
121
- parseSort(bucket, value) {
123
+ parseSort(meta, value) {
122
124
  if (!Array.isArray(value))
123
125
  value = [value];
124
126
  if (value.some(v => typeof v !== 'string')) {
@@ -138,11 +140,11 @@ class NQL_RuleTree {
138
140
  else {
139
141
  throw new Error(`Invalid query sort direction '${key}', string must end with '@asc' or '@desc'`);
140
142
  }
141
- const is_metadata_field = Object.values(bucket.meta).includes(key);
143
+ const is_metadata_field = Object.values(meta.meta).includes(key);
142
144
  if (!is_metadata_field) {
143
- const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, key);
145
+ const fields = bucket_model_schema_1.$BucketModel.getField(meta.schema.model, key);
144
146
  if (!fields.length) {
145
- throw new Error(`Field '${key}' not found on bucket '${bucket.schema.name}'`);
147
+ throw new Error(`Field '${key}' not found on bucket '${meta.schema.name}'`);
146
148
  }
147
149
  for (const field of fields) {
148
150
  if (![
@@ -154,12 +156,13 @@ class NQL_RuleTree {
154
156
  }
155
157
  sort.push({
156
158
  key,
159
+ key_is_deep: key.includes('.'),
157
160
  dir: vdir
158
161
  });
159
162
  }
160
163
  return sort;
161
164
  }
162
- async parseKey(bucket, key) {
165
+ async parseKey(meta, key) {
163
166
  if (key === '#sort') {
164
167
  return { type: 'sort' };
165
168
  }
@@ -171,9 +174,9 @@ class NQL_RuleTree {
171
174
  }
172
175
  else if (key.startsWith('*')) {
173
176
  const linkName = key.slice(1);
174
- const link = bucket.schema.graph.links[linkName];
177
+ const link = meta.schema.graph.links[linkName];
175
178
  if (!link) {
176
- throw new Error(`Graph Link '${linkName}' doesn't exist on the bucket ${bucket}`);
179
+ throw new Error(`Graph Link '${linkName}' doesn't exist on the bucket ${meta}`);
177
180
  }
178
181
  const linkBucket = await daemon_1.Daemon.getBucketMetadata(this.daemon, link.bucket);
179
182
  return { type: 'graphlink', link: link.name, linkBucket: linkBucket.schema };
@@ -184,13 +187,13 @@ class NQL_RuleTree {
184
187
  throw new Error(`Invalid term '${key}'`);
185
188
  }
186
189
  const [_, or, fieldpath, not, case_i, op] = term;
187
- if (Object.values(bucket.meta).includes(fieldpath)) {
190
+ if (Object.values(meta.meta).includes(fieldpath)) {
188
191
  const _op = this.parseOp([{ type: 'datetime', name: fieldpath }], op);
189
192
  return { type: 'fieldpath', or: !!or, fieldpath, not: !!not, case_i: !!case_i, op: _op };
190
193
  }
191
- const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, fieldpath);
194
+ const fields = bucket_model_schema_1.$BucketModel.getField(meta.schema.model, fieldpath);
192
195
  if (!fields.length) {
193
- throw new Error(`Field '${fieldpath}' not found on bucket '${bucket.schema.name}'`);
196
+ throw new Error(`Field '${fieldpath}' not found on bucket '${meta.schema.name}'`);
194
197
  }
195
198
  const _op = this.parseOp(fields, op);
196
199
  return { type: 'fieldpath', or: !!or, fieldpath, not: !!not, case_i: !!case_i, op: _op };
@@ -253,7 +256,7 @@ class NQL_RuleTree {
253
256
  throw new Error(`Cannot mix static and parameter values inside array value [${value}]`);
254
257
  }
255
258
  if (params.length > 0) {
256
- return { param: params };
259
+ return { param: params, param_is_deep: params.some(p => p.includes('.')) };
257
260
  }
258
261
  else {
259
262
  return { static: statyc };
@@ -262,7 +265,7 @@ class NQL_RuleTree {
262
265
  else {
263
266
  // Parameter
264
267
  if ('.' in value) {
265
- return { param: value['.'] };
268
+ return { param: value['.'], param_is_deep: value['.'].includes('.') };
266
269
  }
267
270
  // Path Parameter
268
271
  else if ('$' in value) {
@@ -292,24 +295,28 @@ class NQL_RuleTree {
292
295
  }
293
296
  const [_, or, refBucket, fieldpath] = refField;
294
297
  const tag = dependency_1.Tag.fromNameOrShort(this.module, 'bucket', refBucket);
295
- const bucket = await daemon_1.Daemon.getBucketMetadata(this.daemon, tag);
296
- if (!bucket) {
297
- throw new Error(`Bucket '${bucket}' not found on module`);
298
+ const subMeta = await daemon_1.Daemon.getBucketMetadata(this.daemon, tag);
299
+ if (!subMeta) {
300
+ throw new Error(`Bucket '${subMeta}' not found on module`);
298
301
  }
299
- const field = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, fieldpath);
302
+ subMeta.scope = this.customBuckets[tag.short]?.scope || subMeta.scope;
303
+ const field = bucket_model_schema_1.$BucketModel.getField(subMeta.schema.model, fieldpath);
300
304
  if (!field) {
301
- throw new Error(`Field '${fieldpath}' not found on bucket '${bucket.schema.name}'`);
305
+ throw new Error(`Field '${fieldpath}' not found on bucket '${subMeta.schema.name}'`);
302
306
  }
303
- const refInter = await this.parseUnion(bucket, value[key], fieldpath);
307
+ // The union belongs to the sub scope.
308
+ const refInter = await this.parseUnion(subMeta, value[key], fieldpath);
304
309
  const rule = {
310
+ // This rule belongs to the parent scope.
305
311
  meta: { ...meta },
306
312
  select,
307
313
  fieldpath: parsedKey.fieldpath,
314
+ fieldpath_is_deep: parsedKey.fieldpath.includes('.'),
308
315
  case_i: parsedKey.case_i,
309
316
  not: parsedKey.not,
310
317
  op: parsedKey.op,
311
318
  value: {
312
- subquery: { union: refInter, bucket: bucket.schema, select: fieldpath }
319
+ subquery: { union: refInter, bucket: subMeta.schema, select: fieldpath }
313
320
  }
314
321
  };
315
322
  if (!or) {
@@ -512,8 +519,8 @@ exports.NQL_RuleTree = NQL_RuleTree;
512
519
  * @category NQL
513
520
  * */
514
521
  class NQL_Compiler {
515
- static async build(daemon, module, bucketName, query, customMetadata) {
516
- const tree = new NQL_RuleTree(daemon, module, bucketName, query, customMetadata);
522
+ static async build(daemon, module, bucketName, query, customBuckets = {}) {
523
+ const tree = new NQL_RuleTree(daemon, module, bucketName, query, customBuckets);
517
524
  return this.buildTree(tree);
518
525
  }
519
526
  static async buildTree(tree) {
@@ -659,7 +666,7 @@ class NQL_Compiler {
659
666
  // Close part (&1)
660
667
  if (rule.part) {
661
668
  // Rebuild Union on original tree as Condition
662
- buildNode.value = { param: `%__${rule.part}__%` };
669
+ buildNode.value = { param: `%__${rule.part}__%`, param_is_deep: false };
663
670
  if (rule.part == partStack.at(-1).i) {
664
671
  // debugLog.push('⊙ [part] ' + rule.part);
665
672
  orderedParts.push(parts[rule.part]);
@@ -24,7 +24,10 @@ 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>[], param_templates?: Record<string, string>[], view?: $BucketView, customRunners?: Record<string, NQLRunner>): Promise<NQL_Result>;
27
+ run(trx: AnyTrxNode, query: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], view?: $BucketView, customBuckets?: Record<string, {
28
+ scope: string;
29
+ nql: NQLRunner;
30
+ }>): Promise<NQL_Result>;
28
31
  linkExternal(bucket: AnyBucket): void;
29
32
  }
30
33
  export {};
@@ -23,7 +23,7 @@ class NQL_Engine {
23
23
  }
24
24
  }
25
25
  }
26
- async run(trx, query, pagination, params = [{}], param_templates = [], view, customRunners) {
26
+ async run(trx, query, pagination, params = [{}], param_templates = [], view, customBuckets) {
27
27
  if (!params.length)
28
28
  params = [{}];
29
29
  if (!param_templates.length)
@@ -35,10 +35,8 @@ class NQL_Engine {
35
35
  const part_i = query.execOrder[i];
36
36
  const part = query.parts[part_i];
37
37
  // Run part
38
- const runners = customRunners
39
- ? { ...this.runners, ...customRunners }
40
- : this.runners;
41
- const _runner = runners[part.union.meta.scope];
38
+ const _runner = Object.values(customBuckets || {}).find(b => b.scope === part.union.meta.scope)?.nql
39
+ || this.runners[part.union.meta.scope];
42
40
  const out = await _runner.run(trx, part, params, param_templates, pagination, view);
43
41
  result = out;
44
42
  // Part failed, return
@@ -70,6 +70,7 @@ export declare class MessageTemplateFieldBuilder<Module extends $Module, Message
70
70
  private _required;
71
71
  private _defaultValue?;
72
72
  private _nullable;
73
+ private _rawName?;
73
74
  private _rules;
74
75
  constructor(type: $MessageTemplateFieldType, meta: Omit<$MessageTemplateFieldMeta, 'enum' | 'msg' | 'id'> & {
75
76
  enum?: {
@@ -97,6 +98,7 @@ export declare class MessageTemplateFieldBuilder<Module extends $Module, Message
97
98
  ], InputSuffix>;
98
99
  get nullable(): MessageTemplateFieldBuilder<Module, Message, Input | null, Output | null, Children, Optional, InputSuffix>;
99
100
  rule(rule: MessageTemplateRuleDef<Output, Message['#raw']>): this;
101
+ rawName(name: string): this;
100
102
  static build(builder: AnyMessageTemplateFieldBuilder, name: string, tree: ModuleTree, module: $Module, basePathRaw: string, basePathParsed: string): $MessageTemplateField;
101
103
  static buildMany(fields: MessageTemplateFieldBuilders, tree: ModuleTree, module: $Module, basePathRaw?: string, basePathParsed?: string, name?: string, key?: string): $MessageTemplateFields;
102
104
  }
@@ -138,6 +138,7 @@ class MessageTemplateFieldBuilder {
138
138
  _required = true;
139
139
  _defaultValue = undefined;
140
140
  _nullable = false;
141
+ _rawName;
141
142
  _rules = [];
142
143
  constructor(type, meta, alias, children) {
143
144
  this.type = type;
@@ -166,6 +167,10 @@ class MessageTemplateFieldBuilder {
166
167
  this._rules.push(rule);
167
168
  return this;
168
169
  }
170
+ rawName(name) {
171
+ this._rawName = name;
172
+ return this;
173
+ }
169
174
  // Build
170
175
  static build(builder, name, tree, module, basePathRaw, basePathParsed) {
171
176
  const pathRaw = basePathRaw + (builder.type === 'id' ? `${name}_id` : name);
@@ -123,10 +123,29 @@ export declare class DaemonTrx<S extends $Space, M extends $Module, AuthUsers ex
123
123
  * authenticate this transaction prior to running.
124
124
  */
125
125
  private tokens?;
126
+ /**
127
+ *
128
+ */
129
+ private _origin?;
130
+ /**
131
+ * An idempotent transaction doesn't generate a commit/rollback.
132
+ */
133
+ private _idempotent;
126
134
  /**
127
135
  * @param trxEngine The transaction engine where to run the transaction.
128
136
  */
129
137
  constructor(trxEngine: AnyTrxEngine);
138
+ origin(origin: string): this;
139
+ /**
140
+ * Flags this transaction as idempotent.
141
+ * This means its not stored, neither commited/rolled back.
142
+ * This should generally be used for readonly transactions.
143
+ */
144
+ get idempotent(): this;
145
+ /**
146
+ * Inherit authentication from another transaction node.
147
+ */
148
+ idempotent_inherit(trx: AnyTrxNode): this;
130
149
  /**
131
150
  * Inherit authentication from another transaction node.
132
151
  */
@@ -176,12 +176,40 @@ class DaemonTrx {
176
176
  * authenticate this transaction prior to running.
177
177
  */
178
178
  tokens;
179
+ /**
180
+ *
181
+ */
182
+ _origin;
183
+ /**
184
+ * An idempotent transaction doesn't generate a commit/rollback.
185
+ */
186
+ _idempotent = false;
179
187
  /**
180
188
  * @param trxEngine The transaction engine where to run the transaction.
181
189
  */
182
190
  constructor(trxEngine) {
183
191
  this.trxEngine = trxEngine;
184
192
  }
193
+ origin(origin) {
194
+ this._origin = origin;
195
+ return this;
196
+ }
197
+ /**
198
+ * Flags this transaction as idempotent.
199
+ * This means its not stored, neither commited/rolled back.
200
+ * This should generally be used for readonly transactions.
201
+ */
202
+ get idempotent() {
203
+ this._idempotent = true;
204
+ return this;
205
+ }
206
+ /**
207
+ * Inherit authentication from another transaction node.
208
+ */
209
+ idempotent_inherit(trx) {
210
+ this._idempotent = trx.trx.idempotent;
211
+ return this;
212
+ }
185
213
  /**
186
214
  * Inherit authentication from another transaction node.
187
215
  */
@@ -211,7 +239,7 @@ class DaemonTrx {
211
239
  ...this.tokens
212
240
  };
213
241
  const users = inheritedAuth?.users;
214
- return this.trxEngine.trx(fn, id, tokens, users);
242
+ return this.trxEngine.trx(fn, id, tokens, users, this._origin, this._idempotent);
215
243
  }
216
244
  /**
217
245
  * Run a method inside the transaction, and hold it until
@@ -220,13 +248,23 @@ class DaemonTrx {
220
248
  * @param fn A function to execute inside the transaction
221
249
  * @returns A `TrxStatus` containing metadata about the transaction and the function response
222
250
  */
223
- run_and_hold(fn, id) {
251
+ async run_and_hold(fn, id) {
224
252
  const inheritedAuth = this._inherit.auth;
225
253
  const tokens = {
226
254
  ...inheritedAuth?.tokens,
227
255
  ...this.tokens
228
256
  };
229
257
  const users = inheritedAuth?.users;
258
+ // Idempotent transactions are not commited/rolled back, so they don't need to be held.
259
+ if (this._idempotent) {
260
+ const status = await this.trxEngine.trx(fn, id, tokens, users, this._origin, this._idempotent);
261
+ return {
262
+ id: status.id,
263
+ status,
264
+ commit: () => Promise.resolve(),
265
+ rollback: () => Promise.resolve(),
266
+ };
267
+ }
230
268
  return this.trxEngine.trx_hold(fn, id, tokens, users);
231
269
  }
232
270
  }
@@ -13,7 +13,6 @@ export declare class Tree {
13
13
  *
14
14
  * @deprecated Fieldpath was consolidated into Modelpath and Querypath.
15
15
  */
16
- static get(obj: Record<string, any>, fieldpath: string, index?: '*' | 0 | (number | string)[]): any;
17
- static getModelpath(obj: Record<string, any>, modelpath: string, index: (string | number)[]): any[];
16
+ static get(obj: Record<string, any>, fieldpath: string): any;
18
17
  static set(obj: Record<string, any>, fieldpath: string, replacer: (v: any, i: (number | string)[]) => any, __index?: (number | string)[]): void;
19
18
  }
@@ -4,7 +4,6 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Tree = void 0;
7
- const error_1 = require("./error");
8
7
  /**
9
8
  * @category Engine
10
9
  * @subcategory Data
@@ -20,112 +19,25 @@ class Tree {
20
19
  *
21
20
  * @deprecated Fieldpath was consolidated into Modelpath and Querypath.
22
21
  */
23
- static get(obj, fieldpath, index = '*') {
24
- index = (!Array.isArray(index)) ? index : [...index];
22
+ static get(obj, fieldpath) {
23
+ if (!fieldpath.includes('.'))
24
+ return obj[fieldpath];
25
25
  const paths = fieldpath.split('.');
26
- const pathIndexCount = paths.filter(p => p === '#').length;
27
- if (Array.isArray(index) && pathIndexCount > index.length) {
28
- throw error_1.NesoiError.Bucket.Fieldpath.InvalidIndexLength({ fieldpath, index });
29
- }
30
26
  let ref = obj;
31
27
  for (let i = 0; i < paths.length; i++) {
32
28
  const path = paths[i];
33
- if (path === '#') {
34
- // 0 index, read the first item from the list
35
- if (index === 0) {
36
- // This is a TypeAsObj, stay on the node
37
- if (typeof ref === 'object' && '__array' in ref) {
38
- //
39
- }
40
- else {
41
- if (typeof ref !== 'object') {
42
- return undefined;
43
- }
44
- if (Array.isArray(ref)) {
45
- ref = ref[0];
46
- }
47
- else {
48
- ref = ref[Object.keys(ref)[0]];
49
- }
50
- }
51
- }
52
- // Null index, return a list of all items
53
- else if (index === '*') {
54
- if (typeof ref !== 'object') {
55
- return undefined;
56
- }
57
- if (!Array.isArray(ref)) {
58
- ref = Object.values(ref);
59
- }
60
- const childPath = paths.slice(i + 1);
61
- if (childPath.length === 0) {
62
- return ref;
63
- }
64
- const out = [];
65
- ref.forEach((v) => {
66
- const deep = this.get(v, childPath.join('.'), '*');
67
- if (deep !== undefined)
68
- out.push(deep);
69
- });
70
- return out.flat(1);
71
- }
72
- // List of indices, advance on it
73
- else {
74
- const idx = index.shift();
75
- if (idx === undefined) {
76
- return undefined;
77
- }
78
- ref = ref[idx];
79
- }
80
- }
81
- else {
82
- ref = ref?.[path];
83
- }
29
+ ref = ref?.[path];
84
30
  if (ref === undefined) {
85
- return ref;
31
+ return undefined;
86
32
  }
87
33
  }
88
34
  // When reading from a TypeAsObj,
89
35
  // advance on unions
90
36
  if (!ref && '__or' in obj) {
91
- return this.get(obj.__or, fieldpath, index);
37
+ return this.get(obj.__or, fieldpath);
92
38
  }
93
39
  return ref;
94
40
  }
95
- static getModelpath(obj, modelpath, index) {
96
- const paths = modelpath.split('.');
97
- let poll = [obj];
98
- while (poll.length) {
99
- const next = [];
100
- for (const item of poll) {
101
- const path = paths[item.i];
102
- // '*'
103
- if (path === '*') {
104
- if (typeof item !== 'object') {
105
- throw new Error(`Can't read *, item is not object (${item})`);
106
- }
107
- next.push(...Object.values(item));
108
- }
109
- else {
110
- const idx_str = path.match(/^\$(\d+)/)?.[1];
111
- let _path = path;
112
- // $0, $1..
113
- if (idx_str !== undefined) {
114
- const idx = parseInt(idx_str);
115
- if (idx >= index.length) {
116
- throw new Error(`Can't read $${idx}, too few indexes (${index.length})`);
117
- }
118
- _path = index[idx];
119
- }
120
- const n = typeof item === 'object' ? item[_path] : undefined;
121
- if (n)
122
- next.push(n);
123
- }
124
- }
125
- poll = next;
126
- }
127
- return poll;
128
- }
129
41
  static set(obj, fieldpath, replacer, __index = []) {
130
42
  const paths = fieldpath.split('.');
131
43
  class Ptr {
@@ -20,7 +20,7 @@ export declare class BucketTrxNode<M extends $Module, $ extends $Bucket> {
20
20
  private bucket?;
21
21
  constructor(trx: TrxNode<any, M, any>, tag: Tag);
22
22
  get no_tenancy(): this;
23
- wrap(action: string, input: Record<string, any>, fn: (trx: AnyTrxNode, element: Bucket<M, $>) => Promise<any>, fmtTrxOut?: (out: any) => any): Promise<any>;
23
+ wrap(action: string, input: Record<string, any>, fn: (trx: AnyTrxNode, element: Bucket<M, $>) => Promise<any>, fmtTrxOut?: (out: any) => any, idempotent?: boolean): Promise<any>;
24
24
  /**
25
25
  * Returns one object by `id`, without pre-formatting,
26
26
  * or `undefined` if the object was not found.