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.
- package/lib/elements/edge/controller/adapters/controller_adapter.d.ts +4 -1
- package/lib/elements/edge/controller/adapters/controller_adapter.js +8 -4
- package/lib/elements/edge/controller/controller.js +3 -3
- package/lib/elements/edge/controller/controller.schema.d.ts +2 -1
- package/lib/elements/edge/controller/controller.schema.js +3 -1
- package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +25 -3
- package/lib/elements/entities/bucket/adapters/bucket_adapter.js +21 -2
- package/lib/elements/entities/bucket/adapters/memory.nql.js +80 -44
- package/lib/elements/entities/bucket/adapters/test.bucket_adapter.d.ts +22 -0
- package/lib/elements/entities/bucket/adapters/test.bucket_adapter.js +23 -0
- package/lib/elements/entities/bucket/bucket.js +2 -2
- package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +16 -1
- package/lib/elements/entities/bucket/cache/bucket_cache.js +36 -15
- package/lib/elements/entities/bucket/graph/bucket_graph.js +28 -18
- package/lib/elements/entities/bucket/query/nql.schema.d.ts +3 -0
- package/lib/elements/entities/bucket/query/nql_compiler.d.ts +10 -4
- package/lib/elements/entities/bucket/query/nql_compiler.js +42 -35
- package/lib/elements/entities/bucket/query/nql_engine.d.ts +4 -1
- package/lib/elements/entities/bucket/query/nql_engine.js +3 -5
- package/lib/elements/entities/message/template/message_template_field.builder.d.ts +2 -0
- package/lib/elements/entities/message/template/message_template_field.builder.js +5 -0
- package/lib/engine/daemon.d.ts +19 -0
- package/lib/engine/daemon.js +40 -2
- package/lib/engine/data/tree.d.ts +1 -2
- package/lib/engine/data/tree.js +6 -94
- package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +1 -1
- package/lib/engine/transaction/nodes/bucket.trx_node.js +15 -15
- package/lib/engine/transaction/nodes/bucket_query.trx_node.js +2 -2
- package/lib/engine/transaction/nodes/external.trx_node.d.ts +3 -1
- package/lib/engine/transaction/nodes/external.trx_node.js +54 -4
- package/lib/engine/transaction/nodes/job.trx_node.js +3 -2
- package/lib/engine/transaction/nodes/machine.trx_node.js +1 -1
- package/lib/engine/transaction/nodes/queue.trx_node.js +1 -1
- package/lib/engine/transaction/nodes/resource.trx_node.js +1 -1
- package/lib/engine/transaction/nodes/topic.trx_node.js +1 -1
- package/lib/engine/transaction/trx.d.ts +7 -1
- package/lib/engine/transaction/trx.js +15 -1
- package/lib/engine/transaction/trx_engine.config.d.ts +6 -1
- package/lib/engine/transaction/trx_engine.d.ts +5 -5
- package/lib/engine/transaction/trx_engine.js +59 -36
- package/lib/engine/transaction/trx_node.d.ts +1 -1
- package/lib/engine/transaction/trx_node.js +1 -1
- package/package.json +1 -1
- 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 {
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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
|
|
48
|
-
|
|
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(
|
|
60
|
+
async parseUnion(meta, query, select) {
|
|
60
61
|
const union = {
|
|
61
62
|
meta: {
|
|
62
|
-
...
|
|
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(
|
|
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,
|
|
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: { ...
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 '${
|
|
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(
|
|
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 =
|
|
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 ${
|
|
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(
|
|
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(
|
|
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 '${
|
|
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
|
|
296
|
-
if (!
|
|
297
|
-
throw new Error(`Bucket '${
|
|
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
|
-
|
|
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 '${
|
|
305
|
+
throw new Error(`Field '${fieldpath}' not found on bucket '${subMeta.schema.name}'`);
|
|
302
306
|
}
|
|
303
|
-
|
|
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:
|
|
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,
|
|
516
|
-
const tree = new NQL_RuleTree(daemon, module, bucketName, query,
|
|
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,
|
|
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,
|
|
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
|
|
39
|
-
|
|
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);
|
package/lib/engine/daemon.d.ts
CHANGED
|
@@ -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
|
*/
|
package/lib/engine/daemon.js
CHANGED
|
@@ -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
|
|
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
|
}
|
package/lib/engine/data/tree.js
CHANGED
|
@@ -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
|
|
24
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|