nesoi 3.3.30 → 3.4.1
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/bucket.element.js +3 -3
- package/lib/elements/edge/controller/adapters/controller_adapter.js +1 -3
- package/lib/elements/entities/bucket/adapters/memory.nql.js +12 -18
- package/lib/elements/entities/bucket/bucket.d.ts +6 -2
- package/lib/elements/entities/bucket/bucket.js +4 -4
- package/lib/elements/entities/bucket/graph/bucket_graph.js +13 -3
- package/lib/elements/entities/bucket/model/bucket_model.convert.js +9 -17
- package/lib/elements/entities/bucket/model/bucket_model.d.ts +6 -1
- package/lib/elements/entities/bucket/model/bucket_model.js +182 -33
- package/lib/elements/entities/bucket/model/bucket_model.schema.d.ts +1 -1
- package/lib/elements/entities/bucket/model/bucket_model.schema.js +2 -2
- package/lib/elements/entities/bucket/query/nql.schema.d.ts +1 -0
- package/lib/elements/entities/bucket/query/nql_compiler.js +5 -4
- package/lib/elements/entities/bucket/query/nql_engine.js +0 -2
- package/lib/elements/entities/bucket/view/bucket_view.d.ts +5 -4
- package/lib/elements/entities/bucket/view/bucket_view.js +300 -188
- package/lib/elements/entities/bucket/view/bucket_view.schema.d.ts +5 -3
- package/lib/elements/entities/bucket/view/bucket_view.schema.js +3 -1
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.d.ts +15 -5
- package/lib/elements/entities/bucket/view/bucket_view_field.builder.js +82 -28
- package/lib/elements/entities/message/template/message_template_parser.d.ts +5 -1
- package/lib/elements/entities/message/template/message_template_parser.js +13 -7
- package/lib/engine/daemon.d.ts +1 -11
- package/lib/engine/daemon.js +3 -26
- package/lib/engine/data/datetime.d.ts +35 -1
- package/lib/engine/data/datetime.js +103 -16
- package/lib/engine/data/error.d.ts +17 -0
- package/lib/engine/data/error.js +16 -0
- package/lib/engine/transaction/nodes/bucket.trx_node.d.ts +8 -2
- package/lib/engine/transaction/nodes/bucket.trx_node.js +16 -4
- package/lib/engine/transaction/nodes/bucket_query.trx_node.js +1 -1
- package/lib/engine/transaction/nodes/external.trx_node.d.ts +4 -1
- package/lib/engine/transaction/nodes/external.trx_node.js +19 -19
- package/lib/engine/transaction/nodes/job.trx_node.d.ts +4 -3
- package/lib/engine/transaction/nodes/job.trx_node.js +6 -2
- package/lib/engine/transaction/nodes/resource.trx_node.js +2 -1
- package/lib/engine/transaction/trx.d.ts +4 -3
- package/lib/engine/transaction/trx.js +15 -11
- package/lib/engine/transaction/trx_engine.config.d.ts +7 -3
- package/lib/engine/transaction/trx_engine.d.ts +7 -3
- package/lib/engine/transaction/trx_engine.js +99 -45
- package/lib/engine/transaction/trx_node.d.ts +4 -1
- package/lib/engine/transaction/trx_node.js +12 -9
- package/package.json +1 -1
- package/tools/joaquin/bucket.d.ts +6 -2
- package/tools/joaquin/bucket.js +4 -4
- package/tsconfig.build.tsbuildinfo +1 -1
package/lib/engine/data/error.js
CHANGED
|
@@ -229,6 +229,10 @@ var NesoiError;
|
|
|
229
229
|
return new BaseError('Bucket.FieldNotFound', `Field '${$.path}' not found on bucket '${$.bucket}'`, Status.NOT_FOUND, $);
|
|
230
230
|
}
|
|
231
231
|
Bucket.FieldNotFound = FieldNotFound;
|
|
232
|
+
function IdempotentTransaction($) {
|
|
233
|
+
return new BaseError('Bucket.IdempotentTransaction', `Action '${$.action}' on bucket '${$.bucket}' not allowed for idempotent transaction ${$.trx}`, Status.NOT_FOUND, $);
|
|
234
|
+
}
|
|
235
|
+
Bucket.IdempotentTransaction = IdempotentTransaction;
|
|
232
236
|
let Graph;
|
|
233
237
|
(function (Graph) {
|
|
234
238
|
function LinkNotFound($) {
|
|
@@ -292,6 +296,10 @@ var NesoiError;
|
|
|
292
296
|
})(Fieldpath = Bucket.Fieldpath || (Bucket.Fieldpath = {}));
|
|
293
297
|
let Model;
|
|
294
298
|
(function (Model) {
|
|
299
|
+
function InvalidModelpath($) {
|
|
300
|
+
return new BaseError('Bucket.Model.InvalidModelpath', `Modelpath '${$.modelpath}' not found on bucket '${$.bucket}'`, Status.BAD_REQUEST, $);
|
|
301
|
+
}
|
|
302
|
+
Model.InvalidModelpath = InvalidModelpath;
|
|
295
303
|
function InvalidEnum($) {
|
|
296
304
|
return new BaseError('Bucket.Model.InvalidEnum', `Value '${$.value}' for bucket '${$.bucket}' doesn't match the options: ${$.options}.`, Status.BAD_REQUEST, $);
|
|
297
305
|
}
|
|
@@ -312,6 +320,14 @@ var NesoiError;
|
|
|
312
320
|
return new BaseError('Bucket.Model.InvalidNesoiDatetime', `Value '${$.value}' for bucket '${$.bucket}' is not a Nesoi datetime.`, Status.BAD_REQUEST, $);
|
|
313
321
|
}
|
|
314
322
|
Model.InvalidNesoiDatetime = InvalidNesoiDatetime;
|
|
323
|
+
function InvalidNesoiDuration($) {
|
|
324
|
+
return new BaseError('Bucket.Model.InvalidNesoiDuration', `Value '${$.value}' for bucket '${$.bucket}' is not a Nesoi duration.`, Status.BAD_REQUEST, $);
|
|
325
|
+
}
|
|
326
|
+
Model.InvalidNesoiDuration = InvalidNesoiDuration;
|
|
327
|
+
function InvalidNesoiDecimal($) {
|
|
328
|
+
return new BaseError('Bucket.Model.InvalidNesoiDecimal', `Value '${$.value}' for bucket '${$.bucket}' is not a Nesoi decimal.`, Status.BAD_REQUEST, $);
|
|
329
|
+
}
|
|
330
|
+
Model.InvalidNesoiDecimal = InvalidNesoiDecimal;
|
|
315
331
|
})(Model = Bucket.Model || (Bucket.Model = {}));
|
|
316
332
|
let Drive;
|
|
317
333
|
(function (Drive) {
|
|
@@ -165,8 +165,12 @@ export declare class BucketTrxNode<M extends $Module, $ extends $Bucket> {
|
|
|
165
165
|
* so the behavior depends on the bucket used.
|
|
166
166
|
*/
|
|
167
167
|
deleteMany(ids: $['#data']['id'][]): Promise<void>;
|
|
168
|
-
buildOne<V extends ViewName<$>, Obj extends ViewObj<$, V>>(obj: $['#data'], view: V
|
|
169
|
-
|
|
168
|
+
buildOne<V extends ViewName<$>, Obj extends ViewObj<$, V>>(obj: $['#data'], view: V, flags?: {
|
|
169
|
+
serialize: boolean;
|
|
170
|
+
}): Promise<Obj>;
|
|
171
|
+
buildMany<V extends ViewName<$>, Obj extends ViewObj<$, V>>(objs: $['#data'][], view: V, flags?: {
|
|
172
|
+
serialize: boolean;
|
|
173
|
+
}): Promise<Obj[]>;
|
|
170
174
|
/**
|
|
171
175
|
* Methods to use the Bucket's drive (file storage).
|
|
172
176
|
*/
|
|
@@ -231,6 +235,8 @@ export declare class BucketUnsafeTrxNode<M extends $Module, $ extends $Bucket> {
|
|
|
231
235
|
export declare class BucketDriveTrxNode<M extends $Module, $ extends $Bucket> {
|
|
232
236
|
private bucketTrx;
|
|
233
237
|
private drive;
|
|
238
|
+
private tag;
|
|
239
|
+
private trx;
|
|
234
240
|
constructor(bucketTrx: BucketTrxNode<M, $>, drive: DriveAdapter);
|
|
235
241
|
/**
|
|
236
242
|
* Read the contents of a File of this bucket's drive
|
|
@@ -41,6 +41,10 @@ class BucketTrxNode {
|
|
|
41
41
|
*/
|
|
42
42
|
async wrap(action, input, fn, fmtTrxOut, idempotent = false) {
|
|
43
43
|
const wrapped = async (parentTrx, bucket) => {
|
|
44
|
+
const trx_idempotent = parentTrx.trx.idempotent;
|
|
45
|
+
if (trx_idempotent && !idempotent) {
|
|
46
|
+
throw error_1.NesoiError.Bucket.IdempotentTransaction({ bucket: this.tag.full, trx: this.trx.globalId, action });
|
|
47
|
+
}
|
|
44
48
|
const trx = trx_node_1.TrxNode.makeChildNode(parentTrx, bucket.schema.module, 'bucket', bucket.schema.name);
|
|
45
49
|
trx_node_1.TrxNode.open(trx, action, input);
|
|
46
50
|
let out;
|
|
@@ -55,6 +59,10 @@ class BucketTrxNode {
|
|
|
55
59
|
};
|
|
56
60
|
if (this.external) {
|
|
57
61
|
const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, idempotent);
|
|
62
|
+
// The if below is not strictly necessary but avoids a warning.
|
|
63
|
+
if (idempotent) {
|
|
64
|
+
return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
|
|
65
|
+
}
|
|
58
66
|
return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
|
|
59
67
|
}
|
|
60
68
|
else {
|
|
@@ -322,11 +330,11 @@ class BucketTrxNode {
|
|
|
322
330
|
/*
|
|
323
331
|
Build
|
|
324
332
|
*/
|
|
325
|
-
async buildOne(obj, view) {
|
|
326
|
-
return this.wrap('buildOne', { obj }, (trx, bucket) => bucket.buildOne(trx, obj, view), () => undefined);
|
|
333
|
+
async buildOne(obj, view, flags) {
|
|
334
|
+
return this.wrap('buildOne', { obj }, (trx, bucket) => bucket.buildOne(trx, obj, view, flags), () => undefined);
|
|
327
335
|
}
|
|
328
|
-
async buildMany(objs, view) {
|
|
329
|
-
return this.wrap('buildMany', { objs }, (trx, bucket) => bucket.buildMany(trx, objs, view), () => undefined);
|
|
336
|
+
async buildMany(objs, view, flags) {
|
|
337
|
+
return this.wrap('buildMany', { objs }, (trx, bucket) => bucket.buildMany(trx, objs, view, flags), () => undefined);
|
|
330
338
|
}
|
|
331
339
|
/*
|
|
332
340
|
Drive
|
|
@@ -456,9 +464,13 @@ exports.BucketUnsafeTrxNode = BucketUnsafeTrxNode;
|
|
|
456
464
|
class BucketDriveTrxNode {
|
|
457
465
|
bucketTrx;
|
|
458
466
|
drive;
|
|
467
|
+
tag;
|
|
468
|
+
trx;
|
|
459
469
|
constructor(bucketTrx, drive) {
|
|
460
470
|
this.bucketTrx = bucketTrx;
|
|
461
471
|
this.drive = drive;
|
|
472
|
+
this.tag = bucketTrx.tag;
|
|
473
|
+
this.trx = bucketTrx.trx;
|
|
462
474
|
}
|
|
463
475
|
/**
|
|
464
476
|
* Read the contents of a File of this bucket's drive
|
|
@@ -71,7 +71,7 @@ class BucketQueryTrxNode {
|
|
|
71
71
|
};
|
|
72
72
|
if (this.external) {
|
|
73
73
|
const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, true);
|
|
74
|
-
return ext.
|
|
74
|
+
return ext.run(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
|
|
75
75
|
}
|
|
76
76
|
else {
|
|
77
77
|
return wrapped(this.trx, this.bucket);
|
|
@@ -13,5 +13,8 @@ export declare class ExternalTrxNode<M extends $Module, $ extends $Topic> {
|
|
|
13
13
|
private daemon;
|
|
14
14
|
constructor(trx: TrxNode<any, M, any>, tag: Tag, idempotent?: boolean);
|
|
15
15
|
run_and_hold(element: (trx: AnyTrxNode) => any, fn: (trx: AnyTrxNode, element: any) => Promise<any>): Promise<any>;
|
|
16
|
-
|
|
16
|
+
run_isolated(element: (trx: AnyTrxNode) => any, fn: (trx: AnyTrxNode, element: any) => Promise<any>): Promise<any>;
|
|
17
|
+
run(element: (trx: AnyTrxNode) => any, fn: (trx: AnyTrxNode, element: any) => Promise<any>, options?: {
|
|
18
|
+
isolated?: boolean;
|
|
19
|
+
}): Promise<any>;
|
|
17
20
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ExternalTrxNode = void 0;
|
|
4
4
|
const trx_node_1 = require("../trx_node");
|
|
5
5
|
const error_1 = require("../../data/error");
|
|
6
|
+
const log_1 = require("../../util/log");
|
|
6
7
|
/**
|
|
7
8
|
* @category Engine
|
|
8
9
|
* @subcategory Transaction
|
|
@@ -23,25 +24,26 @@ class ExternalTrxNode {
|
|
|
23
24
|
this.daemon = _module.daemon;
|
|
24
25
|
}
|
|
25
26
|
async run_and_hold(element, fn) {
|
|
26
|
-
|
|
27
|
+
if (this.idempotent) {
|
|
28
|
+
log_1.Log.debug('trx', 'external', `Attempt to hold idempotent external node of transaction ${this.trx.globalId} on ${this.tag.full} ignored. Running without hold.`);
|
|
29
|
+
return this.run(element, fn);
|
|
30
|
+
}
|
|
31
|
+
const parent = this.trx.trx;
|
|
27
32
|
const module = trx_node_1.TrxNode.getModule(this.trx);
|
|
28
33
|
const trx = trx_node_1.TrxNode.makeChildNode(this.trx, module.name, 'externals', this.tag.full);
|
|
29
34
|
trx_node_1.TrxNode.open(trx, '~', {
|
|
30
35
|
tag: this.tag
|
|
31
36
|
});
|
|
37
|
+
const origin = module.name + '::trx:' + parent.id;
|
|
38
|
+
const tag = this.tag.module + '::trx:' + parent.id;
|
|
32
39
|
let out;
|
|
33
40
|
try {
|
|
34
41
|
const dtrx = await this.daemon.trx(this.tag.module)
|
|
35
|
-
.origin(
|
|
36
|
-
// This can be overriden by the TrxEngine if the root
|
|
37
|
-
// it not idempotent (which makes it not idempotent)
|
|
38
|
-
.idempotent(this.idempotent);
|
|
39
|
-
let idempotent = false;
|
|
42
|
+
.origin(origin);
|
|
40
43
|
const hold = await dtrx
|
|
41
44
|
.auth_inherit(trx)
|
|
42
45
|
.run_and_hold(async (extTrx) => {
|
|
43
46
|
try {
|
|
44
|
-
idempotent = extTrx.trx.idempotent;
|
|
45
47
|
return await fn(extTrx, element(extTrx));
|
|
46
48
|
}
|
|
47
49
|
catch (e) {
|
|
@@ -50,15 +52,13 @@ class ExternalTrxNode {
|
|
|
50
52
|
finally {
|
|
51
53
|
trx_node_1.TrxNode.merge(trx, extTrx);
|
|
52
54
|
}
|
|
53
|
-
},
|
|
55
|
+
}, parent.id);
|
|
54
56
|
if (hold.status.state === 'error') {
|
|
55
57
|
throw hold.status.error;
|
|
56
58
|
}
|
|
57
59
|
out = hold.status.output;
|
|
58
|
-
if (!
|
|
59
|
-
|
|
60
|
-
root.holds[root.id] = hold;
|
|
61
|
-
}
|
|
60
|
+
if (!(tag in parent.holds)) {
|
|
61
|
+
parent.holds[tag] = hold;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
catch (e) {
|
|
@@ -67,8 +67,11 @@ class ExternalTrxNode {
|
|
|
67
67
|
trx_node_1.TrxNode.ok(trx, out);
|
|
68
68
|
return out;
|
|
69
69
|
}
|
|
70
|
-
async
|
|
71
|
-
|
|
70
|
+
async run_isolated(element, fn) {
|
|
71
|
+
return this.run(element, fn, { isolated: true });
|
|
72
|
+
}
|
|
73
|
+
async run(element, fn, options) {
|
|
74
|
+
const parent = this.trx.trx;
|
|
72
75
|
const module = trx_node_1.TrxNode.getModule(this.trx);
|
|
73
76
|
const trx = trx_node_1.TrxNode.makeChildNode(this.trx, module.name, 'externals', this.tag.full);
|
|
74
77
|
trx_node_1.TrxNode.open(trx, '~', {
|
|
@@ -77,10 +80,7 @@ class ExternalTrxNode {
|
|
|
77
80
|
let out;
|
|
78
81
|
try {
|
|
79
82
|
const dtrx = await this.daemon.trx(this.tag.module)
|
|
80
|
-
.origin('
|
|
81
|
-
// This can be overriden by the TrxEngine if the root
|
|
82
|
-
// it not idempotent (which makes it not idempotent)
|
|
83
|
-
.idempotent(this.idempotent);
|
|
83
|
+
.origin(module.name + '::trx:' + parent.id);
|
|
84
84
|
const res = await dtrx
|
|
85
85
|
.auth_inherit(trx)
|
|
86
86
|
.run(async (extTrx) => {
|
|
@@ -93,7 +93,7 @@ class ExternalTrxNode {
|
|
|
93
93
|
finally {
|
|
94
94
|
trx_node_1.TrxNode.merge(trx, extTrx);
|
|
95
95
|
}
|
|
96
|
-
},
|
|
96
|
+
}, options?.isolated ? undefined : parent.id, this.idempotent);
|
|
97
97
|
if (res.state === 'error') {
|
|
98
98
|
throw res.error;
|
|
99
99
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { $Module } from "../../../schema";
|
|
2
|
-
import {
|
|
2
|
+
import { TrxNode } from '../trx_node';
|
|
3
3
|
import { $Job } from "../../../elements/blocks/job/job.schema";
|
|
4
|
-
import { Job } from "../../../elements/blocks/job/job";
|
|
5
4
|
import { Message } from "../../../elements/entities/message/message";
|
|
6
5
|
import { JobInput } from "../../../elements/blocks/job/job.types";
|
|
7
6
|
import { Tag } from "../../dependency";
|
|
@@ -15,8 +14,10 @@ export declare class JobTrxNode<M extends $Module, $ extends $Job> {
|
|
|
15
14
|
private ctx?;
|
|
16
15
|
private external;
|
|
17
16
|
private job?;
|
|
17
|
+
private _idempotent;
|
|
18
18
|
constructor(trx: TrxNode<any, M, any>, tag: Tag, ctx?: Record<string, any> | undefined);
|
|
19
|
-
|
|
19
|
+
get idempotent(): this;
|
|
20
|
+
private wrap;
|
|
20
21
|
run(message: JobInput<$>): Promise<$['#output']>;
|
|
21
22
|
forward(message: Message<$['#input']>): Promise<$['#output']>;
|
|
22
23
|
}
|
|
@@ -15,6 +15,7 @@ class JobTrxNode {
|
|
|
15
15
|
ctx;
|
|
16
16
|
external;
|
|
17
17
|
job;
|
|
18
|
+
_idempotent = false;
|
|
18
19
|
constructor(trx, tag, ctx) {
|
|
19
20
|
this.trx = trx;
|
|
20
21
|
this.tag = tag;
|
|
@@ -28,6 +29,10 @@ class JobTrxNode {
|
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
get idempotent() {
|
|
33
|
+
this._idempotent = true;
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
31
36
|
/*
|
|
32
37
|
Wrap
|
|
33
38
|
*/
|
|
@@ -46,8 +51,7 @@ class JobTrxNode {
|
|
|
46
51
|
return out;
|
|
47
52
|
};
|
|
48
53
|
if (this.external) {
|
|
49
|
-
const
|
|
50
|
-
const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, root.idempotent);
|
|
54
|
+
const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, this._idempotent);
|
|
51
55
|
return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
|
|
52
56
|
}
|
|
53
57
|
else {
|
|
@@ -44,7 +44,8 @@ class ResourceTrxNode {
|
|
|
44
44
|
return out;
|
|
45
45
|
};
|
|
46
46
|
if (this.external) {
|
|
47
|
-
const
|
|
47
|
+
const idempotent = action === 'view' || action === 'query';
|
|
48
|
+
const ext = new external_trx_node_1.ExternalTrxNode(this.trx, this.tag, idempotent);
|
|
48
49
|
return ext.run_and_hold(trx => dependency_1.Tag.element(this.tag, trx), wrapped);
|
|
49
50
|
}
|
|
50
51
|
else {
|
|
@@ -20,8 +20,9 @@ export declare class TrxStatus<Output> {
|
|
|
20
20
|
state?: TrxState | undefined;
|
|
21
21
|
output?: Output | undefined;
|
|
22
22
|
error?: NesoiError.BaseError | undefined;
|
|
23
|
+
idempotent: boolean;
|
|
23
24
|
nodes: TrxNodeStatus[];
|
|
24
|
-
constructor(id: string, origin: TrxOrigin, start: NesoiDatetime, end?: NesoiDatetime | undefined, state?: TrxState | undefined, output?: Output | undefined, error?: NesoiError.BaseError | undefined, nodes?: TrxNodeStatus[]);
|
|
25
|
+
constructor(id: string, origin: TrxOrigin, start: NesoiDatetime, end?: NesoiDatetime | undefined, state?: TrxState | undefined, output?: Output | undefined, error?: NesoiError.BaseError | undefined, idempotent?: boolean, nodes?: TrxNodeStatus[]);
|
|
25
26
|
summary(): string;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
@@ -67,8 +68,8 @@ export declare class Trx<S extends $Space, M extends $Module, AuthUsers extends
|
|
|
67
68
|
* to the transaction. Elements should not modify the transaction.
|
|
68
69
|
*/
|
|
69
70
|
static set(node: AnyTrxNode, key: string, value: any): AnyTrx;
|
|
70
|
-
static
|
|
71
|
-
static
|
|
71
|
+
static commitHolds(trx: AnyTrx): Promise<void>;
|
|
72
|
+
static rollbackHolds(trx: AnyTrx): Promise<void>;
|
|
72
73
|
}
|
|
73
74
|
export type AnyTrx = Trx<any, any, any>;
|
|
74
75
|
export {};
|
|
@@ -22,8 +22,9 @@ class TrxStatus {
|
|
|
22
22
|
state;
|
|
23
23
|
output;
|
|
24
24
|
error;
|
|
25
|
+
idempotent;
|
|
25
26
|
nodes;
|
|
26
|
-
constructor(id, origin, start, end, state, output, error, nodes = []) {
|
|
27
|
+
constructor(id, origin, start, end, state, output, error, idempotent = false, nodes = []) {
|
|
27
28
|
this.id = id;
|
|
28
29
|
this.origin = origin;
|
|
29
30
|
this.start = start;
|
|
@@ -31,10 +32,11 @@ class TrxStatus {
|
|
|
31
32
|
this.state = state;
|
|
32
33
|
this.output = output;
|
|
33
34
|
this.error = error;
|
|
35
|
+
this.idempotent = idempotent;
|
|
34
36
|
this.nodes = nodes;
|
|
35
37
|
}
|
|
36
38
|
summary() {
|
|
37
|
-
const state = this.state ? (0, string_1.colored)(`[${this.state}]`, {
|
|
39
|
+
const state = this.state ? (0, string_1.colored)(`[${this.state}]${this.idempotent ? '*' : ''}`, {
|
|
38
40
|
'open': 'lightblue',
|
|
39
41
|
'hold': 'yellow',
|
|
40
42
|
'ok': 'lightgreen',
|
|
@@ -42,10 +44,13 @@ class TrxStatus {
|
|
|
42
44
|
}[this.state]) : 'unknown';
|
|
43
45
|
let str = `${state} ${this.id} ${(0, log_1.anyScopeTag)(this.origin)} `;
|
|
44
46
|
str += (0, string_1.colored)(`[${this.end ? (this.end.epoch - this.start.epoch) : -1}ms]\n`, 'brown');
|
|
45
|
-
function print(nodes, l = 1) {
|
|
47
|
+
function print(nodes, idempotent, l = 1) {
|
|
46
48
|
let str = '';
|
|
47
49
|
nodes.forEach(node => {
|
|
48
|
-
|
|
50
|
+
if (node.ext?.idempotent !== undefined) {
|
|
51
|
+
idempotent = node.ext.idempotent;
|
|
52
|
+
}
|
|
53
|
+
const state = node.state ? (0, string_1.colored)(`[${node.state}]${idempotent ? '*' : ''}`, {
|
|
49
54
|
'open': 'lightblue',
|
|
50
55
|
'hold': 'yellow',
|
|
51
56
|
'ok': 'lightgreen',
|
|
@@ -53,11 +58,11 @@ class TrxStatus {
|
|
|
53
58
|
}[node.state] || 'lightred') : 'unknown';
|
|
54
59
|
str += `${'-'.repeat(l)}${state} ${node.id} ${(0, log_1.anyScopeTag)(node.scope)} ${node.action} ${node.cached_buckets > 0 ? `[cached: ${node.cached_buckets}]` : ''}`;
|
|
55
60
|
str += (0, string_1.colored)(` [${node.app}ms]\n`, 'brown');
|
|
56
|
-
str += print(node.nodes, l + 1);
|
|
61
|
+
str += print(node.nodes, idempotent, l + 1);
|
|
57
62
|
});
|
|
58
63
|
return str;
|
|
59
64
|
}
|
|
60
|
-
return str + print(this.nodes);
|
|
65
|
+
return str + print(this.nodes, this.idempotent);
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
exports.TrxStatus = TrxStatus;
|
|
@@ -83,7 +88,7 @@ class Trx {
|
|
|
83
88
|
this.id = id || (Math.random() + 1).toString(36).substring(7);
|
|
84
89
|
this.origin = origin;
|
|
85
90
|
this.idempotent = idempotent ?? false;
|
|
86
|
-
this.root = root || new trx_node_1.TrxNode('root', this, undefined, module, auth, false
|
|
91
|
+
this.root = root || new trx_node_1.TrxNode('root', this, undefined, module, auth, false);
|
|
87
92
|
this.nodes = nodes || {};
|
|
88
93
|
}
|
|
89
94
|
addNode(node) {
|
|
@@ -94,7 +99,7 @@ class Trx {
|
|
|
94
99
|
const state = this.root.state;
|
|
95
100
|
const output = this.root.output;
|
|
96
101
|
const error = this.root.error;
|
|
97
|
-
return new TrxStatus(this.id, this.origin, this.start, this.end, state, output, error, this.root.status().nodes);
|
|
102
|
+
return new TrxStatus(this.id, this.origin, this.start, this.end, state, output, error, this.idempotent, this.root.status().nodes);
|
|
98
103
|
}
|
|
99
104
|
/**
|
|
100
105
|
* Cache
|
|
@@ -146,13 +151,12 @@ class Trx {
|
|
|
146
151
|
return trx;
|
|
147
152
|
}
|
|
148
153
|
//
|
|
149
|
-
static async
|
|
154
|
+
static async commitHolds(trx) {
|
|
150
155
|
for (const h in trx.holds) {
|
|
151
156
|
await trx.holds[h].commit();
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
|
-
static async
|
|
155
|
-
trx.end = datetime_1.NesoiDatetime.now();
|
|
159
|
+
static async rollbackHolds(trx) {
|
|
156
160
|
for (const h in trx.holds) {
|
|
157
161
|
const error = `rollback ${trx.id}`;
|
|
158
162
|
await trx.holds[h].rollback(error);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $Module, $Space } from "../../elements";
|
|
1
|
+
import { $Bucket, $Module, $Space } from "../../elements";
|
|
2
2
|
import { BucketAdapter } from "../../elements/entities/bucket/adapters/bucket_adapter";
|
|
3
3
|
import { Trx } from './trx';
|
|
4
4
|
import { AnyUsers } from '../auth/authn';
|
|
@@ -7,9 +7,13 @@ import { TrxData } from './trx_engine';
|
|
|
7
7
|
export type TrxEngineWrapFn<S extends $Space, M extends $Module> = (trx: TrxNode<S, M, any>) => Promise<any>;
|
|
8
8
|
export type TrxEngineConfig<S extends $Space, M extends $Module, AuthUsers extends AnyUsers, Services extends Record<string, any>> = {
|
|
9
9
|
/**
|
|
10
|
-
* Adapter used to store transactions of this module.
|
|
10
|
+
* Adapter used to temporarily store transactions of this module, while they happen.
|
|
11
11
|
*/
|
|
12
|
-
adapter?: (schema:
|
|
12
|
+
adapter?: (schema: $Bucket) => BucketAdapter<TrxData>;
|
|
13
|
+
/**
|
|
14
|
+
* Adapter used to log transactions of this module once they're finished.
|
|
15
|
+
*/
|
|
16
|
+
log_adapter?: (schema: $Bucket) => BucketAdapter<TrxData>;
|
|
13
17
|
wrap?: {
|
|
14
18
|
begin: <T extends Trx<S, M, AuthUsers>>(trx: T, services: Services) => Promise<void>;
|
|
15
19
|
continue: <T extends Trx<S, M, AuthUsers>>(trx: T, services: Services) => Promise<void>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $Module, $Space } from "../../schema";
|
|
2
2
|
import { Module } from '../module';
|
|
3
3
|
import { AnyTrx, Trx, TrxStatus } from './trx';
|
|
4
|
-
import { TrxNode, TrxNodeStatus } from './trx_node';
|
|
4
|
+
import { TrxNode, TrxNodeState, TrxNodeStatus } from './trx_node';
|
|
5
5
|
import { AnyAuthnProviders, AnyUsers, AuthRequest } from '../auth/authn';
|
|
6
6
|
import { BucketAdapterConfig } from "../../elements/entities/bucket/adapters/bucket_adapter";
|
|
7
7
|
import { TrxEngineConfig } from './trx_engine.config';
|
|
@@ -12,6 +12,7 @@ import { DriveAdapter } from "../../elements/entities/drive/drive_adapter";
|
|
|
12
12
|
export type TrxEngineOrigin = `app:${string}` | `plugin:${string}`;
|
|
13
13
|
export type TrxData = {
|
|
14
14
|
id: AnyTrx['id'];
|
|
15
|
+
state: TrxNodeState;
|
|
15
16
|
origin: AnyTrx['origin'];
|
|
16
17
|
module: string;
|
|
17
18
|
start: AnyTrx['start'];
|
|
@@ -43,16 +44,19 @@ export declare class TrxEngine<S extends $Space, M extends $Module, AuthUsers ex
|
|
|
43
44
|
*/
|
|
44
45
|
private innerTrx;
|
|
45
46
|
private adapter;
|
|
47
|
+
private log_adapter?;
|
|
46
48
|
constructor(origin: TrxEngineOrigin, module: Module<S, M>, authnProviders?: AuthUsers | undefined, config?: TrxEngineConfig<S, M, any, any> | undefined, services?: Record<string, IService>);
|
|
47
49
|
getModule(): Module<S, M>;
|
|
48
|
-
get(id?: string, origin?: string,
|
|
50
|
+
get(id?: string, origin?: string, req_idempotent?: boolean): Promise<Trx<S, M, any>>;
|
|
49
51
|
trx(fn: (trx: TrxNode<S, M, any>) => Promise<TrxNodeStatus>, id?: string, tokens?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>, origin?: string, idempotent?: boolean): Promise<TrxStatus<any>>;
|
|
50
|
-
trx_hold(fn: (trx: TrxNode<S, M, any>) => Promise<any>, id?: string, authn?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>, origin?: string
|
|
52
|
+
trx_hold(fn: (trx: TrxNode<S, M, any>) => Promise<any>, id?: string, authn?: AuthRequest<keyof AuthUsers>, users?: Partial<AuthUsers>, origin?: string): Promise<HeldTrxNode<any>>;
|
|
51
53
|
getBucketMetadata(tag: Tag): BucketMetadata;
|
|
52
54
|
getBucketDrive(tag: Tag): DriveAdapter | undefined;
|
|
53
55
|
authenticate(node: TrxNode<S, M, any>, tokens?: AuthRequest<keyof AuthUsers>, users?: AnyUsers, force?: boolean): Promise<void>;
|
|
54
56
|
private hold;
|
|
57
|
+
private ok;
|
|
55
58
|
private commit;
|
|
59
|
+
private error;
|
|
56
60
|
private rollback;
|
|
57
61
|
}
|
|
58
62
|
export type AnyTrxEngine = TrxEngine<any, any, any>;
|