nesoi 3.3.19 → 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 +86 -50
- 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,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;
|
|
@@ -4,6 +4,7 @@ exports.BucketAdapter = void 0;
|
|
|
4
4
|
const trx_node_1 = require("../../../../engine/transaction/trx_node");
|
|
5
5
|
const error_1 = require("../../../../engine/data/error");
|
|
6
6
|
const nql_compiler_1 = require("../query/nql_compiler");
|
|
7
|
+
const trx_1 = require("../../../../engine/transaction/trx");
|
|
7
8
|
/**
|
|
8
9
|
* @category Adapters
|
|
9
10
|
* @subcategory Entity
|
|
@@ -36,12 +37,30 @@ class BucketAdapter {
|
|
|
36
37
|
async query(trx, query, pagination, params, param_templates, config,
|
|
37
38
|
// When running a temporary local memory adapter,
|
|
38
39
|
// these are required
|
|
40
|
+
custom) {
|
|
41
|
+
const compiled = await this._compileQuery(trx, query, custom);
|
|
42
|
+
return this._queryCompiled(trx, compiled, pagination, params, param_templates, config, custom);
|
|
43
|
+
}
|
|
44
|
+
async _compileQuery(trx, query,
|
|
45
|
+
// When running a temporary local memory adapter,
|
|
46
|
+
// these are required
|
|
39
47
|
custom) {
|
|
40
48
|
const module = trx_node_1.TrxNode.getModule(trx);
|
|
41
49
|
const moduleName = custom?.module || module.name;
|
|
42
|
-
const
|
|
50
|
+
const customBuckets = {
|
|
51
|
+
...(custom?.buckets || {}),
|
|
52
|
+
...trx_1.Trx.getCacheCustomBuckets(trx)
|
|
53
|
+
};
|
|
54
|
+
return nql_compiler_1.NQL_Compiler.build(module.daemon, moduleName, this.schema.name, query, customBuckets);
|
|
55
|
+
}
|
|
56
|
+
async _queryCompiled(trx, compiled, pagination, params, param_templates, config, custom) {
|
|
57
|
+
const module = trx_node_1.TrxNode.getModule(trx);
|
|
58
|
+
const customBuckets = {
|
|
59
|
+
...(custom?.buckets || {}),
|
|
60
|
+
...trx_1.Trx.getCacheCustomBuckets(trx)
|
|
61
|
+
};
|
|
43
62
|
const view = config?.view ? this.schema.views[config.view] : undefined;
|
|
44
|
-
const result = await module.nql.run(trx, compiled, pagination, params, param_templates, view,
|
|
63
|
+
const result = await module.nql.run(trx, compiled, pagination, params, param_templates, view, customBuckets);
|
|
45
64
|
if (config?.metadataOnly) {
|
|
46
65
|
result.data = result.data.map(obj => ({
|
|
47
66
|
id: obj.id,
|
|
@@ -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;
|
|
@@ -53,11 +53,11 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
|
|
|
53
53
|
if (a_val instanceof datetime_1.NesoiDatetime) {
|
|
54
54
|
let d = 0;
|
|
55
55
|
if (b_val instanceof datetime_1.NesoiDatetime)
|
|
56
|
-
|
|
56
|
+
d = a_val.epoch - b_val.epoch;
|
|
57
57
|
else if (typeof b_val === 'string')
|
|
58
|
-
|
|
58
|
+
d = a_val.epoch - datetime_1.NesoiDatetime.fromISO(b_val).epoch;
|
|
59
59
|
else if (typeof b_val === 'number')
|
|
60
|
-
|
|
60
|
+
d = a_val.epoch - b_val;
|
|
61
61
|
else
|
|
62
62
|
throw new Error(`Cannot compare datetime and ${typeof b_val}`);
|
|
63
63
|
if (d !== 0) {
|
|
@@ -69,11 +69,11 @@ class MemoryNQLRunner extends nql_engine_1.NQLRunner {
|
|
|
69
69
|
else if (b_val instanceof datetime_1.NesoiDatetime) {
|
|
70
70
|
let d = 0;
|
|
71
71
|
if (a_val instanceof datetime_1.NesoiDatetime)
|
|
72
|
-
|
|
72
|
+
d = a_val.epoch - b_val.epoch;
|
|
73
73
|
else if (typeof a_val === 'string')
|
|
74
|
-
|
|
74
|
+
d = datetime_1.NesoiDatetime.fromISO(a_val).epoch - b_val.epoch;
|
|
75
75
|
else if (typeof a_val === 'number')
|
|
76
|
-
|
|
76
|
+
d = a_val - b_val.epoch;
|
|
77
77
|
else
|
|
78
78
|
throw new Error(`Cannot compare datetime and ${typeof a_val}`);
|
|
79
79
|
if (d !== 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
|
*/
|
|
@@ -2,11 +2,15 @@
|
|
|
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");
|
|
13
|
+
const trx_1 = require("../../../../engine/transaction/trx");
|
|
10
14
|
/**
|
|
11
15
|
* @category Elements
|
|
12
16
|
* @subcategory Entity
|
|
@@ -105,26 +109,42 @@ class BucketCache {
|
|
|
105
109
|
return out;
|
|
106
110
|
}
|
|
107
111
|
async query(trx, query, pagination, params, param_templates, config) {
|
|
112
|
+
const compiled = await this._compileQuery(trx, query);
|
|
113
|
+
return this._queryCompiled(trx, compiled, pagination, params, param_templates, config);
|
|
114
|
+
}
|
|
115
|
+
async _compileQuery(trx, query,
|
|
116
|
+
// When running a temporary local memory adapter,
|
|
117
|
+
// these are required
|
|
118
|
+
custom) {
|
|
119
|
+
const module = trx_node_1.TrxNode.getModule(trx);
|
|
120
|
+
const moduleName = custom?.module || module.name;
|
|
121
|
+
const customBuckets = {
|
|
122
|
+
...(custom?.buckets || {}),
|
|
123
|
+
...trx_1.Trx.getCacheCustomBuckets(trx)
|
|
124
|
+
};
|
|
125
|
+
return nql_compiler_1.NQL_Compiler.build(module.daemon, moduleName, this.bucket.schema.name, query, customBuckets);
|
|
126
|
+
}
|
|
127
|
+
async _queryCompiled(trx, query, pagination, params, param_templates, config) {
|
|
128
|
+
const tag = new dependency_1.Tag(this.bucket.schema.module, 'bucket', this.bucket.schema.name);
|
|
108
129
|
const mode = this.config?.mode?.query;
|
|
109
130
|
let data;
|
|
110
131
|
if (mode === 'eager') {
|
|
111
132
|
log_1.Log.debug('bucket', this.bucket.schema.name, 'CACHE index.eager');
|
|
112
|
-
|
|
133
|
+
const result = await this.innerAdapter._queryCompiled(trx, query, pagination, params, param_templates, config, {
|
|
134
|
+
module: this.bucket.schema.module
|
|
135
|
+
});
|
|
136
|
+
data = result.data;
|
|
113
137
|
}
|
|
114
|
-
if (mode === 'incremental') {
|
|
115
|
-
const { action, sync } = await this.syncQuery(trx, query
|
|
138
|
+
else if (mode === 'incremental') {
|
|
139
|
+
const { action, sync } = await this.syncQuery(trx, query /* TODO */, pagination, params);
|
|
116
140
|
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.incremental, ${action}`);
|
|
117
141
|
data = sync;
|
|
118
142
|
}
|
|
119
143
|
else if (mode === 'all') {
|
|
120
144
|
const { action, sync } = await this.syncAll(trx);
|
|
121
145
|
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
|
-
}
|
|
146
|
+
const entries = (await this.innerAdapter._queryCompiled(trx, query, pagination, params, undefined, undefined, {
|
|
147
|
+
module: this.bucket.schema.module
|
|
128
148
|
})).data;
|
|
129
149
|
data = [];
|
|
130
150
|
for (const e of entries) {
|
|
@@ -132,8 +152,10 @@ class BucketCache {
|
|
|
132
152
|
data.push(obj);
|
|
133
153
|
}
|
|
134
154
|
}
|
|
155
|
+
// Invalid mode, bypass cache
|
|
135
156
|
else {
|
|
136
|
-
|
|
157
|
+
const result = await this.outerAdapter.query(trx, query /* TODO */, pagination, params);
|
|
158
|
+
data = result.data;
|
|
137
159
|
}
|
|
138
160
|
for (const entry of data) {
|
|
139
161
|
delete entry['__update_epoch'];
|
|
@@ -149,6 +171,7 @@ class BucketCache {
|
|
|
149
171
|
* Update inner adapter with data from outer adapter.
|
|
150
172
|
*/
|
|
151
173
|
async sync(trx) {
|
|
174
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE sync, trx: ${trx.globalId}`);
|
|
152
175
|
const objects = await this.outerAdapter.index(trx);
|
|
153
176
|
const entries = objects.map(obj => new BucketCacheEntry(obj, this.outerAdapter.getUpdateEpoch(obj), this.lastSyncEpoch));
|
|
154
177
|
await this.innerAdapter.deleteEverything(trx);
|
|
@@ -162,6 +185,7 @@ class BucketCache {
|
|
|
162
185
|
* - reduces transit payload for data that doesn't change much
|
|
163
186
|
*/
|
|
164
187
|
async syncOne(trx, id) {
|
|
188
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE sync one: ${id}, trx: ${trx.globalId}`);
|
|
165
189
|
let localObj = await this.innerAdapter.get(trx, id);
|
|
166
190
|
if (!localObj) {
|
|
167
191
|
const obj = await this.outerAdapter.get(trx, id);
|
|
@@ -253,14 +277,11 @@ class BucketCache {
|
|
|
253
277
|
return { action: 'none', sync: [] };
|
|
254
278
|
}
|
|
255
279
|
// 2. Read ids from the inner adapter
|
|
256
|
-
const
|
|
280
|
+
const tag = new dependency_1.Tag(this.bucket.schema.module, 'bucket', this.bucket.schema.name);
|
|
257
281
|
const innerData = await this.innerAdapter.query(trx, {
|
|
258
282
|
'id in': outerMetadata.data.map(obj => obj.id)
|
|
259
283
|
}, undefined, undefined, undefined, undefined, {
|
|
260
|
-
module: this.bucket.schema.module
|
|
261
|
-
runners: {
|
|
262
|
-
[meta.scope]: this.innerAdapter.nql
|
|
263
|
-
}
|
|
284
|
+
module: this.bucket.schema.module
|
|
264
285
|
});
|
|
265
286
|
// 3. Filter modified query results
|
|
266
287
|
const outerEpoch = {};
|