nesoi 3.2.1 → 3.2.3
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/compiler/elements/constants.element.js +1 -1
- package/lib/compiler/error.d.ts +1 -0
- package/lib/compiler/error.js +3 -0
- package/lib/compiler/stages/4_build_schemas_stage.js +14 -0
- package/lib/compiler/treeshake.js +3 -1
- package/lib/elements/blocks/job/internal/resource_job.js +1 -1
- package/lib/elements/blocks/resource/resource.builder.js +1 -1
- package/lib/elements/blocks/resource/resource.js +1 -0
- package/lib/elements/edge/externals/externals.builder.d.ts +2 -0
- package/lib/elements/edge/externals/externals.builder.js +6 -1
- package/lib/elements/edge/externals/externals.schema.d.ts +2 -1
- package/lib/elements/edge/externals/externals.schema.js +3 -1
- package/lib/elements/entities/bucket/adapters/bucket_adapter.d.ts +2 -2
- package/lib/elements/entities/bucket/adapters/bucket_adapter.js +2 -2
- package/lib/elements/entities/bucket/adapters/memory.nql.d.ts +1 -1
- package/lib/elements/entities/bucket/adapters/memory.nql.js +9 -5
- package/lib/elements/entities/bucket/bucket.d.ts +15 -3
- package/lib/elements/entities/bucket/bucket.js +51 -15
- package/lib/elements/entities/bucket/cache/bucket_cache.d.ts +14 -10
- package/lib/elements/entities/bucket/cache/bucket_cache.js +92 -58
- package/lib/elements/entities/bucket/graph/bucket_graph.d.ts +11 -0
- package/lib/elements/entities/bucket/graph/bucket_graph.js +57 -3
- package/lib/elements/entities/bucket/model/bucket_model.schema.js +16 -13
- package/lib/elements/entities/bucket/model/bucket_model_field.builder.d.ts +3 -4
- package/lib/elements/entities/bucket/query/nql_compiler.js +7 -1
- package/lib/elements/entities/bucket/query/nql_engine.d.ts +2 -2
- package/lib/elements/entities/bucket/query/nql_engine.js +8 -4
- package/lib/elements/entities/bucket/view/bucket_view.js +65 -12
- package/lib/elements/entities/constants/constants.schema.d.ts +2 -4
- package/lib/engine/apps/inline.app.js +1 -0
- package/lib/engine/module.d.ts +2 -2
- package/lib/engine/module.js +9 -2
- package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +5 -0
- package/lib/engine/transaction/nodes/bucket.trx_node.js +10 -0
- 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_node.d.ts +1 -2
- package/lib/engine/util/log.d.ts +1 -1
- package/lib/engine/util/log.js +1 -0
- package/package.json +1 -1
- package/tools/joaquin/bucket.d.ts +23 -3
- package/tools/joaquin/bucket.js +48 -20
- package/tools/joaquin/job.js +4 -4
- package/tsconfig.build.tsbuildinfo +1 -1
- /package/lib/engine/apps/distributed/inc/{test.d.ts → sandbox.d.ts} +0 -0
- /package/lib/engine/apps/distributed/inc/{test.js → sandbox.js} +0 -0
|
@@ -4,16 +4,18 @@ exports.BucketCache = exports.BucketCacheEntry = void 0;
|
|
|
4
4
|
const log_1 = require("../../../../engine/util/log");
|
|
5
5
|
const memory_bucket_adapter_1 = require("../adapters/memory.bucket_adapter");
|
|
6
6
|
const datetime_1 = require("../../../../engine/data/datetime");
|
|
7
|
+
const bucket_schema_1 = require("../bucket.schema");
|
|
8
|
+
const bucket_model_schema_1 = require("../model/bucket_model.schema");
|
|
9
|
+
const bucket_graph_schema_1 = require("../graph/bucket_graph.schema");
|
|
7
10
|
/**
|
|
8
11
|
* @category Elements
|
|
9
12
|
* @subcategory Entity
|
|
10
13
|
* */
|
|
11
14
|
class BucketCacheEntry {
|
|
12
|
-
constructor(
|
|
13
|
-
this.
|
|
14
|
-
this.
|
|
15
|
-
this
|
|
16
|
-
this.syncEpoch = syncEpoch;
|
|
15
|
+
constructor(obj, __update_epoch, __sync_epoch) {
|
|
16
|
+
this.__update_epoch = __update_epoch;
|
|
17
|
+
this.__sync_epoch = __sync_epoch;
|
|
18
|
+
Object.assign(this, obj);
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
exports.BucketCacheEntry = BucketCacheEntry;
|
|
@@ -22,28 +24,43 @@ exports.BucketCacheEntry = BucketCacheEntry;
|
|
|
22
24
|
* @subcategory Entity
|
|
23
25
|
* */
|
|
24
26
|
class BucketCache {
|
|
25
|
-
constructor(
|
|
26
|
-
this.
|
|
27
|
-
this.outerAdapter = outerAdapter;
|
|
27
|
+
constructor(bucket, config) {
|
|
28
|
+
this.bucket = bucket;
|
|
28
29
|
this.config = config;
|
|
29
|
-
|
|
30
|
+
const innerSchema = new bucket_schema_1.$Bucket(bucket.schema.module, bucket.schema.name, '[cache] ' + bucket.schema.alias, new bucket_model_schema_1.$BucketModel({
|
|
31
|
+
...bucket.schema.model.fields,
|
|
32
|
+
__update_epoch: new bucket_model_schema_1.$BucketModelField('__update_epoch', '__update_epoch', 'int', '__update_epoch', true),
|
|
33
|
+
__sync_epoch: new bucket_model_schema_1.$BucketModelField('__sync_epoch', '__sync_epoch', 'int', '__sync_epoch', true),
|
|
34
|
+
}), new bucket_graph_schema_1.$BucketGraph(), {});
|
|
35
|
+
this.innerAdapter = this.config?.adapter || new memory_bucket_adapter_1.MemoryBucketAdapter(innerSchema, {});
|
|
36
|
+
this.outerAdapter = bucket.adapter;
|
|
30
37
|
}
|
|
31
38
|
async get(trx, id) {
|
|
32
39
|
const mode = this.config?.mode?.get;
|
|
33
40
|
if (mode === 'one') {
|
|
34
41
|
const { action, sync } = await this.syncOne(trx, id);
|
|
35
|
-
log_1.Log.debug('bucket', this.
|
|
36
|
-
|
|
42
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE get.one, ${action}`);
|
|
43
|
+
if (!sync)
|
|
44
|
+
return undefined;
|
|
45
|
+
const { __update_epoch, __sync_epoch, ...obj } = sync;
|
|
46
|
+
return obj;
|
|
37
47
|
}
|
|
38
48
|
if (mode === 'past') {
|
|
39
49
|
const { action, sync } = await this.syncOneAndPast(trx, id);
|
|
40
|
-
log_1.Log.debug('bucket', this.
|
|
41
|
-
|
|
50
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE get.past, ${action}`);
|
|
51
|
+
if (!sync)
|
|
52
|
+
return undefined;
|
|
53
|
+
const { __update_epoch, __sync_epoch, ...obj } = sync;
|
|
54
|
+
return obj;
|
|
42
55
|
}
|
|
43
56
|
if (mode === 'all') {
|
|
44
57
|
const { action, sync } = await this.syncAll(trx);
|
|
45
|
-
log_1.Log.debug('bucket', this.
|
|
46
|
-
|
|
58
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE get.all, ${action}`);
|
|
59
|
+
const one = sync.find(s => s.id === id);
|
|
60
|
+
if (!one)
|
|
61
|
+
return undefined;
|
|
62
|
+
const { __update_epoch, __sync_epoch, ...obj } = one;
|
|
63
|
+
return one;
|
|
47
64
|
}
|
|
48
65
|
return this.outerAdapter.get(trx, id);
|
|
49
66
|
}
|
|
@@ -51,50 +68,69 @@ class BucketCache {
|
|
|
51
68
|
const mode = this.config?.mode?.index;
|
|
52
69
|
if (mode === 'all') {
|
|
53
70
|
const { action, sync } = await this.syncAll(trx);
|
|
54
|
-
log_1.Log.debug('bucket', this.
|
|
55
|
-
|
|
71
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE index.all, ${action}`);
|
|
72
|
+
const data = [];
|
|
73
|
+
for (const e of sync) {
|
|
74
|
+
const { __update_epoch, __sync_epoch, ...obj } = e;
|
|
75
|
+
data.push(obj);
|
|
76
|
+
}
|
|
77
|
+
return data;
|
|
56
78
|
}
|
|
57
79
|
return this.outerAdapter.index(trx);
|
|
58
80
|
}
|
|
59
|
-
async query(trx,
|
|
81
|
+
async query(trx, query, pagination, params, config) {
|
|
60
82
|
const mode = this.config?.mode?.query;
|
|
83
|
+
let data;
|
|
61
84
|
if (mode === 'incremental') {
|
|
62
|
-
const { action, sync } = await this.syncQuery(trx,
|
|
63
|
-
log_1.Log.debug('bucket', this.
|
|
64
|
-
|
|
85
|
+
const { action, sync } = await this.syncQuery(trx, query, pagination, params);
|
|
86
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.incremental, ${action}`);
|
|
87
|
+
data = sync;
|
|
65
88
|
}
|
|
66
|
-
if (mode === 'all') {
|
|
89
|
+
else if (mode === 'all') {
|
|
67
90
|
const { action, sync } = await this.syncAll(trx);
|
|
68
|
-
log_1.Log.debug('bucket', this.
|
|
69
|
-
|
|
91
|
+
log_1.Log.debug('bucket', this.bucket.schema.name, `CACHE query.all, ${action}`);
|
|
92
|
+
const entries = (await this.innerAdapter.query(trx, query, pagination, params, undefined, this.innerAdapter.nql)).data;
|
|
93
|
+
data = [];
|
|
94
|
+
for (const e of entries) {
|
|
95
|
+
const { __update_epoch, __sync_epoch, ...obj } = e;
|
|
96
|
+
data.push(obj);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
data = (await this.outerAdapter.query(trx, query, pagination, params)).data;
|
|
101
|
+
}
|
|
102
|
+
for (const entry of data) {
|
|
103
|
+
delete entry['__update_epoch'];
|
|
104
|
+
delete entry['__sync_epoch'];
|
|
70
105
|
}
|
|
71
|
-
|
|
106
|
+
if (config?.view) {
|
|
107
|
+
data = await this.bucket.buildMany(trx, data, config.view);
|
|
108
|
+
}
|
|
109
|
+
return { data };
|
|
72
110
|
}
|
|
73
111
|
/* Cache modes */
|
|
74
112
|
async syncOne(trx, id) {
|
|
75
|
-
|
|
113
|
+
let localObj = await this.innerAdapter.get(trx, id);
|
|
76
114
|
if (!localObj) {
|
|
77
115
|
const obj = await this.outerAdapter.get(trx, id);
|
|
78
116
|
if (obj) {
|
|
79
|
-
const entry = new BucketCacheEntry(obj
|
|
117
|
+
const entry = new BucketCacheEntry(obj, this.outerAdapter.getUpdateEpoch(obj), this.lastSyncEpoch);
|
|
80
118
|
await this.innerAdapter.create(trx, entry);
|
|
81
119
|
return { action: 'update', sync: entry };
|
|
82
120
|
}
|
|
83
|
-
return { action: '
|
|
121
|
+
return { action: 'none' };
|
|
84
122
|
}
|
|
85
|
-
const sync = await this.outerAdapter.syncOne(trx, id, localObj.
|
|
123
|
+
const sync = await this.outerAdapter.syncOne(trx, id, localObj.__update_epoch);
|
|
86
124
|
if (sync === null) {
|
|
87
|
-
return { action: '
|
|
125
|
+
return { action: 'none', sync: localObj };
|
|
88
126
|
}
|
|
89
127
|
if (sync === 'deleted') {
|
|
90
128
|
await this.innerAdapter.delete(trx, id);
|
|
91
129
|
return { action: 'delete' };
|
|
92
130
|
}
|
|
93
|
-
localObj
|
|
94
|
-
localObj.updateEpoch = sync.updateEpoch;
|
|
95
|
-
localObj.syncEpoch = datetime_1.NesoiDatetime.now().epoch;
|
|
131
|
+
localObj = new BucketCacheEntry(sync.obj, sync.updateEpoch, datetime_1.NesoiDatetime.now().epoch);
|
|
96
132
|
await this.innerAdapter.put(trx, localObj);
|
|
97
|
-
return { action: 'update', sync };
|
|
133
|
+
return { action: 'update', sync: localObj };
|
|
98
134
|
}
|
|
99
135
|
async syncOneAndPast(trx, id) {
|
|
100
136
|
const localObj = await this.innerAdapter.get(trx, id);
|
|
@@ -102,54 +138,52 @@ class BucketCache {
|
|
|
102
138
|
const obj = await this.outerAdapter.get(trx, id);
|
|
103
139
|
if (obj) {
|
|
104
140
|
await this.innerAdapter.create(trx, obj);
|
|
105
|
-
return { action: 'update', sync:
|
|
106
|
-
obj,
|
|
107
|
-
updateEpoch: this.outerAdapter.getUpdateEpoch(obj)
|
|
108
|
-
} };
|
|
141
|
+
return { action: 'update', sync: new BucketCacheEntry(obj, this.outerAdapter.getUpdateEpoch(obj), datetime_1.NesoiDatetime.now().epoch) };
|
|
109
142
|
}
|
|
110
|
-
return { action: '
|
|
143
|
+
return { action: 'none' };
|
|
111
144
|
}
|
|
112
|
-
const sync = await this.outerAdapter.syncOneAndPast(trx, id, localObj.
|
|
145
|
+
const sync = await this.outerAdapter.syncOneAndPast(trx, id, localObj.__update_epoch);
|
|
113
146
|
if (sync === null) {
|
|
114
|
-
return { action: '
|
|
147
|
+
return { action: 'none', sync: localObj };
|
|
115
148
|
}
|
|
116
149
|
if (sync === 'deleted') {
|
|
117
150
|
await this.innerAdapter.delete(trx, id);
|
|
118
151
|
return { action: 'delete' };
|
|
119
152
|
}
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
const entries = sync.map(s => new BucketCacheEntry(s.obj, s.updateEpoch, datetime_1.NesoiDatetime.now().epoch));
|
|
154
|
+
await this.innerAdapter.putMany(trx, entries);
|
|
155
|
+
return { action: 'update', sync: entries.find(e => e.id === id) };
|
|
122
156
|
}
|
|
123
157
|
async syncAll(trx) {
|
|
124
158
|
const sync = await this.outerAdapter.syncAll(trx, this.lastHash, this.lastUpdateEpoch);
|
|
125
159
|
if (sync === null) {
|
|
126
160
|
const all = await this.innerAdapter.index(trx);
|
|
127
|
-
return { action: '
|
|
161
|
+
return { action: 'none', sync: all };
|
|
128
162
|
}
|
|
129
163
|
this.lastUpdateEpoch = sync.updateEpoch;
|
|
130
164
|
this.lastHash = sync.hash;
|
|
131
165
|
this.lastSyncEpoch = datetime_1.NesoiDatetime.now().epoch;
|
|
132
|
-
const entries = sync.sync.map(s => new BucketCacheEntry(s.obj
|
|
166
|
+
const entries = sync.sync.map(s => new BucketCacheEntry(s.obj, s.updateEpoch, this.lastSyncEpoch));
|
|
133
167
|
if (sync.reset) {
|
|
134
168
|
await this.innerAdapter.deleteEverything(trx);
|
|
135
169
|
await this.innerAdapter.putMany(trx, entries);
|
|
136
|
-
return { action: 'reset', sync:
|
|
170
|
+
return { action: 'reset', sync: entries };
|
|
137
171
|
}
|
|
138
172
|
await this.innerAdapter.putMany(trx, entries);
|
|
139
|
-
return { action: 'update', sync:
|
|
173
|
+
return { action: 'update', sync: entries };
|
|
140
174
|
}
|
|
141
|
-
async syncQuery(trx,
|
|
175
|
+
async syncQuery(trx, query, pagination, params) {
|
|
142
176
|
// 1. Query id and epoch from outer adapter
|
|
143
|
-
const outerMetadata = await this.outerAdapter.query(trx, query, pagination,
|
|
177
|
+
const outerMetadata = await this.outerAdapter.query(trx, query, pagination, params, {
|
|
144
178
|
metadataOnly: true
|
|
145
179
|
});
|
|
146
180
|
if (!outerMetadata.data.length) {
|
|
147
|
-
return { action: '
|
|
181
|
+
return { action: 'none', sync: [] };
|
|
148
182
|
}
|
|
149
183
|
// 2. Read ids from the inner adapter
|
|
150
184
|
const innerData = await this.innerAdapter.query(trx, {
|
|
151
185
|
'id in': outerMetadata.data.map(obj => obj.id)
|
|
152
|
-
});
|
|
186
|
+
}, undefined, undefined, undefined, this.innerAdapter.nql);
|
|
153
187
|
// 3. Filter modified query results
|
|
154
188
|
const outerEpoch = {};
|
|
155
189
|
for (const i in outerMetadata.data) {
|
|
@@ -159,18 +193,18 @@ class BucketCache {
|
|
|
159
193
|
const queryResults = {};
|
|
160
194
|
const modifiedIds = [];
|
|
161
195
|
for (const i in innerData.data) {
|
|
162
|
-
const
|
|
163
|
-
const epoch = outerEpoch[
|
|
164
|
-
if (!epoch || epoch >
|
|
165
|
-
modifiedIds.push(
|
|
196
|
+
const entry = innerData.data[i];
|
|
197
|
+
const epoch = outerEpoch[entry.id];
|
|
198
|
+
if (!epoch || epoch > entry.__update_epoch) {
|
|
199
|
+
modifiedIds.push(entry.id);
|
|
166
200
|
}
|
|
167
201
|
else {
|
|
168
|
-
queryResults[
|
|
202
|
+
queryResults[entry.id] = entry;
|
|
169
203
|
}
|
|
170
204
|
}
|
|
171
205
|
// 4. Nothing changed, return current data
|
|
172
206
|
if (!modifiedIds.length) {
|
|
173
|
-
return { action: '
|
|
207
|
+
return { action: 'none', sync: innerData.data };
|
|
174
208
|
}
|
|
175
209
|
// 5. Query modified objects to outer adapter and merge them on results
|
|
176
210
|
const outerData = await this.outerAdapter.query(trx, {
|
|
@@ -184,7 +218,7 @@ class BucketCache {
|
|
|
184
218
|
updateEpoch
|
|
185
219
|
};
|
|
186
220
|
}
|
|
187
|
-
return { action: 'update', sync: Object.values(queryResults) };
|
|
221
|
+
return { action: 'update', sync: Object.values(queryResults).map(r => new BucketCacheEntry(r.obj, r.updateEpoch, datetime_1.NesoiDatetime.now().epoch)) };
|
|
188
222
|
}
|
|
189
223
|
}
|
|
190
224
|
exports.BucketCache = BucketCache;
|
|
@@ -22,6 +22,17 @@ export declare class BucketGraph<M extends $Module, $ extends $Bucket> {
|
|
|
22
22
|
silent?: boolean;
|
|
23
23
|
no_tenancy?: boolean;
|
|
24
24
|
}): Promise<Obj | Obj[] | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Read the data from a link
|
|
27
|
+
*
|
|
28
|
+
* - Options
|
|
29
|
+
* - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
|
|
30
|
+
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
31
|
+
*/
|
|
32
|
+
readManyLinks<LinkName extends keyof $['graph']['links'], LinkBucketName extends $['graph']['links'][LinkName]['bucket']['refName'], LinkBucket extends M['buckets'][LinkBucketName], Obj = LinkBucket['#data']>(trx: AnyTrxNode, objs: $['#data'][], link: LinkName, options?: {
|
|
33
|
+
silent?: boolean;
|
|
34
|
+
no_tenancy?: boolean;
|
|
35
|
+
}): Promise<Obj[] | Obj[][]>;
|
|
25
36
|
/**
|
|
26
37
|
* Read the data from a link and build it with a given view
|
|
27
38
|
*
|
|
@@ -4,6 +4,8 @@ exports.BucketGraph = void 0;
|
|
|
4
4
|
const trx_node_1 = require("../../../../engine/transaction/trx_node");
|
|
5
5
|
const log_1 = require("../../../../engine/util/log");
|
|
6
6
|
const error_1 = require("../../../../engine/data/error");
|
|
7
|
+
const memory_bucket_adapter_1 = require("../adapters/memory.bucket_adapter");
|
|
8
|
+
const bucket_cache_1 = require("../cache/bucket_cache");
|
|
7
9
|
/**
|
|
8
10
|
* @category Elements
|
|
9
11
|
* @subcategory Entity
|
|
@@ -30,12 +32,13 @@ class BucketGraph {
|
|
|
30
32
|
: this.bucket.getTenancyQuery(trx);
|
|
31
33
|
// Query
|
|
32
34
|
const otherBucket = trx_node_1.TrxNode.getModule(trx).buckets[schema.bucket.refName];
|
|
33
|
-
const
|
|
35
|
+
const adapter = otherBucket.cache || otherBucket.adapter;
|
|
36
|
+
const links = await adapter.query(trx, {
|
|
34
37
|
...schema.query,
|
|
35
38
|
'#and': tenancy
|
|
36
39
|
}, {
|
|
37
40
|
perPage: schema.many ? undefined : 1,
|
|
38
|
-
}, { ...obj });
|
|
41
|
+
}, [{ ...obj }]);
|
|
39
42
|
// Empty response
|
|
40
43
|
if (!schema.many && !schema.optional && !links.data.length) {
|
|
41
44
|
// silent = undefined
|
|
@@ -57,6 +60,57 @@ class BucketGraph {
|
|
|
57
60
|
return links.data[0];
|
|
58
61
|
}
|
|
59
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Read the data from a link
|
|
65
|
+
*
|
|
66
|
+
* - Options
|
|
67
|
+
* - `silent`: If not found, returns undefined instead of raising an exception (default: `false`)
|
|
68
|
+
* - `no_tenancy`: Don't apply tenancy rules (default: `false`)
|
|
69
|
+
*/
|
|
70
|
+
async readManyLinks(trx, objs, link, options) {
|
|
71
|
+
log_1.Log.trace('bucket', this.bucketName, `Read link ${link}`);
|
|
72
|
+
const schema = this.schema.links[link];
|
|
73
|
+
// Make tenancy query
|
|
74
|
+
const tenancy = (options?.no_tenancy)
|
|
75
|
+
? undefined
|
|
76
|
+
: this.bucket.getTenancyQuery(trx);
|
|
77
|
+
// Query
|
|
78
|
+
const otherBucket = trx_node_1.TrxNode.getModule(trx).buckets[schema.bucket.refName];
|
|
79
|
+
// let tempData: Record<string, any> = {};
|
|
80
|
+
let tempAdapter;
|
|
81
|
+
if (otherBucket.adapter instanceof memory_bucket_adapter_1.MemoryBucketAdapter) {
|
|
82
|
+
tempAdapter = otherBucket.cache || otherBucket.adapter;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const adapter = otherBucket.cache || otherBucket.adapter;
|
|
86
|
+
const allLinks = await adapter.query(trx, {
|
|
87
|
+
...schema.query,
|
|
88
|
+
'#and': tenancy
|
|
89
|
+
}, undefined, objs.map(obj => ({ ...obj })));
|
|
90
|
+
const tempData = {};
|
|
91
|
+
for (const obj of allLinks.data)
|
|
92
|
+
tempData[obj.id] = obj;
|
|
93
|
+
tempAdapter = new memory_bucket_adapter_1.MemoryBucketAdapter(otherBucket.schema, tempData);
|
|
94
|
+
}
|
|
95
|
+
const links = [];
|
|
96
|
+
for (const obj of objs) {
|
|
97
|
+
const result = tempAdapter instanceof bucket_cache_1.BucketCache
|
|
98
|
+
? await tempAdapter.query(trx, schema.query, {
|
|
99
|
+
perPage: schema.many ? undefined : 1,
|
|
100
|
+
}, [{ ...obj }], undefined)
|
|
101
|
+
: await tempAdapter.query(trx, schema.query, {
|
|
102
|
+
perPage: schema.many ? undefined : 1,
|
|
103
|
+
}, [{ ...obj }], undefined, tempAdapter.nql);
|
|
104
|
+
if (schema.many) {
|
|
105
|
+
links.push(result.data);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
links.push(result.data[0]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Empty response
|
|
112
|
+
return links;
|
|
113
|
+
}
|
|
60
114
|
/**
|
|
61
115
|
* Read the data from a link and build it with a given view
|
|
62
116
|
*
|
|
@@ -102,7 +156,7 @@ class BucketGraph {
|
|
|
102
156
|
'#and': tenancy
|
|
103
157
|
}, {
|
|
104
158
|
perPage: 1,
|
|
105
|
-
}, { ...obj });
|
|
159
|
+
}, [{ ...obj }]);
|
|
106
160
|
return !!links.data.length;
|
|
107
161
|
}
|
|
108
162
|
}
|
|
@@ -55,7 +55,6 @@ class $BucketModel {
|
|
|
55
55
|
}
|
|
56
56
|
// If it's a list or dict, or an object
|
|
57
57
|
if (field.type === 'list' || field.type === 'dict') {
|
|
58
|
-
// If not, iterate
|
|
59
58
|
next.push({
|
|
60
59
|
i: item.i + 1,
|
|
61
60
|
field: field.children['#']
|
|
@@ -70,6 +69,10 @@ class $BucketModel {
|
|
|
70
69
|
})));
|
|
71
70
|
continue;
|
|
72
71
|
}
|
|
72
|
+
if (field.type === 'unknown') {
|
|
73
|
+
results.push(field);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
73
76
|
const child = field.children[path];
|
|
74
77
|
if (child) {
|
|
75
78
|
next.push({
|
|
@@ -127,53 +130,53 @@ class $BucketModel {
|
|
|
127
130
|
while (poll.length) {
|
|
128
131
|
const next = [];
|
|
129
132
|
for (const entry of poll) {
|
|
130
|
-
const val = obj[entry.path];
|
|
133
|
+
const val = entry.obj[entry.path];
|
|
131
134
|
if (val === undefined) {
|
|
132
135
|
continue;
|
|
133
136
|
}
|
|
134
137
|
if (val === null) {
|
|
135
|
-
copy[entry.path] = null;
|
|
138
|
+
entry.copy[entry.path] = null;
|
|
136
139
|
continue;
|
|
137
140
|
}
|
|
138
141
|
if (entry.field.type === 'list') {
|
|
139
142
|
if (!Array.isArray(val))
|
|
140
143
|
continue;
|
|
141
|
-
copy[entry.path] = [];
|
|
144
|
+
entry.copy[entry.path] = [];
|
|
142
145
|
next.push(...val.map((_, i) => ({
|
|
143
146
|
path: i.toString(),
|
|
144
147
|
obj: val,
|
|
145
|
-
copy: copy[entry.path],
|
|
146
|
-
field: entry.field.children['
|
|
148
|
+
copy: entry.copy[entry.path],
|
|
149
|
+
field: entry.field.children['#']
|
|
147
150
|
})));
|
|
148
151
|
}
|
|
149
152
|
else if (entry.field.type === 'dict') {
|
|
150
153
|
if (typeof val !== 'object' || Array.isArray(val))
|
|
151
154
|
continue;
|
|
152
|
-
copy[entry.path] = {};
|
|
155
|
+
entry.copy[entry.path] = {};
|
|
153
156
|
next.push(...Object.keys(val).map((path) => ({
|
|
154
157
|
path,
|
|
155
158
|
obj: val,
|
|
156
|
-
copy: copy[entry.path],
|
|
157
|
-
field: entry.field.children['
|
|
159
|
+
copy: entry.copy[entry.path],
|
|
160
|
+
field: entry.field.children['#']
|
|
158
161
|
})));
|
|
159
162
|
}
|
|
160
163
|
else if (entry.field.type === 'obj') {
|
|
161
164
|
if (typeof val !== 'object' || Array.isArray(val))
|
|
162
165
|
continue;
|
|
163
|
-
copy[entry.path] = {};
|
|
166
|
+
entry.copy[entry.path] = {};
|
|
164
167
|
next.push(...Object.keys(entry.field.children).map(path => ({
|
|
165
168
|
path: path,
|
|
166
169
|
obj: val,
|
|
167
|
-
copy: copy[entry.path],
|
|
170
|
+
copy: entry.copy[entry.path],
|
|
168
171
|
field: entry.field.children[path]
|
|
169
172
|
})));
|
|
170
173
|
}
|
|
171
174
|
else if (entry.field.type === 'union') {
|
|
172
175
|
// TODO: ??????????
|
|
173
|
-
copy[entry.path] = obj[entry.path];
|
|
176
|
+
entry.copy[entry.path] = entry.obj[entry.path];
|
|
174
177
|
}
|
|
175
178
|
else {
|
|
176
|
-
copy[entry.path] = obj[entry.path];
|
|
179
|
+
entry.copy[entry.path] = entry.obj[entry.path];
|
|
177
180
|
}
|
|
178
181
|
}
|
|
179
182
|
poll = next;
|
|
@@ -2,7 +2,6 @@ import { $Module, $Space } from "../../../../schema";
|
|
|
2
2
|
import { $BucketModelField, $BucketModelFieldType, $BucketModelFields } from './bucket_model.schema';
|
|
3
3
|
import { NesoiDate } from "../../../../engine/data/date";
|
|
4
4
|
import { BucketModelpathObjInfer, BucketModelpathDictInfer, BucketModelpathListInfer, BucketModelObjInfer, BucketQuerypathDictInfer, BucketQuerypathListInfer, BucketQuerypathObjInfer, BucketModelpathUnionInfer } from './bucket_model.infer';
|
|
5
|
-
import { EnumFromName, EnumName } from '../../constants/constants.schema';
|
|
6
5
|
import { NesoiDecimal } from "../../../../engine/data/decimal";
|
|
7
6
|
import { NesoiDatetime } from "../../../../engine/data/datetime";
|
|
8
7
|
import { NesoiFile } from "../../../../engine/data/file";
|
|
@@ -49,10 +48,10 @@ export declare class BucketModelFieldFactory<Space extends $Space, Module extend
|
|
|
49
48
|
}, {
|
|
50
49
|
'': NesoiDecimal;
|
|
51
50
|
}>;
|
|
52
|
-
enum<Enums extends
|
|
53
|
-
'': Options extends string ? keyof
|
|
51
|
+
enum<Enums extends Module['constants']['enums'], Options extends (keyof Enums & string) | (readonly string[])>(options: Options): BucketModelFieldBuilder<Module, Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options], Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options], [false, false], {
|
|
52
|
+
'': Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options];
|
|
54
53
|
}, {
|
|
55
|
-
'': Options extends string ? keyof
|
|
54
|
+
'': Options extends string ? keyof Module["constants"]["enums"][Options]["#data"] : Options extends (infer X)[] | readonly (infer X)[] ? X : Options[keyof Options];
|
|
56
55
|
}>;
|
|
57
56
|
get int(): BucketModelFieldBuilder<Module, number, number, [false, false], {
|
|
58
57
|
'': number;
|
|
@@ -91,6 +91,8 @@ class NQL_RuleTree {
|
|
|
91
91
|
let by = value['by'];
|
|
92
92
|
if (by) {
|
|
93
93
|
for (const key of by) {
|
|
94
|
+
if (Object.values(bucket.adapter.config.meta).includes(key))
|
|
95
|
+
continue;
|
|
94
96
|
const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, key);
|
|
95
97
|
if (!fields.length) {
|
|
96
98
|
throw new Error(`Field '${key}' not found on bucket '${bucket.schema.name}'`);
|
|
@@ -148,6 +150,10 @@ class NQL_RuleTree {
|
|
|
148
150
|
throw new Error(`Invalid term '${key}'`);
|
|
149
151
|
}
|
|
150
152
|
const [_, or, fieldpath, not, case_i, op] = term;
|
|
153
|
+
if (Object.values(bucket.adapter.config.meta).includes(fieldpath)) {
|
|
154
|
+
const _op = this.parseOp(bucket.schema.name, [{ type: 'datetime', name: fieldpath }], op);
|
|
155
|
+
return { type: 'fieldpath', or: !!or, fieldpath, not: !!not, case_i: !!case_i, op: _op };
|
|
156
|
+
}
|
|
151
157
|
const fields = bucket_model_schema_1.$BucketModel.getField(bucket.schema.model, fieldpath);
|
|
152
158
|
if (!fields.length) {
|
|
153
159
|
throw new Error(`Field '${fieldpath}' not found on bucket '${bucket.schema.name}'`);
|
|
@@ -242,7 +248,7 @@ class NQL_RuleTree {
|
|
|
242
248
|
};
|
|
243
249
|
for (const key in value) {
|
|
244
250
|
if (key.startsWith('@') || key.startsWith('or @')) {
|
|
245
|
-
const refField = key.match(/(or )?@(\w+)\.(.*)/);
|
|
251
|
+
const refField = key.match(/(or )?@([\w:]+)\.(.*)/);
|
|
246
252
|
if (!refField) {
|
|
247
253
|
throw new Error(`Invalid bucket field '${key}'`);
|
|
248
254
|
}
|
|
@@ -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
|
|
18
|
+
abstract run(trx: AnyTrxNode, part: NQL_Part, params: Record<string, any>[], 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
|
|
27
|
+
run(trx: AnyTrxNode, query: NQL_CompiledQuery, pagination?: NQL_Pagination, params?: Record<string, any>[], view?: $BucketView, runner?: NQLRunner): Promise<NQL_Result>;
|
|
28
28
|
linkExternal(bucket: AnyBucket): void;
|
|
29
29
|
}
|
|
30
30
|
export {};
|
|
@@ -22,7 +22,9 @@ class NQL_Engine {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
async run(trx, query, pagination, params = {}, view) {
|
|
25
|
+
async run(trx, query, pagination, params = [{}], view, runner) {
|
|
26
|
+
if (!params.length)
|
|
27
|
+
params = [{}];
|
|
26
28
|
let result = {
|
|
27
29
|
data: []
|
|
28
30
|
};
|
|
@@ -30,8 +32,8 @@ class NQL_Engine {
|
|
|
30
32
|
const part_i = query.execOrder[i];
|
|
31
33
|
const part = query.parts[part_i];
|
|
32
34
|
// Run part
|
|
33
|
-
const
|
|
34
|
-
const out = await
|
|
35
|
+
const _runner = runner || this.runners[part.union.meta.scope];
|
|
36
|
+
const out = await _runner.run(trx, part, params, pagination, view);
|
|
35
37
|
result = out;
|
|
36
38
|
// Part failed, return
|
|
37
39
|
// Failure here is only when a single value is expected,
|
|
@@ -43,7 +45,9 @@ class NQL_Engine {
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
// Fill part params
|
|
46
|
-
|
|
48
|
+
for (const paramGroup of params) {
|
|
49
|
+
paramGroup[`%__${part_i}__%`] = part.many ? result.data : result.data[0];
|
|
50
|
+
}
|
|
47
51
|
}
|
|
48
52
|
return result;
|
|
49
53
|
}
|