nesoi 3.3.5 → 3.3.7
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/blocks/job/internal/resource_job.builder.js +3 -1
- package/lib/elements/blocks/resource/resource.builder.js +2 -3
- package/lib/elements/blocks/resource/resource.js +1 -0
- package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +5 -1
- package/lib/elements/entities/bucket/adapters/bucket_adapter.js +6 -2
- package/lib/elements/entities/bucket/adapters/memory.nql.d.ts +1 -1
- package/lib/elements/entities/bucket/adapters/memory.nql.js +55 -35
- package/lib/elements/entities/bucket/bucket.builder.js +1 -1
- package/lib/elements/entities/bucket/bucket.d.ts +4 -0
- package/lib/elements/entities/bucket/bucket.infer.d.ts +7 -7
- package/lib/elements/entities/bucket/bucket.js +14 -9
- package/lib/elements/entities/bucket/bucket.schema.d.ts +1 -1
- package/lib/elements/entities/bucket/cache/bucket_cache.js +3 -3
- package/lib/elements/entities/bucket/graph/bucket_graph.d.ts +13 -3
- package/lib/elements/entities/bucket/graph/bucket_graph.infer.d.ts +1 -1
- package/lib/elements/entities/bucket/graph/bucket_graph.js +23 -13
- package/lib/elements/entities/bucket/graph/bucket_graph_link.builder.d.ts +6 -5
- package/lib/elements/entities/bucket/model/bucket_model.convert.js +4 -4
- package/lib/elements/entities/bucket/query/nql.schema.d.ts +8 -9
- package/lib/elements/entities/bucket/query/nql_compiler.d.ts +1 -1
- package/lib/elements/entities/bucket/query/nql_compiler.js +38 -27
- package/lib/elements/entities/bucket/query/nql_engine.d.ts +2 -2
- package/lib/elements/entities/bucket/query/nql_engine.js +4 -2
- package/lib/elements/entities/bucket/view/bucket_view.builder.d.ts +3 -2
- package/lib/elements/entities/bucket/view/bucket_view.builder.js +3 -3
- package/lib/elements/entities/bucket/view/bucket_view.js +123 -32
- package/lib/elements/entities/bucket/view/bucket_view.schema.d.ts +6 -3
- package/lib/elements/entities/bucket/view/bucket_view.schema.js +2 -1
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.d.ts +25 -24
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.js +65 -25
- package/lib/engine/app/inline.app.js +6 -0
- package/lib/engine/app/native/distributed_node.app.js +6 -0
- package/lib/engine/app/service.d.ts +7 -0
- package/lib/engine/app/service.js +2 -0
- package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +2 -2
- package/lib/engine/transaction/nodes/bucket.trx_node.js +6 -4
- package/lib/engine/transaction/nodes/bucket_query.trx_node.d.ts +2 -0
- package/lib/engine/transaction/nodes/bucket_query.trx_node.js +15 -4
- package/lib/engine/transaction/trx_engine.js +1 -1
- package/lib/engine/transaction/trx_node.js +3 -3
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -26,8 +26,8 @@ class BucketGraph {
|
|
|
26
26
|
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
27
27
|
*/
|
|
28
28
|
async readLink(trx, obj, link, options) {
|
|
29
|
-
log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
|
|
30
|
-
const schema = this.schema.links[link];
|
|
29
|
+
log_1.Log.trace('bucket', this.bucketName, `Read link ${link.name}`);
|
|
30
|
+
const schema = this.schema.links[link.name];
|
|
31
31
|
// Make tenancy query
|
|
32
32
|
const tenancy = (options?.no_tenancy)
|
|
33
33
|
? undefined
|
|
@@ -38,23 +38,29 @@ class BucketGraph {
|
|
|
38
38
|
...schema.query,
|
|
39
39
|
'#and __tenancy__': tenancy
|
|
40
40
|
};
|
|
41
|
-
const params = [{ ...obj }];
|
|
42
41
|
const page = {
|
|
43
42
|
perPage: schema.many ? undefined : 1,
|
|
44
43
|
};
|
|
44
|
+
// Params
|
|
45
|
+
const params = [{ ...obj }];
|
|
46
|
+
const param_templates = link.index.length
|
|
47
|
+
? Object.fromEntries(link.index
|
|
48
|
+
.map((s, i) => [`$${i}`, s]))
|
|
49
|
+
: undefined;
|
|
45
50
|
// External
|
|
46
51
|
let links;
|
|
47
52
|
if (schema.bucket.module !== module.name) {
|
|
48
53
|
links = await trx.bucket(schema.bucket.short)
|
|
49
54
|
.query(query)
|
|
50
55
|
.params(params)
|
|
56
|
+
.param_templates(param_templates)
|
|
51
57
|
.page(page);
|
|
52
58
|
}
|
|
53
59
|
// Internal
|
|
54
60
|
else {
|
|
55
61
|
const otherBucket = dependency_1.Tag.element(schema.bucket, trx);
|
|
56
62
|
const adapter = otherBucket.cache || otherBucket.adapter;
|
|
57
|
-
links = await adapter.query(trx, query, page, params);
|
|
63
|
+
links = await adapter.query(trx, query, page, params, param_templates ? [param_templates] : undefined);
|
|
58
64
|
}
|
|
59
65
|
// Empty response
|
|
60
66
|
if (!schema.many && !schema.optional && !links.data.length) {
|
|
@@ -65,7 +71,7 @@ class BucketGraph {
|
|
|
65
71
|
else {
|
|
66
72
|
throw error_1.NesoiError.Bucket.Graph.RequiredLinkNotFound({
|
|
67
73
|
bucket: this.bucketName,
|
|
68
|
-
link: link,
|
|
74
|
+
link: link.name,
|
|
69
75
|
id: obj.id
|
|
70
76
|
});
|
|
71
77
|
}
|
|
@@ -85,25 +91,29 @@ class BucketGraph {
|
|
|
85
91
|
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
86
92
|
*/
|
|
87
93
|
async readManyLinks(trx, objs, link, options) {
|
|
88
|
-
log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
|
|
89
|
-
const schema = this.schema.links[link];
|
|
94
|
+
log_1.Log.trace('bucket', this.bucketName, `Read link ${link.name}`);
|
|
95
|
+
const schema = this.schema.links[link.name];
|
|
90
96
|
// Make tenancy query
|
|
91
97
|
const tenancy = (options?.no_tenancy)
|
|
92
98
|
? undefined
|
|
93
99
|
: this.bucket.getTenancyQuery(trx);
|
|
94
|
-
// Query
|
|
100
|
+
// 1st Query
|
|
95
101
|
const module = trx_node_1.TrxNode.getModule(trx);
|
|
96
102
|
const query = {
|
|
97
103
|
...schema.query,
|
|
98
104
|
'#and __tenancy__': tenancy
|
|
99
105
|
};
|
|
100
106
|
const params = objs.map(obj => ({ ...obj }));
|
|
107
|
+
const param_templates = link.indexes.length
|
|
108
|
+
? link.indexes.map(index => Object.fromEntries(index
|
|
109
|
+
.map((s, i) => [`$${i}`, s]))) : undefined;
|
|
101
110
|
let tempAdapter;
|
|
102
111
|
// External
|
|
103
112
|
if (schema.bucket.module !== module.name) {
|
|
104
113
|
const allLinks = await trx.bucket(schema.bucket.short)
|
|
105
114
|
.query(query)
|
|
106
115
|
.params(params)
|
|
116
|
+
.param_templates(param_templates)
|
|
107
117
|
.all();
|
|
108
118
|
const tempData = {};
|
|
109
119
|
for (const obj of allLinks)
|
|
@@ -119,14 +129,14 @@ class BucketGraph {
|
|
|
119
129
|
}
|
|
120
130
|
else {
|
|
121
131
|
const adapter = otherBucket.cache || otherBucket.adapter;
|
|
122
|
-
const allLinks = await adapter.query(trx, query, undefined, params);
|
|
132
|
+
const allLinks = await adapter.query(trx, query, undefined, params, param_templates);
|
|
123
133
|
const tempData = {};
|
|
124
134
|
for (const obj of allLinks.data)
|
|
125
135
|
tempData[obj.id] = obj;
|
|
126
136
|
tempAdapter = new memory_bucket_adapter_1.MemoryBucketAdapter(otherBucket.schema, tempData);
|
|
127
137
|
}
|
|
128
138
|
}
|
|
129
|
-
// Query
|
|
139
|
+
// 2nd Query
|
|
130
140
|
const links = [];
|
|
131
141
|
for (const obj of objs) {
|
|
132
142
|
const result = tempAdapter instanceof bucket_cache_1.BucketCache
|
|
@@ -135,7 +145,7 @@ class BucketGraph {
|
|
|
135
145
|
}, [{ ...obj }], undefined)
|
|
136
146
|
: await tempAdapter.query(trx, schema.query, {
|
|
137
147
|
perPage: schema.many ? undefined : 1,
|
|
138
|
-
}, [{ ...obj }], undefined, {
|
|
148
|
+
}, [{ ...obj }], undefined, undefined, {
|
|
139
149
|
module: schema.bucket.module,
|
|
140
150
|
runners: {
|
|
141
151
|
[tempAdapter.getQueryMeta().scope]: tempAdapter.nql
|
|
@@ -165,8 +175,8 @@ class BucketGraph {
|
|
|
165
175
|
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
166
176
|
*/
|
|
167
177
|
async viewLink(trx, obj, link, view, options) {
|
|
168
|
-
log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
|
|
169
|
-
const schema = this.schema.links[link];
|
|
178
|
+
log_1.Log.trace('bucket', this.bucketName, `Read link ${link.name}`);
|
|
179
|
+
const schema = this.schema.links[link.name];
|
|
170
180
|
const links = await this.readLink(trx, obj, link, options);
|
|
171
181
|
if (!links)
|
|
172
182
|
return undefined;
|
|
@@ -15,27 +15,28 @@ export declare class BucketGraphLinkFactory<Module extends $Module, SelfBucket e
|
|
|
15
15
|
constructor(module: string);
|
|
16
16
|
as(alias: string): this;
|
|
17
17
|
get compose(): typeof this;
|
|
18
|
-
one<N extends keyof Module['buckets'], Bucket extends $Bucket = Module['buckets'][N]>(bucket: N, query: NQL_Query<Module, Bucket, Fieldpaths>): BucketGraphLinkBuilder<Module, SelfBucket, Module["buckets"][N]>;
|
|
19
|
-
many<N extends keyof Module['buckets'], Bucket extends $Bucket = Module['buckets'][N]>(bucket: N, query: NQL_Query<Module, Bucket, Fieldpaths>): BucketGraphLinkBuilder<Module, SelfBucket, Module["buckets"][N]>;
|
|
18
|
+
one<N extends keyof Module['buckets'], Bucket extends $Bucket = Module['buckets'][N]>(bucket: N, query: NQL_Query<Module, Bucket, Fieldpaths>): BucketGraphLinkBuilder<Module, SelfBucket, Module["buckets"][N], false>;
|
|
19
|
+
many<N extends keyof Module['buckets'], Bucket extends $Bucket = Module['buckets'][N]>(bucket: N, query: NQL_Query<Module, Bucket, Fieldpaths>): BucketGraphLinkBuilder<Module, SelfBucket, Module["buckets"][N], true>;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* @category Builders
|
|
23
23
|
* @subcategory Entity
|
|
24
24
|
* */
|
|
25
|
-
export declare class BucketGraphLinkBuilder<Module extends $Module, SelfBucket extends $Bucket, OtherBucket extends $Bucket> {
|
|
25
|
+
export declare class BucketGraphLinkBuilder<Module extends $Module, SelfBucket extends $Bucket, OtherBucket extends $Bucket, Many extends boolean> {
|
|
26
26
|
private bucket;
|
|
27
27
|
private rel;
|
|
28
28
|
private query;
|
|
29
29
|
private many;
|
|
30
30
|
private alias?;
|
|
31
31
|
'#other': OtherBucket;
|
|
32
|
+
'#many': Many;
|
|
32
33
|
private _optional;
|
|
33
34
|
constructor(bucket: Dependency, rel: 'aggregation' | 'composition', query: NQL_AnyQuery, many: boolean, alias?: string | undefined);
|
|
34
35
|
as(alias: string): this;
|
|
35
36
|
get optional(): this;
|
|
36
|
-
static build(node: BucketBuilderNode, builder: BucketGraphLinkBuilder<any, any, any>, name: string): $BucketGraphLink;
|
|
37
|
+
static build(node: BucketBuilderNode, builder: BucketGraphLinkBuilder<any, any, any, any>, name: string): $BucketGraphLink;
|
|
37
38
|
static inferKeyOwner(query: NQL_AnyQuery): "self";
|
|
38
39
|
}
|
|
39
40
|
export type BucketGraphLinkBuilders = {
|
|
40
|
-
[x: string]: BucketGraphLinkBuilder<any, any, any>;
|
|
41
|
+
[x: string]: BucketGraphLinkBuilder<any, any, any, any>;
|
|
41
42
|
};
|
|
@@ -18,7 +18,7 @@ function convertToView(model, name, fields = model.fields, path, depth = 0) {
|
|
|
18
18
|
const viewFields = {};
|
|
19
19
|
for (const f in fields) {
|
|
20
20
|
const field = fields[f];
|
|
21
|
-
const $ = new bucket_view_field_builder_1.BucketViewFieldFactory(
|
|
21
|
+
const $ = new bucket_view_field_builder_1.BucketViewFieldFactory();
|
|
22
22
|
const key = (path ? path + '.' : '')
|
|
23
23
|
+ field.name;
|
|
24
24
|
const builder = $.model(key);
|
|
@@ -38,9 +38,9 @@ function convertToMessage(module, model, name, alias, include = [], exclude = []
|
|
|
38
38
|
const convertField = (field) => {
|
|
39
39
|
return new message_template_schema_1.$MessageTemplateField(field.type, field.name, field.alias, field.path, field.path, optional.includes(field.path) ? false : field.required, undefined, false, [], {
|
|
40
40
|
enum: field.meta?.enum
|
|
41
|
-
}, field.children ? convertFields(field.children
|
|
41
|
+
}, field.children ? convertFields(field.children) : undefined);
|
|
42
42
|
};
|
|
43
|
-
const convertFields = (fields
|
|
43
|
+
const convertFields = (fields) => {
|
|
44
44
|
const msgFields = {};
|
|
45
45
|
for (const f in fields) {
|
|
46
46
|
const field = fields[f];
|
|
@@ -52,7 +52,7 @@ function convertToMessage(module, model, name, alias, include = [], exclude = []
|
|
|
52
52
|
}
|
|
53
53
|
return msgFields;
|
|
54
54
|
};
|
|
55
|
-
const msgFields = convertFields(model.fields
|
|
55
|
+
const msgFields = convertFields(model.fields);
|
|
56
56
|
const template = new message_template_schema_1.$MessageTemplate(msgFields);
|
|
57
57
|
return new message_schema_1.$Message(module, name, alias, template);
|
|
58
58
|
}
|
|
@@ -11,10 +11,10 @@ export type NQL_QueryMeta = {
|
|
|
11
11
|
export type NQL_Union = {
|
|
12
12
|
meta: NQL_QueryMeta;
|
|
13
13
|
inters: NQL_Intersection[];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
dir: ('asc' | 'desc')
|
|
17
|
-
};
|
|
14
|
+
sort?: {
|
|
15
|
+
key: string;
|
|
16
|
+
dir: ('asc' | 'desc');
|
|
17
|
+
}[];
|
|
18
18
|
_debug_id?: number;
|
|
19
19
|
};
|
|
20
20
|
export type NQL_Intersection = {
|
|
@@ -32,6 +32,8 @@ export type NQL_Rule = {
|
|
|
32
32
|
static: any | any[];
|
|
33
33
|
} | {
|
|
34
34
|
param: string | string[];
|
|
35
|
+
} | {
|
|
36
|
+
param_with_$: string;
|
|
35
37
|
} | {
|
|
36
38
|
subquery: {
|
|
37
39
|
bucket: $Bucket;
|
|
@@ -54,10 +56,7 @@ export type NQL_Node = NQL_Union | NQL_Intersection | NQL_Rule;
|
|
|
54
56
|
* All operations
|
|
55
57
|
*/
|
|
56
58
|
export type NQL_Operation = '==' | '>' | '<' | '>=' | '<=' | 'in' | 'contains' | 'contains_any' | 'present';
|
|
57
|
-
export type
|
|
58
|
-
by?: (keyof Querypath)[];
|
|
59
|
-
dir?: ('asc' | 'desc')[];
|
|
60
|
-
};
|
|
59
|
+
export type NQL_Sort<Querypath> = `${keyof Querypath & string}@${'asc' | 'desc'}` | `${keyof Querypath & string}@${'asc' | 'desc'}`[];
|
|
61
60
|
export type NQL_Pagination = {
|
|
62
61
|
page?: number;
|
|
63
62
|
perPage?: number;
|
|
@@ -134,7 +133,7 @@ type NQL_Terms<M extends $Module, $ extends $Bucket, Parameters = {}, Querypath
|
|
|
134
133
|
}>> = Conditions[keyof Conditions] & {
|
|
135
134
|
[K in `${'#and' | '#or'}${string}`]?: NQL_Terms<M, $, Parameters>;
|
|
136
135
|
} & NQL_GraphLinks<M, $, Parameters> & {
|
|
137
|
-
'#
|
|
136
|
+
'#sort'?: NQL_Sort<Querypath>;
|
|
138
137
|
};
|
|
139
138
|
/**
|
|
140
139
|
* NQL Dynamic Query Type
|
|
@@ -16,7 +16,7 @@ export declare class NQL_RuleTree {
|
|
|
16
16
|
constructor(daemon: AnyDaemon, module: string, bucketName: string, query: NQL_AnyQuery, customMetadata?: BucketMetadata | undefined, debug?: boolean);
|
|
17
17
|
parse(): Promise<void>;
|
|
18
18
|
private parseUnion;
|
|
19
|
-
private
|
|
19
|
+
private parseSort;
|
|
20
20
|
private parseKey;
|
|
21
21
|
private parseOp;
|
|
22
22
|
private parseValue;
|
|
@@ -84,8 +84,8 @@ class NQL_RuleTree {
|
|
|
84
84
|
const subInter = await this.parseUnion(bucket, value, select);
|
|
85
85
|
union.inters.push({ meta: {}, rules: [subInter] });
|
|
86
86
|
}
|
|
87
|
-
else if (parsedKey.type === '
|
|
88
|
-
union.
|
|
87
|
+
else if (parsedKey.type === 'sort') {
|
|
88
|
+
union.sort = await this.parseSort(bucket, value);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
if (!union.inters[0]?.rules.length) {
|
|
@@ -93,12 +93,28 @@ class NQL_RuleTree {
|
|
|
93
93
|
}
|
|
94
94
|
return union;
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
parseSort(bucket, value) {
|
|
97
|
+
if (!Array.isArray(value))
|
|
98
|
+
value = [value];
|
|
99
|
+
if (value.some(v => typeof v !== 'string')) {
|
|
100
|
+
throw new Error('Invalid sort parameter. Should be a string or array of strings.');
|
|
101
|
+
}
|
|
102
|
+
const sort = [];
|
|
103
|
+
for (const v of value) {
|
|
104
|
+
let key, vdir;
|
|
105
|
+
if (v.endsWith('@asc')) {
|
|
106
|
+
key = v.split('@asc')[0];
|
|
107
|
+
vdir = 'asc';
|
|
108
|
+
}
|
|
109
|
+
else if (v.endsWith('@desc')) {
|
|
110
|
+
key = v.split('@desc')[0];
|
|
111
|
+
vdir = 'desc';
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
throw new Error(`Invalid query sort direction '${key}', string must end with '@asc' or '@desc'`);
|
|
115
|
+
}
|
|
116
|
+
const is_metadata_field = Object.values(bucket.meta).includes(key);
|
|
117
|
+
if (!is_metadata_field) {
|
|
102
118
|
const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, key);
|
|
103
119
|
if (!fields.length) {
|
|
104
120
|
throw new Error(`Field '${key}' not found on bucket '${bucket.schema.name}'`);
|
|
@@ -111,26 +127,16 @@ class NQL_RuleTree {
|
|
|
111
127
|
}
|
|
112
128
|
}
|
|
113
129
|
}
|
|
130
|
+
sort.push({
|
|
131
|
+
key,
|
|
132
|
+
dir: vdir
|
|
133
|
+
});
|
|
114
134
|
}
|
|
115
|
-
|
|
116
|
-
by = [];
|
|
117
|
-
}
|
|
118
|
-
let dir = value['dir'];
|
|
119
|
-
if (dir) {
|
|
120
|
-
for (const key of dir) {
|
|
121
|
-
if (key !== 'asc' && key !== 'desc') {
|
|
122
|
-
throw new Error(`Invalid query order direction '${key}', expected 'asc'|'desc'`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
dir = [];
|
|
128
|
-
}
|
|
129
|
-
return { by, dir: dir };
|
|
135
|
+
return sort;
|
|
130
136
|
}
|
|
131
137
|
async parseKey(bucket, key) {
|
|
132
|
-
if (key === '#
|
|
133
|
-
return { type: '
|
|
138
|
+
if (key === '#sort') {
|
|
139
|
+
return { type: 'sort' };
|
|
134
140
|
}
|
|
135
141
|
else if (key.startsWith('#and')) {
|
|
136
142
|
return { type: 'and' };
|
|
@@ -233,6 +239,10 @@ class NQL_RuleTree {
|
|
|
233
239
|
if ('.' in value) {
|
|
234
240
|
return { param: value['.'] };
|
|
235
241
|
}
|
|
242
|
+
// Path Parameter
|
|
243
|
+
else if ('$' in value) {
|
|
244
|
+
return { param_with_$: value['$'] };
|
|
245
|
+
}
|
|
236
246
|
// Sub-Query
|
|
237
247
|
return { subquery: await this.parseSubQuery(value, parsedKey, meta, select) };
|
|
238
248
|
}
|
|
@@ -434,7 +444,7 @@ class NQL_RuleTree {
|
|
|
434
444
|
str += Array(d).fill(' ').join('')
|
|
435
445
|
+ (0, string_1.colored)(`└ ${node._debug_id || ''}[OR] `, 'lightpurple')
|
|
436
446
|
+ (0, string_1.colored)(`${node.meta.scope || ''} ${node.meta.avgTime || '?'}ms `, 'black')
|
|
437
|
-
+ (node.
|
|
447
|
+
+ (node.sort ? ` sort by ${node.sort}` : '')
|
|
438
448
|
+ '\n';
|
|
439
449
|
node.inters.forEach(inter => {
|
|
440
450
|
str += this.describe(inter, d + 1);
|
|
@@ -459,7 +469,8 @@ class NQL_RuleTree {
|
|
|
459
469
|
+ `@${node.meta.schema?.name}.${node.fieldpath}${node.not ? ' not' : ''} ${node.case_i ? '~' : ''}${node.op}`
|
|
460
470
|
+ (('static' in node.value) ? ` ${node.value.static}`
|
|
461
471
|
: ('param' in node.value) ? ` ->${node.value.param}`
|
|
462
|
-
:
|
|
472
|
+
: ('param_with_$' in node.value) ? ` ->>${node.value.param_with_$}`
|
|
473
|
+
: ' ▼ ' + (0, string_1.colored)('(' + node.value.subquery.bucket.name + '.' + node.value.subquery.select + ')', 'brown'))
|
|
463
474
|
+ '\n';
|
|
464
475
|
if ('subquery' in node.value) {
|
|
465
476
|
str += this.describe(node.value['subquery'].union, d + 1);
|
|
@@ -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>[], param_templates: Record<string, string>[], 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, 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, customRunners?: Record<string, NQLRunner>): Promise<NQL_Result>;
|
|
28
28
|
linkExternal(bucket: AnyBucket): void;
|
|
29
29
|
}
|
|
30
30
|
export {};
|
|
@@ -22,9 +22,11 @@ class NQL_Engine {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
async run(trx, query, pagination, params = [{}], view, customRunners) {
|
|
25
|
+
async run(trx, query, pagination, params = [{}], param_templates = [], view, customRunners) {
|
|
26
26
|
if (!params.length)
|
|
27
27
|
params = [{}];
|
|
28
|
+
if (!param_templates.length)
|
|
29
|
+
param_templates = [{}];
|
|
28
30
|
let result = {
|
|
29
31
|
data: []
|
|
30
32
|
};
|
|
@@ -36,7 +38,7 @@ class NQL_Engine {
|
|
|
36
38
|
? { ...this.runners, ...customRunners }
|
|
37
39
|
: this.runners;
|
|
38
40
|
const _runner = runners[part.union.meta.scope];
|
|
39
|
-
const out = await _runner.run(trx, part, params, pagination, view);
|
|
41
|
+
const out = await _runner.run(trx, part, params, param_templates, pagination, view);
|
|
40
42
|
result = out;
|
|
41
43
|
// Part failed, return
|
|
42
44
|
// Failure here is only when a single value is expected,
|
|
@@ -4,6 +4,7 @@ import { $BucketGraph } from '../graph/bucket_graph.schema';
|
|
|
4
4
|
import { BucketViewFieldBuilders, BucketViewFieldFactory } from './bucket_view_field.builder';
|
|
5
5
|
import { $Bucket } from '../bucket.schema';
|
|
6
6
|
import { $Module, $Space } from "../../..";
|
|
7
|
+
import { ModuleTree } from "../../../../engine/tree";
|
|
7
8
|
/**
|
|
8
9
|
* @category Builders
|
|
9
10
|
* @subcategory Entity
|
|
@@ -13,6 +14,6 @@ export declare class BucketViewBuilder<Space extends $Space, Module extends $Mod
|
|
|
13
14
|
private _fields;
|
|
14
15
|
constructor(name: string);
|
|
15
16
|
fields($: BucketViewDef<Space, Module, Bucket>): this;
|
|
16
|
-
static build(builder: BucketViewBuilder<any, any, any>, model: $BucketModel, graph: $BucketGraph, views: $BucketViews): $BucketView;
|
|
17
|
+
static build(builder: BucketViewBuilder<any, any, any>, model: $BucketModel, graph: $BucketGraph, views: $BucketViews, tree: ModuleTree): $BucketView;
|
|
17
18
|
}
|
|
18
|
-
export type BucketViewDef<Space extends $Space, Module extends $Module, Bucket extends $Bucket> = ($: BucketViewFieldFactory<Space, Module, Bucket>) => BucketViewFieldBuilders
|
|
19
|
+
export type BucketViewDef<Space extends $Space, Module extends $Module, Bucket extends $Bucket> = ($: BucketViewFieldFactory<Space, Module, Bucket>) => BucketViewFieldBuilders<Bucket>;
|
|
@@ -13,13 +13,13 @@ class BucketViewBuilder {
|
|
|
13
13
|
this._fields = {};
|
|
14
14
|
}
|
|
15
15
|
fields($) {
|
|
16
|
-
const fieldBuilder = new bucket_view_field_builder_1.BucketViewFieldFactory(
|
|
16
|
+
const fieldBuilder = new bucket_view_field_builder_1.BucketViewFieldFactory();
|
|
17
17
|
this._fields = $(fieldBuilder);
|
|
18
18
|
return this;
|
|
19
19
|
}
|
|
20
20
|
// Build
|
|
21
|
-
static build(builder, model, graph, views) {
|
|
22
|
-
const fields = bucket_view_field_builder_1.BucketViewFieldBuilder.buildFields(builder._fields, model, graph, views);
|
|
21
|
+
static build(builder, model, graph, views, tree) {
|
|
22
|
+
const fields = bucket_view_field_builder_1.BucketViewFieldBuilder.buildFields(builder._fields, model, graph, views, undefined, tree);
|
|
23
23
|
const schema = new bucket_view_schema_1.$BucketView(builder.name, fields);
|
|
24
24
|
schema.fields.id = new bucket_view_schema_1.$BucketViewField('id', 'model', 'id', { model: { path: 'id' } });
|
|
25
25
|
return schema;
|
|
@@ -153,6 +153,7 @@ class BucketView {
|
|
|
153
153
|
if (!node.field.children)
|
|
154
154
|
return [];
|
|
155
155
|
const next = [];
|
|
156
|
+
// subview
|
|
156
157
|
for (const key in node.field.children) {
|
|
157
158
|
if (key === '__raw')
|
|
158
159
|
continue;
|
|
@@ -258,6 +259,12 @@ class BucketView {
|
|
|
258
259
|
}
|
|
259
260
|
}
|
|
260
261
|
}
|
|
262
|
+
// Apply prop
|
|
263
|
+
for (const data of poll) {
|
|
264
|
+
if (node.field.prop) {
|
|
265
|
+
data.target[data.key] = data.target[data.key][node.field.prop];
|
|
266
|
+
}
|
|
267
|
+
}
|
|
261
268
|
return poll.map(p => ({
|
|
262
269
|
index: p.index,
|
|
263
270
|
raw: p.raw,
|
|
@@ -271,7 +278,7 @@ class BucketView {
|
|
|
271
278
|
async parseComputedProp(trx, node) {
|
|
272
279
|
const meta = node.field.meta.computed;
|
|
273
280
|
for (const entry of node.data) {
|
|
274
|
-
entry.target[node.field.name] = await promise_1.default.solve(meta.fn({ trx, raw: entry.raw, bucket: node.bucket.schema }));
|
|
281
|
+
entry.target[node.field.name] = await promise_1.default.solve(meta.fn({ trx, raw: entry.raw, value: entry.value, bucket: node.bucket.schema }));
|
|
275
282
|
}
|
|
276
283
|
}
|
|
277
284
|
/**
|
|
@@ -279,29 +286,47 @@ class BucketView {
|
|
|
279
286
|
*/
|
|
280
287
|
async parseGraphProp(trx, node) {
|
|
281
288
|
const meta = node.field.meta.graph;
|
|
282
|
-
let
|
|
289
|
+
let linksObjs;
|
|
283
290
|
const module = trx_node_1.TrxNode.getModule(trx);
|
|
291
|
+
// Step 1: Read many links from bucket
|
|
284
292
|
// External
|
|
285
293
|
if (node.bucket.tag.module !== module.name) {
|
|
286
|
-
|
|
294
|
+
linksObjs = await trx.bucket(node.bucket.tag.short).readManyLinks(node.data.map(entry => entry.raw.id), meta.path, node.data.map(entry => entry.index.map(i => i.toString())));
|
|
287
295
|
}
|
|
288
296
|
// Internal
|
|
289
297
|
else {
|
|
290
298
|
const bucket = module.buckets[node.bucket.tag.name];
|
|
291
|
-
|
|
299
|
+
linksObjs = await bucket.graph.readManyLinks(trx, node.data.map(entry => entry.raw), {
|
|
300
|
+
name: meta.link,
|
|
301
|
+
indexes: node.data.map(entry => entry.index.map(i => i.toString()))
|
|
302
|
+
}, { silent: true });
|
|
292
303
|
}
|
|
293
|
-
|
|
304
|
+
// Step 2: Initialize target values
|
|
305
|
+
const link = node.bucket.schema.graph.links[meta.link];
|
|
306
|
+
for (let i = 0; i < linksObjs.length; i++) {
|
|
294
307
|
if (meta.view) {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
308
|
+
if (link.many) {
|
|
309
|
+
node.data[i].target[node.field.name] = [];
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
node.data[i].target[node.field.name] = linksObjs[i] ? {} : undefined;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (node.field.prop) {
|
|
316
|
+
if (link.many) {
|
|
317
|
+
node.data[i].target[node.field.name] = linksObjs[i].map((link) => link[node.field.prop]);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
node.data[i].target[node.field.name] = linksObjs[i]?.[node.field.prop];
|
|
321
|
+
}
|
|
299
322
|
}
|
|
300
323
|
else {
|
|
301
|
-
node.data[i].target[node.field.name] =
|
|
324
|
+
node.data[i].target[node.field.name] = linksObjs[i];
|
|
302
325
|
}
|
|
303
326
|
}
|
|
327
|
+
// Step 3: Build view
|
|
304
328
|
let next = [];
|
|
329
|
+
let nextData = linksObjs;
|
|
305
330
|
if (meta.view) {
|
|
306
331
|
const schema = node.bucket.schema;
|
|
307
332
|
const otherBucketDep = schema.graph.links[meta.link].bucket;
|
|
@@ -311,46 +336,112 @@ class BucketView {
|
|
|
311
336
|
const view = otherBucket.schema.views[meta.view];
|
|
312
337
|
const { __raw, ...v } = view.fields;
|
|
313
338
|
const link = node.bucket.schema.graph.links[meta.link];
|
|
314
|
-
let nextData;
|
|
315
339
|
if (link.many) {
|
|
316
|
-
const _links =
|
|
340
|
+
const _links = linksObjs;
|
|
317
341
|
for (let i = 0; i < _links.length; i++) {
|
|
318
342
|
const target = node.data[i].target[node.field.name];
|
|
319
343
|
for (let j = 0; j < _links[i].length; j++) {
|
|
320
|
-
|
|
321
|
-
|
|
344
|
+
if (node.field.prop) {
|
|
345
|
+
target.push(_links[i][j][node.field.prop]);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
target.push(__raw ? { ..._links[i][j] } : {});
|
|
349
|
+
target[j].$v = meta.view;
|
|
350
|
+
}
|
|
322
351
|
}
|
|
323
352
|
}
|
|
324
|
-
|
|
353
|
+
if (!node.field.prop) {
|
|
354
|
+
nextData = _links.map((ll, i) => ll.map((l, j) => ({ value: l, target: node.data[i].target[node.field.name][j] }))).flat(1);
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
nextData = [];
|
|
358
|
+
}
|
|
325
359
|
}
|
|
326
360
|
else {
|
|
327
|
-
const _links =
|
|
361
|
+
const _links = linksObjs;
|
|
328
362
|
nextData = [];
|
|
329
363
|
for (let i = 0; i < _links.length; i++) {
|
|
330
364
|
if (!_links[i])
|
|
331
365
|
continue;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
366
|
+
if (node.field.prop) {
|
|
367
|
+
node.data[i].target[node.field.name] = _links[i][node.field.prop];
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
const target = node.data[i].target[node.field.name];
|
|
371
|
+
if (__raw) {
|
|
372
|
+
Object.assign(target, _links[i]);
|
|
373
|
+
}
|
|
374
|
+
target.$v = meta.view;
|
|
375
|
+
nextData.push({
|
|
376
|
+
value: _links[i], target: node.data[i].target[node.field.name]
|
|
377
|
+
});
|
|
335
378
|
}
|
|
336
|
-
target.$v = meta.view;
|
|
337
|
-
nextData.push({
|
|
338
|
-
value: _links[i], target: node.data[i].target[node.field.name]
|
|
339
|
-
});
|
|
340
379
|
}
|
|
341
380
|
}
|
|
342
|
-
//
|
|
381
|
+
// (still step 3) Add link bucket view fields to queue
|
|
343
382
|
next = [];
|
|
344
|
-
|
|
345
|
-
|
|
383
|
+
const bucket = await daemon_1.Daemon.getBucketMetadata(module.daemon, otherBucketDep);
|
|
384
|
+
// Next data is empty if meta.prop is defined, since there's no need to go deeper
|
|
385
|
+
if (nextData.length) {
|
|
386
|
+
for (const field of Object.values(v)) {
|
|
387
|
+
next.push({
|
|
388
|
+
bucket,
|
|
389
|
+
field,
|
|
390
|
+
data: nextData.map($ => ({
|
|
391
|
+
raw: $.value,
|
|
392
|
+
value: $.value,
|
|
393
|
+
index: [],
|
|
394
|
+
target: $.target
|
|
395
|
+
}))
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Step 4: Add subview fields to queue
|
|
401
|
+
if (node.field.children) {
|
|
402
|
+
// Prepare subview data
|
|
403
|
+
const subview_data = [];
|
|
404
|
+
for (let i = 0; i < linksObjs.length; i++) {
|
|
405
|
+
const objs = linksObjs[i];
|
|
406
|
+
let target;
|
|
407
|
+
if (link.many) {
|
|
408
|
+
target = [];
|
|
409
|
+
for (const tobj of node.data[i].target[node.field.name]) {
|
|
410
|
+
if ('__raw' in node.field.children) {
|
|
411
|
+
target.push({ ...tobj });
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
target.push({ id: tobj.id });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
subview_data.push(...objs.map((obj, i) => ({
|
|
418
|
+
obj: { ...obj },
|
|
419
|
+
target: target[i]
|
|
420
|
+
})));
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
target = { id: objs.id };
|
|
424
|
+
if ('__raw' in node.field.children) {
|
|
425
|
+
Object.assign(target, node.data[i].target[node.field.name]);
|
|
426
|
+
}
|
|
427
|
+
subview_data.push({ obj: { ...objs }, target });
|
|
428
|
+
}
|
|
429
|
+
node.data[i].target[node.field.name] = target;
|
|
430
|
+
}
|
|
431
|
+
const module = trx_node_1.TrxNode.getModule(trx);
|
|
432
|
+
const subview_bucket = daemon_1.Daemon.getBucketMetadata(module.daemon, link.bucket);
|
|
433
|
+
// Add subview data to queue
|
|
434
|
+
for (const key in node.field.children) {
|
|
435
|
+
if (key === '__raw')
|
|
436
|
+
continue;
|
|
346
437
|
next.push({
|
|
347
|
-
bucket,
|
|
348
|
-
field,
|
|
349
|
-
data:
|
|
350
|
-
raw:
|
|
351
|
-
value:
|
|
438
|
+
bucket: subview_bucket,
|
|
439
|
+
field: node.field.children[key],
|
|
440
|
+
data: subview_data.map(data => ({
|
|
441
|
+
raw: data.obj,
|
|
442
|
+
value: data.obj,
|
|
352
443
|
index: [],
|
|
353
|
-
target:
|
|
444
|
+
target: data.target
|
|
354
445
|
}))
|
|
355
446
|
});
|
|
356
447
|
}
|