nesoi 3.3.20 → 3.3.22
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 +26 -3
- package/lib/elements/entities/bucket/adapters/bucket_adapter.js +32 -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 +17 -1
- package/lib/elements/entities/bucket/cache/bucket_cache.js +47 -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 +2 -1
- package/lib/engine/transaction/trx.js +3 -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,7 +13,10 @@ export declare abstract class ControllerAdapter {
|
|
|
13
13
|
protected schema: $Controller;
|
|
14
14
|
protected daemon?: AnyDaemon;
|
|
15
15
|
constructor(module: $Module, schema: $Controller);
|
|
16
|
-
trx(fn: (trx: AnyTrxNode) => Promise<any>,
|
|
16
|
+
trx(fn: (trx: AnyTrxNode) => Promise<any>, endpoint: {
|
|
17
|
+
name: string;
|
|
18
|
+
idempotent?: boolean;
|
|
19
|
+
}, auth?: AuthRequest<any>): Promise<import("../../../../engine/transaction/trx").TrxStatus<any>>;
|
|
17
20
|
bind(daemon: AnyDaemon): void;
|
|
18
21
|
protected abstract makeEndpoint(path: string, schema: $ControllerEndpoint): void;
|
|
19
22
|
protected abstract makeTopic(schema: $ControllerTopic): void;
|
|
@@ -14,14 +14,18 @@ class ControllerAdapter {
|
|
|
14
14
|
this.module = module;
|
|
15
15
|
this.schema = schema;
|
|
16
16
|
}
|
|
17
|
-
async trx(fn, auth) {
|
|
17
|
+
async trx(fn, endpoint, auth) {
|
|
18
18
|
if (!this.daemon) {
|
|
19
19
|
throw new Error('Controller not bound to a daemon');
|
|
20
20
|
}
|
|
21
21
|
try {
|
|
22
|
-
|
|
23
|
-
.
|
|
24
|
-
.
|
|
22
|
+
const trx = this.daemon.trx(this.schema.module)
|
|
23
|
+
.origin(endpoint.name)
|
|
24
|
+
.auth(auth);
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
26
|
+
if (endpoint.idempotent)
|
|
27
|
+
trx.idempotent;
|
|
28
|
+
return await trx.run(fn);
|
|
25
29
|
}
|
|
26
30
|
catch (e) {
|
|
27
31
|
log_1.Log.error('controller', this.schema.name, 'Unknown error', e);
|
|
@@ -36,7 +36,7 @@ class ControllerEndpoint {
|
|
|
36
36
|
if (this.schema.target.type === 'machine') {
|
|
37
37
|
return trx.machine(this.schema.target.short).run(raw);
|
|
38
38
|
}
|
|
39
|
-
}, auth);
|
|
39
|
+
}, this.schema, auth);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
exports.ControllerEndpoint = ControllerEndpoint;
|
|
@@ -57,7 +57,7 @@ class ControllerTopic {
|
|
|
57
57
|
const response = await this.adapter.trx(async (trx) => {
|
|
58
58
|
await trx_node_1.TrxNode.checkAuth(trx, this.schema.auth);
|
|
59
59
|
return trx.topic(this.schema.name).subscribe(fn);
|
|
60
|
-
}, auth);
|
|
60
|
+
}, this.schema, auth);
|
|
61
61
|
if (response.state === 'error') {
|
|
62
62
|
throw error_1.NesoiError.Controller.SubscribeFailed({ topic: this.schema.alias });
|
|
63
63
|
}
|
|
@@ -67,7 +67,7 @@ class ControllerTopic {
|
|
|
67
67
|
const response = await this.adapter.trx(async (trx) => {
|
|
68
68
|
await trx_node_1.TrxNode.checkAuth(trx, this.schema.auth);
|
|
69
69
|
return trx.topic(this.schema.name).unsubscribe(id);
|
|
70
|
-
});
|
|
70
|
+
}, this.schema);
|
|
71
71
|
if (response.state === 'error') {
|
|
72
72
|
throw error_1.NesoiError.Controller.UnsubscribeFailed({ topic: this.schema.alias });
|
|
73
73
|
}
|
|
@@ -14,8 +14,9 @@ export declare class $ControllerEndpoint {
|
|
|
14
14
|
msg: Tag;
|
|
15
15
|
target: Tag;
|
|
16
16
|
implicit?: Record<string, any> | undefined;
|
|
17
|
+
idempotent: boolean;
|
|
17
18
|
$t: string;
|
|
18
|
-
constructor(name: string, alias: string, auth: $BlockAuth[], tags: string[], msg: Tag, target: Tag, implicit?: Record<string, any> | undefined);
|
|
19
|
+
constructor(name: string, alias: string, auth: $BlockAuth[], tags: string[], msg: Tag, target: Tag, implicit?: Record<string, any> | undefined, idempotent?: boolean);
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* @category Schemas
|
|
@@ -13,8 +13,9 @@ class $ControllerEndpoint {
|
|
|
13
13
|
msg;
|
|
14
14
|
target;
|
|
15
15
|
implicit;
|
|
16
|
+
idempotent;
|
|
16
17
|
$t = 'controller.endpoint';
|
|
17
|
-
constructor(name, alias, auth, tags, msg, target, implicit) {
|
|
18
|
+
constructor(name, alias, auth, tags, msg, target, implicit, idempotent = false) {
|
|
18
19
|
this.name = name;
|
|
19
20
|
this.alias = alias;
|
|
20
21
|
this.auth = auth;
|
|
@@ -22,6 +23,7 @@ class $ControllerEndpoint {
|
|
|
22
23
|
this.msg = msg;
|
|
23
24
|
this.target = target;
|
|
24
25
|
this.implicit = implicit;
|
|
26
|
+
this.idempotent = idempotent;
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
exports.$ControllerEndpoint = $ControllerEndpoint;
|
|
@@ -3,8 +3,8 @@ import { NesoiObj, ObjWithOptionalId } from "../../../../engine/data/obj";
|
|
|
3
3
|
import { BucketCacheSync } from '../cache/bucket_cache';
|
|
4
4
|
import { NQL_AnyQuery, NQL_Pagination } from '../query/nql.schema';
|
|
5
5
|
import { NQLRunner, NQL_Result } from '../query/nql_engine';
|
|
6
|
+
import { NQL_CompiledQuery } from '../query/nql_compiler';
|
|
6
7
|
import { $Bucket } from "../../..";
|
|
7
|
-
import { BucketMetadata } from "../../../../engine/transaction/trx_engine";
|
|
8
8
|
export type BucketAdapterConfig = {
|
|
9
9
|
meta: {
|
|
10
10
|
created_at: string;
|
|
@@ -146,8 +146,30 @@ export declare abstract class BucketAdapter<Obj extends NesoiObj, Config extends
|
|
|
146
146
|
metadataOnly?: MetadataOnly;
|
|
147
147
|
}, custom?: {
|
|
148
148
|
module?: string;
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
buckets?: Record<string, {
|
|
150
|
+
scope: string;
|
|
151
|
+
nql: NQLRunner;
|
|
152
|
+
}>;
|
|
153
|
+
}): Promise<NQL_Result<MetadataOnly extends true ? {
|
|
154
|
+
id: Obj['id'];
|
|
155
|
+
[x: string]: any;
|
|
156
|
+
} : Obj>>;
|
|
157
|
+
_compileQuery(trx: AnyTrxNode, query: NQL_AnyQuery, custom?: {
|
|
158
|
+
module?: string;
|
|
159
|
+
buckets?: Record<string, {
|
|
160
|
+
scope: string;
|
|
161
|
+
nql: NQLRunner;
|
|
162
|
+
}>;
|
|
163
|
+
}): Promise<NQL_CompiledQuery>;
|
|
164
|
+
_queryCompiled<MetadataOnly extends boolean>(trx: AnyTrxNode, compiled: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], config?: {
|
|
165
|
+
view?: string;
|
|
166
|
+
metadataOnly?: MetadataOnly;
|
|
167
|
+
}, custom?: {
|
|
168
|
+
module?: string;
|
|
169
|
+
buckets?: Record<string, {
|
|
170
|
+
scope: string;
|
|
171
|
+
nql: NQLRunner;
|
|
172
|
+
}>;
|
|
151
173
|
}): Promise<NQL_Result<MetadataOnly extends true ? {
|
|
152
174
|
id: Obj['id'];
|
|
153
175
|
[x: string]: any;
|
|
@@ -157,5 +179,6 @@ export declare abstract class BucketAdapter<Obj extends NesoiObj, Config extends
|
|
|
157
179
|
* @param {Obj} obj An object of this bucket
|
|
158
180
|
*/
|
|
159
181
|
getUpdateEpoch(obj: Obj): number;
|
|
182
|
+
private static getCacheCustomBuckets;
|
|
160
183
|
}
|
|
161
184
|
export type AnyBucketAdapter = BucketAdapter<any, any>;
|
|
@@ -36,12 +36,30 @@ class BucketAdapter {
|
|
|
36
36
|
async query(trx, query, pagination, params, param_templates, config,
|
|
37
37
|
// When running a temporary local memory adapter,
|
|
38
38
|
// these are required
|
|
39
|
+
custom) {
|
|
40
|
+
const compiled = await this._compileQuery(trx, query, custom);
|
|
41
|
+
return this._queryCompiled(trx, compiled, pagination, params, param_templates, config, custom);
|
|
42
|
+
}
|
|
43
|
+
async _compileQuery(trx, query,
|
|
44
|
+
// When running a temporary local memory adapter,
|
|
45
|
+
// these are required
|
|
39
46
|
custom) {
|
|
40
47
|
const module = trx_node_1.TrxNode.getModule(trx);
|
|
41
48
|
const moduleName = custom?.module || module.name;
|
|
42
|
-
const
|
|
49
|
+
const customBuckets = {
|
|
50
|
+
...(custom?.buckets || {}),
|
|
51
|
+
...BucketAdapter.getCacheCustomBuckets(trx)
|
|
52
|
+
};
|
|
53
|
+
return nql_compiler_1.NQL_Compiler.build(module.daemon, moduleName, this.schema.name, query, customBuckets);
|
|
54
|
+
}
|
|
55
|
+
async _queryCompiled(trx, compiled, pagination, params, param_templates, config, custom) {
|
|
56
|
+
const module = trx_node_1.TrxNode.getModule(trx);
|
|
57
|
+
const customBuckets = {
|
|
58
|
+
...(custom?.buckets || {}),
|
|
59
|
+
...BucketAdapter.getCacheCustomBuckets(trx)
|
|
60
|
+
};
|
|
43
61
|
const view = config?.view ? this.schema.views[config.view] : undefined;
|
|
44
|
-
const result = await module.nql.run(trx, compiled, pagination, params, param_templates, view,
|
|
62
|
+
const result = await module.nql.run(trx, compiled, pagination, params, param_templates, view, customBuckets);
|
|
45
63
|
if (config?.metadataOnly) {
|
|
46
64
|
result.data = result.data.map(obj => ({
|
|
47
65
|
id: obj.id,
|
|
@@ -61,5 +79,17 @@ class BucketAdapter {
|
|
|
61
79
|
}
|
|
62
80
|
return objUpdate.epoch;
|
|
63
81
|
}
|
|
82
|
+
static getCacheCustomBuckets(node) {
|
|
83
|
+
const trx = node.trx;
|
|
84
|
+
const buckets = {};
|
|
85
|
+
for (const tag in trx.cache) {
|
|
86
|
+
const adapter = trx.cache[tag].innerAdapter;
|
|
87
|
+
buckets[tag] = {
|
|
88
|
+
scope: `__cache_${tag}`,
|
|
89
|
+
nql: adapter.nql
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return buckets;
|
|
93
|
+
}
|
|
64
94
|
}
|
|
65
95
|
exports.BucketAdapter = BucketAdapter;
|
|
@@ -36,8 +36,8 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
|
|
|
36
36
|
let fallback = 0;
|
|
37
37
|
for (let i = 0; i < sort.length; i++) {
|
|
38
38
|
const s = sort[i];
|
|
39
|
-
const a_val = tree_1.Tree.get(a, s.key);
|
|
40
|
-
const b_val = tree_1.Tree.get(b, s.key);
|
|
39
|
+
const a_val = s.key_is_deep ? tree_1.Tree.get(a, s.key) : a[s.key];
|
|
40
|
+
const b_val = s.key_is_deep ? tree_1.Tree.get(b, s.key) : b[s.key];
|
|
41
41
|
if (a_val == null) {
|
|
42
42
|
if (b_val == null)
|
|
43
43
|
return 0;
|
|
@@ -172,56 +172,42 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
|
|
|
172
172
|
};
|
|
173
173
|
const _rule = (rule, objs, params, param_templates) => {
|
|
174
174
|
const out = {};
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (param_templates.length) {
|
|
181
|
-
for (const template of param_templates) {
|
|
182
|
-
combos.push({ params: param, param_template: template });
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
combos.push({ params: param, param_template: {} });
|
|
175
|
+
const combos = [];
|
|
176
|
+
for (const param of params) {
|
|
177
|
+
if (param_templates.length) {
|
|
178
|
+
for (const template of param_templates) {
|
|
179
|
+
combos.push({ params: param, param_template: template });
|
|
187
180
|
}
|
|
188
181
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (match)
|
|
192
|
-
break;
|
|
193
|
-
}
|
|
194
|
-
if (rule.not) {
|
|
195
|
-
match = !match;
|
|
182
|
+
else {
|
|
183
|
+
combos.push({ params: param, param_template: {} });
|
|
196
184
|
}
|
|
185
|
+
}
|
|
186
|
+
for (const combo of combos) {
|
|
187
|
+
const match = _index(rule, objs, combo.params, combo.param_template);
|
|
197
188
|
if (match) {
|
|
198
|
-
|
|
199
|
-
|
|
189
|
+
Object.assign(out, match);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
for (const id in objs) {
|
|
193
|
+
const obj = objs[id];
|
|
194
|
+
let match = _obj(rule, obj, combo.params, combo.param_template);
|
|
195
|
+
if (rule.not) {
|
|
196
|
+
match = !match;
|
|
200
197
|
}
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
if (match) {
|
|
199
|
+
if (rule.select) {
|
|
200
|
+
out[obj.id] = obj[rule.select];
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
out[obj.id] = obj;
|
|
204
|
+
}
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
}
|
|
206
208
|
return out;
|
|
207
209
|
};
|
|
208
|
-
const
|
|
209
|
-
const fieldValue = tree_1.Tree.get(obj, rule.fieldpath);
|
|
210
|
-
// Value is undefined, only 'present' rule applies
|
|
211
|
-
if (fieldValue === undefined) {
|
|
212
|
-
if (rule.op === 'present') {
|
|
213
|
-
return false;
|
|
214
|
-
}
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
// Fieldpath is a spread, apply rule to each item
|
|
218
|
-
if (rule.fieldpath.includes('.#')) {
|
|
219
|
-
for (const item of fieldValue) {
|
|
220
|
-
if (_obj(rule, item, params, param_template))
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
210
|
+
const _value = (rule, params, param_template) => {
|
|
225
211
|
let queryValue;
|
|
226
212
|
// Value is a subquery, run union
|
|
227
213
|
if ('subquery' in rule.value) {
|
|
@@ -238,10 +224,14 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
|
|
|
238
224
|
}
|
|
239
225
|
else if ('param' in rule.value) {
|
|
240
226
|
if (Array.isArray(rule.value.param)) {
|
|
241
|
-
queryValue = rule.value.
|
|
227
|
+
queryValue = rule.value.param_is_deep
|
|
228
|
+
? rule.value.param.map(p => tree_1.Tree.get(params, p))
|
|
229
|
+
: rule.value.param.map(p => params[p]);
|
|
242
230
|
}
|
|
243
231
|
else {
|
|
244
|
-
queryValue =
|
|
232
|
+
queryValue = rule.value.param_is_deep
|
|
233
|
+
? tree_1.Tree.get(params, rule.value.param)
|
|
234
|
+
: params[rule.value.param];
|
|
245
235
|
}
|
|
246
236
|
}
|
|
247
237
|
else if ('param_with_$' in rule.value) {
|
|
@@ -254,6 +244,52 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
|
|
|
254
244
|
else if ('static' in rule.value) {
|
|
255
245
|
queryValue = rule.value.static;
|
|
256
246
|
}
|
|
247
|
+
return queryValue;
|
|
248
|
+
};
|
|
249
|
+
const _index = (rule, objs, params, param_template) => {
|
|
250
|
+
if (rule.op !== '==')
|
|
251
|
+
return undefined;
|
|
252
|
+
if (rule.fieldpath !== 'id')
|
|
253
|
+
return undefined;
|
|
254
|
+
const queryValue = _value(rule, params, param_template);
|
|
255
|
+
let out = {};
|
|
256
|
+
if (rule.not) {
|
|
257
|
+
out = Object.assign({}, objs);
|
|
258
|
+
delete out[queryValue];
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
const obj = objs[queryValue];
|
|
262
|
+
if (obj) {
|
|
263
|
+
out[obj.id] = obj;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (rule.select) {
|
|
267
|
+
for (const id in out) {
|
|
268
|
+
out[id] = out[id][rule.select];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
};
|
|
273
|
+
const _obj = (rule, obj, params, param_template) => {
|
|
274
|
+
const fieldValue = rule.fieldpath_is_deep
|
|
275
|
+
? tree_1.Tree.get(obj, rule.fieldpath)
|
|
276
|
+
: obj[rule.fieldpath];
|
|
277
|
+
// Value is undefined, only 'present' rule applies
|
|
278
|
+
if (fieldValue === undefined) {
|
|
279
|
+
if (rule.op === 'present') {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
// Fieldpath is a spread, apply rule to each item
|
|
285
|
+
if (rule.fieldpath.includes('.#')) {
|
|
286
|
+
for (const item of fieldValue) {
|
|
287
|
+
if (_obj(rule, item, params, param_template))
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
const queryValue = _value(rule, params, param_template);
|
|
257
293
|
// Check each operation
|
|
258
294
|
// (Compatible operations and types have already been validated)
|
|
259
295
|
if (rule.op === '<') {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BucketAdapterConfig } from './bucket_adapter';
|
|
2
|
+
import { $Bucket, MemoryBucketAdapter } from "../../..";
|
|
3
|
+
/**
|
|
4
|
+
* @category Adapters
|
|
5
|
+
* @subcategory Entity
|
|
6
|
+
*/
|
|
7
|
+
export declare class TestBucketAdapter<B extends $Bucket, Obj extends B['#data']> extends MemoryBucketAdapter<B, Obj> {
|
|
8
|
+
schema: B;
|
|
9
|
+
data: NoInfer<Record<Obj['id'], Obj>>;
|
|
10
|
+
private queryMeta?;
|
|
11
|
+
constructor(schema: B, data?: NoInfer<Record<Obj['id'], Obj>>, config?: BucketAdapterConfig & {
|
|
12
|
+
queryMeta?: {
|
|
13
|
+
scope: string;
|
|
14
|
+
avgTime: number;
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
getQueryMeta(): {
|
|
18
|
+
scope: string;
|
|
19
|
+
avgTime: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export type AnyTestBucketAdapter = TestBucketAdapter<any, any>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TestBucketAdapter = void 0;
|
|
4
|
+
const elements_1 = require("../../..");
|
|
5
|
+
/**
|
|
6
|
+
* @category Adapters
|
|
7
|
+
* @subcategory Entity
|
|
8
|
+
*/
|
|
9
|
+
class TestBucketAdapter extends elements_1.MemoryBucketAdapter {
|
|
10
|
+
schema;
|
|
11
|
+
data;
|
|
12
|
+
queryMeta;
|
|
13
|
+
constructor(schema, data = {}, config) {
|
|
14
|
+
super(schema, data, config);
|
|
15
|
+
this.schema = schema;
|
|
16
|
+
this.data = data;
|
|
17
|
+
this.queryMeta = config?.queryMeta;
|
|
18
|
+
}
|
|
19
|
+
getQueryMeta() {
|
|
20
|
+
return this.queryMeta || super.getQueryMeta();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.TestBucketAdapter = TestBucketAdapter;
|
|
@@ -88,8 +88,8 @@ class Bucket {
|
|
|
88
88
|
? undefined
|
|
89
89
|
: this.getTenancyQuery(trx);
|
|
90
90
|
let raw;
|
|
91
|
-
// With Tenancy
|
|
92
91
|
const adapter = await trx_1.Trx.getCache(trx, this) || this.cache || this.adapter;
|
|
92
|
+
// With Tenancy
|
|
93
93
|
if (tenancy) {
|
|
94
94
|
const result = await adapter.query(trx, {
|
|
95
95
|
id,
|
|
@@ -127,8 +127,8 @@ class Bucket {
|
|
|
127
127
|
? undefined
|
|
128
128
|
: this.getTenancyQuery(trx);
|
|
129
129
|
let raws;
|
|
130
|
-
// With Tenancy
|
|
131
130
|
const adapter = await trx_1.Trx.getCache(trx, this) || this.cache || this.adapter;
|
|
131
|
+
// With Tenancy
|
|
132
132
|
if (tenancy) {
|
|
133
133
|
const result = await adapter.query(trx, tenancy, undefined, undefined, undefined, options?.query_view ? { view: options?.query_view } : undefined);
|
|
134
134
|
raws = result.data;
|
|
@@ -2,8 +2,9 @@ import { BucketConfig } from '../bucket.config';
|
|
|
2
2
|
import { AnyTrxNode } from "../../../../engine/transaction/trx_node";
|
|
3
3
|
import { NesoiObj } from "../../../../engine/data/obj";
|
|
4
4
|
import { NQL_AnyQuery, NQL_Pagination } from '../query/nql.schema';
|
|
5
|
-
import { NQL_Result } from '../query/nql_engine';
|
|
5
|
+
import { NQL_Result, NQLRunner } from '../query/nql_engine';
|
|
6
6
|
import { AnyBucket } from '../bucket';
|
|
7
|
+
import { NQL_CompiledQuery } from '../query/nql_compiler';
|
|
7
8
|
export type BucketCacheSync<T> = {
|
|
8
9
|
obj: T;
|
|
9
10
|
updateEpoch: number;
|
|
@@ -42,6 +43,20 @@ export declare class BucketCache<Obj extends NesoiObj> {
|
|
|
42
43
|
id: Obj['id'];
|
|
43
44
|
[x: string]: any;
|
|
44
45
|
} : Obj>>;
|
|
46
|
+
_compileQuery(trx: AnyTrxNode, query: NQL_AnyQuery, custom?: {
|
|
47
|
+
module?: string;
|
|
48
|
+
buckets?: Record<string, {
|
|
49
|
+
scope: string;
|
|
50
|
+
nql: NQLRunner;
|
|
51
|
+
}>;
|
|
52
|
+
}): Promise<NQL_CompiledQuery>;
|
|
53
|
+
_queryCompiled<MetadataOnly extends boolean>(trx: AnyTrxNode, query: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], param_templates?: Record<string, string>[], config?: {
|
|
54
|
+
view?: string;
|
|
55
|
+
metadataOnly?: MetadataOnly;
|
|
56
|
+
}): Promise<NQL_Result<MetadataOnly extends true ? {
|
|
57
|
+
id: Obj['id'];
|
|
58
|
+
[x: string]: any;
|
|
59
|
+
} : Obj>>;
|
|
45
60
|
/**
|
|
46
61
|
* Update inner adapter with data from outer adapter.
|
|
47
62
|
*/
|
|
@@ -77,5 +92,6 @@ export declare class BucketCache<Obj extends NesoiObj> {
|
|
|
77
92
|
* - reduces transit payload for data that doesn't change much
|
|
78
93
|
*/
|
|
79
94
|
private syncQuery;
|
|
95
|
+
private static getCacheCustomBuckets;
|
|
80
96
|
}
|
|
81
97
|
export type AnyBucketCache = BucketCache<any>;
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BucketCache = exports.BucketCacheEntry = void 0;
|
|
4
4
|
const log_1 = require("../../../../engine/util/log");
|
|
5
|
+
const trx_node_1 = require("../../../../engine/transaction/trx_node");
|
|
5
6
|
const memory_bucket_adapter_1 = require("../adapters/memory.bucket_adapter");
|
|
6
7
|
const datetime_1 = require("../../../../engine/data/datetime");
|
|
7
8
|
const bucket_schema_1 = require("../bucket.schema");
|
|
8
9
|
const bucket_model_schema_1 = require("../model/bucket_model.schema");
|
|
9
10
|
const bucket_graph_schema_1 = require("../graph/bucket_graph.schema");
|
|
11
|
+
const dependency_1 = require("../../../../engine/dependency");
|
|
12
|
+
const nql_compiler_1 = require("../query/nql_compiler");
|
|
10
13
|
/**
|
|
11
14
|
* @category Elements
|
|
12
15
|
* @subcategory Entity
|
|
@@ -105,26 +108,42 @@ class BucketCache {
|
|
|
105
108
|
return out;
|
|
106
109
|
}
|
|
107
110
|
async query(trx, query, pagination, params, param_templates, config) {
|
|
111
|
+
const compiled = await this._compileQuery(trx, query);
|
|
112
|
+
return this._queryCompiled(trx, compiled, pagination, params, param_templates, config);
|
|
113
|
+
}
|
|
114
|
+
async _compileQuery(trx, query,
|
|
115
|
+
// When running a temporary local memory adapter,
|
|
116
|
+
// these are required
|
|
117
|
+
custom) {
|
|
118
|
+
const module = trx_node_1.TrxNode.getModule(trx);
|
|
119
|
+
const moduleName = custom?.module || module.name;
|
|
120
|
+
const customBuckets = {
|
|
121
|
+
...(custom?.buckets || {}),
|
|
122
|
+
...BucketCache.getCacheCustomBuckets(trx)
|
|
123
|
+
};
|
|
124
|
+
return nql_compiler_1.NQL_Compiler.build(module.daemon, moduleName, this.bucket.schema.name, query, customBuckets);
|
|
125
|
+
}
|
|
126
|
+
async _queryCompiled(trx, query, pagination, params, param_templates, config) {
|
|
127
|
+
const tag = new dependency_1.Tag(this.bucket.schema.module, 'bucket', this.bucket.schema.name);
|
|
108
128
|
const mode = this.config?.mode?.query;
|
|
109
129
|
let data;
|
|
110
130
|
if (mode === 'eager') {
|
|
111
131
|
log_1.Log.debug('bucket', this.bucket.schema.name, 'CACHE index.eager');
|
|
112
|
-
|
|
132
|
+
const result = await this.innerAdapter._queryCompiled(trx, query, pagination, params, param_templates, config, {
|
|
133
|
+
module: this.bucket.schema.module
|
|
134
|
+
});
|
|
135
|
+
data = result.data;
|
|
113
136
|
}
|
|
114
|
-
if (mode === 'incremental') {
|
|
115
|
-
const { action, sync } = await this.syncQuery(trx, query
|
|
137
|
+
else if (mode === 'incremental') {
|
|
138
|
+
const { action, sync } = await this.syncQuery(trx, query /* TODO */, pagination, params);
|
|
116
139
|
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.incremental, ${action}`);
|
|
117
140
|
data = sync;
|
|
118
141
|
}
|
|
119
142
|
else if (mode === 'all') {
|
|
120
143
|
const { action, sync } = await this.syncAll(trx);
|
|
121
144
|
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.all, ${action}`);
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
module: this.bucket.schema.module,
|
|
125
|
-
runners: {
|
|
126
|
-
[meta.scope]: this.innerAdapter.nql
|
|
127
|
-
}
|
|
145
|
+
const entries = (await this.innerAdapter._queryCompiled(trx, query, pagination, params, undefined, undefined, {
|
|
146
|
+
module: this.bucket.schema.module
|
|
128
147
|
})).data;
|
|
129
148
|
data = [];
|
|
130
149
|
for (const e of entries) {
|
|
@@ -132,8 +151,10 @@ class BucketCache {
|
|
|
132
151
|
data.push(obj);
|
|
133
152
|
}
|
|
134
153
|
}
|
|
154
|
+
// Invalid mode, bypass cache
|
|
135
155
|
else {
|
|
136
|
-
|
|
156
|
+
const result = await this.outerAdapter.query(trx, query /* TODO */, pagination, params);
|
|
157
|
+
data = result.data;
|
|
137
158
|
}
|
|
138
159
|
for (const entry of data) {
|
|
139
160
|
delete entry['__update_epoch'];
|
|
@@ -149,6 +170,7 @@ class BucketCache {
|
|
|
149
170
|
* Update inner adapter with data from outer adapter.
|
|
150
171
|
*/
|
|
151
172
|
async sync(trx) {
|
|
173
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE sync, trx: ${trx.globalId}`);
|
|
152
174
|
const objects = await this.outerAdapter.index(trx);
|
|
153
175
|
const entries = objects.map(obj => new BucketCacheEntry(obj, this.outerAdapter.getUpdateEpoch(obj), this.lastSyncEpoch));
|
|
154
176
|
await this.innerAdapter.deleteEverything(trx);
|
|
@@ -162,6 +184,7 @@ class BucketCache {
|
|
|
162
184
|
* - reduces transit payload for data that doesn't change much
|
|
163
185
|
*/
|
|
164
186
|
async syncOne(trx, id) {
|
|
187
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE sync one: ${id}, trx: ${trx.globalId}`);
|
|
165
188
|
let localObj = await this.innerAdapter.get(trx, id);
|
|
166
189
|
if (!localObj) {
|
|
167
190
|
const obj = await this.outerAdapter.get(trx, id);
|
|
@@ -253,14 +276,11 @@ class BucketCache {
|
|
|
253
276
|
return { action: 'none', sync: [] };
|
|
254
277
|
}
|
|
255
278
|
// 2. Read ids from the inner adapter
|
|
256
|
-
const
|
|
279
|
+
const tag = new dependency_1.Tag(this.bucket.schema.module, 'bucket', this.bucket.schema.name);
|
|
257
280
|
const innerData = await this.innerAdapter.query(trx, {
|
|
258
281
|
'id in': outerMetadata.data.map(obj => obj.id)
|
|
259
282
|
}, undefined, undefined, undefined, undefined, {
|
|
260
|
-
module: this.bucket.schema.module
|
|
261
|
-
runners: {
|
|
262
|
-
[meta.scope]: this.innerAdapter.nql
|
|
263
|
-
}
|
|
283
|
+
module: this.bucket.schema.module
|
|
264
284
|
});
|
|
265
285
|
// 3. Filter modified query results
|
|
266
286
|
const outerEpoch = {};
|
|
@@ -298,5 +318,17 @@ class BucketCache {
|
|
|
298
318
|
}
|
|
299
319
|
return { action: 'update', sync: Object.values(queryResults).map(r => new BucketCacheEntry(r.obj, r.updateEpoch, datetime_1.NesoiDatetime.now().epoch)) };
|
|
300
320
|
}
|
|
321
|
+
static getCacheCustomBuckets(node) {
|
|
322
|
+
const trx = node.trx;
|
|
323
|
+
const buckets = {};
|
|
324
|
+
for (const tag in trx.cache) {
|
|
325
|
+
const adapter = trx.cache[tag].innerAdapter;
|
|
326
|
+
buckets[tag] = {
|
|
327
|
+
scope: `__cache_${tag}`,
|
|
328
|
+
nql: adapter.nql
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return buckets;
|
|
332
|
+
}
|
|
301
333
|
}
|
|
302
334
|
exports.BucketCache = BucketCache;
|