@platforma-sdk/workflow-tengo 2.4.0 → 2.5.0
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/dist/tengo/lib/exec.lib.tengo +1 -1
- package/dist/tengo/lib/ll.lib.tengo +38 -0
- package/dist/tengo/lib/maps.lib.tengo +8 -0
- package/dist/tengo/lib/pframes.util.lib.tengo +3 -0
- package/dist/tengo/lib/render.lib.tengo +1 -1
- package/dist/tengo/lib/smart.lib.tengo +90 -11
- package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
- package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
- package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
- package/package.json +2 -2
|
@@ -651,7 +651,7 @@ builder := func() {
|
|
|
651
651
|
* @return field - a reference to the file stream resource.
|
|
652
652
|
*/
|
|
653
653
|
getFileStream: func(fileName) {
|
|
654
|
-
return tpl.output("fileStreams", cache).getFutureInputField(fileName)
|
|
654
|
+
return tpl.output("fileStreams", cache).getFutureInputField(fileName, true)
|
|
655
655
|
},
|
|
656
656
|
|
|
657
657
|
/**
|
|
@@ -6,6 +6,13 @@ fmt := import("fmt")
|
|
|
6
6
|
log := import("log")
|
|
7
7
|
text := import("text")
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Provides current API version available at runtime
|
|
11
|
+
*/
|
|
12
|
+
apiVersion := func() {
|
|
13
|
+
return 0 // stub code. Real API checker will appear here.
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
/**
|
|
10
17
|
* Prints message to the pl log
|
|
11
18
|
*/
|
|
@@ -74,6 +81,35 @@ fromStrict := func(r) {
|
|
|
74
81
|
return plapi.strictToMap(r)
|
|
75
82
|
}
|
|
76
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Safe way to check if method exists in a builtin module or a library
|
|
86
|
+
*
|
|
87
|
+
* @param module: module - builtin module or tengo library
|
|
88
|
+
* @param methodName: string - name of a method to be checked
|
|
89
|
+
*
|
|
90
|
+
* @return bool - true when method exists, false otherwise
|
|
91
|
+
*/
|
|
92
|
+
methodExists := func(module, methodName) {
|
|
93
|
+
if isStrict(module) {
|
|
94
|
+
if !is_callable(plapi.mapHasKey) {
|
|
95
|
+
module = fromStrict(module)
|
|
96
|
+
|
|
97
|
+
} else {
|
|
98
|
+
if !plapi.mapHasKey(module, methodName) {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
method := module[methodName]
|
|
105
|
+
|
|
106
|
+
if is_undefined(method) {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return is_callable(method)
|
|
111
|
+
}
|
|
112
|
+
|
|
77
113
|
/**
|
|
78
114
|
* If input is a strict map, converts it to a normal one, otherwise returns the object as is
|
|
79
115
|
*
|
|
@@ -255,9 +291,11 @@ getCtx := func() {
|
|
|
255
291
|
}
|
|
256
292
|
|
|
257
293
|
export toStrict({
|
|
294
|
+
apiVersion: apiVersion,
|
|
258
295
|
print: print,
|
|
259
296
|
panic: panic,
|
|
260
297
|
assert: assert,
|
|
298
|
+
methodExists: methodExists,
|
|
261
299
|
isStrict: isStrict,
|
|
262
300
|
isMap: isMap,
|
|
263
301
|
fromStrict: fromStrict,
|
|
@@ -29,6 +29,14 @@ containsKey := func(map, key) {
|
|
|
29
29
|
return false
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// Load effective version of map key checker if it exists in controller's API
|
|
33
|
+
plapi := import("plapi")
|
|
34
|
+
if ll.methodExists(plapi, "mapHasKey") {
|
|
35
|
+
containsKey = func(map, key) {
|
|
36
|
+
return plapi.mapHasKey(map, key)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
/**
|
|
33
41
|
* Transforms all keys of the map with a function and returns a new map with these keys.
|
|
34
42
|
*
|
|
@@ -180,6 +180,9 @@ _COLUMN_FILTER_SCHEMA := {
|
|
|
180
180
|
// Match any of the names listed here;
|
|
181
181
|
// default: name is ignored during matching
|
|
182
182
|
`name,?`: `string`,
|
|
183
|
+
// Match requires all the listed domains to have provided values;
|
|
184
|
+
// default: no domain equality checks are performed during matching
|
|
185
|
+
`domainValue,?`: { any: `string` },
|
|
183
186
|
// Match requires all the listed annotations to have provided values;
|
|
184
187
|
// default: no annotation equality checks are performed during matching
|
|
185
188
|
`annotationValue,?`: { any: `string` },
|
|
@@ -59,7 +59,7 @@ createUniversal := func(tpl, isEph, inputs) {
|
|
|
59
59
|
*/
|
|
60
60
|
output: func(name, ...cache) {
|
|
61
61
|
ll.assert(len(cache) == 0 || is_int(cache[0]), "cache should be a number (use 'times' tengo library), got: %v", cache)
|
|
62
|
-
out := renderer.getFutureOutputField(tplutil.TEMPLATE_OUTPUT_PREFIX + name)
|
|
62
|
+
out := renderer.getFutureOutputField(tplutil.TEMPLATE_OUTPUT_PREFIX + name, isEph)
|
|
63
63
|
if len(cache) > 0 && cache[0] > 0 {
|
|
64
64
|
cache = cache[0]
|
|
65
65
|
tx.cacheSetToField(out.id, cache)
|
|
@@ -264,6 +264,7 @@ resource = func(r) {
|
|
|
264
264
|
* ID: int64
|
|
265
265
|
* Data: byte[],
|
|
266
266
|
* Type: { Name: string, Version: string }
|
|
267
|
+
* Features: { ephemeral: bool }
|
|
267
268
|
* Inputs: strict map
|
|
268
269
|
* Outputs: strict map
|
|
269
270
|
* Dynamic: strict map
|
|
@@ -297,6 +298,19 @@ resource = func(r) {
|
|
|
297
298
|
return self.info().ResourceReady
|
|
298
299
|
},
|
|
299
300
|
|
|
301
|
+
isEphemeral: func() {
|
|
302
|
+
resourceInfo := self.info()
|
|
303
|
+
|
|
304
|
+
if !maps.containsKey(resourceInfo, "Features") {
|
|
305
|
+
// by default we consider all resources to be ephemeral for backward compatiblity to keep stable logic
|
|
306
|
+
// in platforma backend before v1.16.0.
|
|
307
|
+
// TODO: once we consider this version old enough, we can panic here instead of 'return true'
|
|
308
|
+
return true
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return resourceInfo.Features.ephemeral
|
|
312
|
+
},
|
|
313
|
+
|
|
300
314
|
/**
|
|
301
315
|
* Get raw resource data
|
|
302
316
|
*
|
|
@@ -433,7 +447,7 @@ resource = func(r) {
|
|
|
433
447
|
* @return field: smart.field
|
|
434
448
|
*/
|
|
435
449
|
getFutureField: func(name, fieldType, ...eph) {
|
|
436
|
-
isEph :=
|
|
450
|
+
isEph := strictSelf.isEphemeral()
|
|
437
451
|
if len(eph) > 0 {
|
|
438
452
|
isEph = eph[0]
|
|
439
453
|
}
|
|
@@ -450,14 +464,19 @@ resource = func(r) {
|
|
|
450
464
|
* @return field: smart.field
|
|
451
465
|
*/
|
|
452
466
|
getFutureInputField: func(nameOrPath, ...eph) {
|
|
467
|
+
isEph := strictSelf.isEphemeral()
|
|
468
|
+
if len(eph) > 0 {
|
|
469
|
+
isEph = eph[0]
|
|
470
|
+
}
|
|
471
|
+
|
|
453
472
|
if is_array(nameOrPath) {
|
|
454
473
|
current := strictSelf
|
|
455
474
|
for name in nameOrPath {
|
|
456
|
-
current = current.getFutureField(name, "input",
|
|
475
|
+
current = current.getFutureField(name, "input", isEph)
|
|
457
476
|
}
|
|
458
477
|
return current
|
|
459
478
|
} else {
|
|
460
|
-
return self.getFutureField(nameOrPath, "input",
|
|
479
|
+
return self.getFutureField(nameOrPath, "input", isEph)
|
|
461
480
|
}
|
|
462
481
|
},
|
|
463
482
|
|
|
@@ -471,7 +490,18 @@ resource = func(r) {
|
|
|
471
490
|
* @return field: smart.field
|
|
472
491
|
*/
|
|
473
492
|
getFutureOutputField: func(name, ...eph) {
|
|
474
|
-
|
|
493
|
+
isEph := strictSelf.isEphemeral()
|
|
494
|
+
if len(eph) > 0 {
|
|
495
|
+
isEph = eph[0]
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if ll.apiVersion() < 1 && !isEph {
|
|
499
|
+
// Dirty hack that saves from issues with buggy pure getField before v1.16.1
|
|
500
|
+
// We can safely drop it when we consider v1.16.0 old enough.
|
|
501
|
+
return self.getFutureField(name, "output", true).expectNonEphemeral()
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return self.getFutureField(name, "output", isEph)
|
|
475
505
|
},
|
|
476
506
|
|
|
477
507
|
/**
|
|
@@ -592,10 +622,12 @@ field = func(f) {
|
|
|
592
622
|
/**
|
|
593
623
|
* Field info:
|
|
594
624
|
*
|
|
595
|
-
* ID:
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
625
|
+
* ID: { ResourceId: int64, Name: string }
|
|
626
|
+
* Type: string - see constants.FTYPE_* for possible values
|
|
627
|
+
* Features: { ephemeral: bool }
|
|
628
|
+
* Value: int64 - value resource id
|
|
629
|
+
* Error: int64 - error resource id
|
|
630
|
+
* IsSet: bool - whether field is set
|
|
599
631
|
*/
|
|
600
632
|
info: func() {
|
|
601
633
|
return tx.getField(self.id)
|
|
@@ -622,6 +654,37 @@ field = func(f) {
|
|
|
622
654
|
return self.info().Error != 0
|
|
623
655
|
},
|
|
624
656
|
|
|
657
|
+
/**
|
|
658
|
+
* Some fields cannot point to ephemeral resources.
|
|
659
|
+
* This method checks, if current field can.
|
|
660
|
+
*
|
|
661
|
+
* @return bool - "true' when field can point to ephemeral resource, 'false' when not
|
|
662
|
+
*/
|
|
663
|
+
isEphemeral: func() {
|
|
664
|
+
fieldInfo := self.info()
|
|
665
|
+
|
|
666
|
+
if !maps.containsKey(fieldInfo, "Features") {
|
|
667
|
+
// by default we consider all fields can point to ephemeral resources for backward compatiblity to keep stable logic
|
|
668
|
+
// in platforma backend before v1.16.0.
|
|
669
|
+
// TODO: once we consider this version old enough, we can panic here instead of 'return true'
|
|
670
|
+
return true
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
isParentResourceEphemeral := fieldInfo.Features.ephemeral
|
|
674
|
+
if isParentResourceEphemeral {
|
|
675
|
+
return true
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
return fieldInfo.Type != constants.FTYPE_INPUT &&
|
|
679
|
+
fieldInfo.Type != constants.FTYPE_OUTPUT
|
|
680
|
+
},
|
|
681
|
+
|
|
682
|
+
expectNonEphemeral: func() {
|
|
683
|
+
rr := field(self.id)
|
|
684
|
+
rr.isEphemeral = func() { return false }
|
|
685
|
+
return rr
|
|
686
|
+
},
|
|
687
|
+
|
|
625
688
|
/**
|
|
626
689
|
* Use cacheMillis, cacheSeconds, cacheMinutes, cacheHours and cacheDays to not make hidden mistakes in cache time ranges.
|
|
627
690
|
* Sets the cache time.
|
|
@@ -779,7 +842,7 @@ field = func(f) {
|
|
|
779
842
|
* @return field: smart.field
|
|
780
843
|
*/
|
|
781
844
|
getFutureField: func(name, fieldType, ...eph) {
|
|
782
|
-
isEph :=
|
|
845
|
+
isEph := strictSelf.isEphemeral()
|
|
783
846
|
if len(eph) > 0 {
|
|
784
847
|
isEph = eph[0]
|
|
785
848
|
}
|
|
@@ -796,6 +859,11 @@ field = func(f) {
|
|
|
796
859
|
* @return field: smart field
|
|
797
860
|
*/
|
|
798
861
|
getFutureInputField: func(nameOrPath, ...eph) {
|
|
862
|
+
isEph := strictSelf.isEphemeral()
|
|
863
|
+
if len(eph) > 0 {
|
|
864
|
+
isEph = eph[0]
|
|
865
|
+
}
|
|
866
|
+
|
|
799
867
|
if is_array(nameOrPath) {
|
|
800
868
|
current := strictSelf
|
|
801
869
|
for name in nameOrPath {
|
|
@@ -817,7 +885,18 @@ field = func(f) {
|
|
|
817
885
|
* @return field: smart field
|
|
818
886
|
*/
|
|
819
887
|
getFutureOutputField: func(name, ...eph) {
|
|
820
|
-
|
|
888
|
+
isEph := strictSelf.isEphemeral()
|
|
889
|
+
if len(eph) > 0 {
|
|
890
|
+
isEph = eph[0]
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if ll.apiVersion() < 1 && !isEph {
|
|
894
|
+
// Dirty hack that saves from issues with buggy pure getField before v1.16.1
|
|
895
|
+
// We can safely drop it when we consider v1.16.0 old enough.
|
|
896
|
+
return self.getFutureField(name, "output", true).expectNonEphemeral()
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return self.getFutureField(name, "output", isEph)
|
|
821
900
|
}
|
|
822
901
|
}
|
|
823
902
|
|
|
@@ -848,7 +927,7 @@ resourceBuilder = func(r) {
|
|
|
848
927
|
* Create new field with given name and field type.
|
|
849
928
|
*
|
|
850
929
|
* @param name field name
|
|
851
|
-
* @param fieldType: field type - input, output, dynamic, service, OTW. Use
|
|
930
|
+
* @param fieldType: field type - input, output, dynamic, service, OTW. Use FfTYPE_* constants.
|
|
852
931
|
*/
|
|
853
932
|
createField: func(name, fieldType) {
|
|
854
933
|
assertNotBuilt()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/workflow-tengo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "Tengo SDK library",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"./dist/**/*"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@milaboratories/software-pframes-conv": "2.0
|
|
19
|
+
"@milaboratories/software-pframes-conv": "2.1.0",
|
|
20
20
|
"@platforma-open/milaboratories.software-small-binaries": "^1.14.6"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|