@platforma-sdk/workflow-tengo 1.2.6
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/README.md +6 -0
- package/dist/tengo/lib/assets.lib.tengo +64 -0
- package/dist/tengo/lib/constants.lib.tengo +75 -0
- package/dist/tengo/lib/exec.internal.lib.tengo +211 -0
- package/dist/tengo/lib/exec.lib.tengo +516 -0
- package/dist/tengo/lib/exec.package.lib.tengo +296 -0
- package/dist/tengo/lib/exec.runcmd.lib.tengo +275 -0
- package/dist/tengo/lib/exec.runenv.lib.tengo +221 -0
- package/dist/tengo/lib/exec.stream.lib.tengo +64 -0
- package/dist/tengo/lib/file.lib.tengo +112 -0
- package/dist/tengo/lib/ll.lib.tengo +233 -0
- package/dist/tengo/lib/maps.lib.tengo +102 -0
- package/dist/tengo/lib/objects.lib.tengo +22 -0
- package/dist/tengo/lib/oop.lib.tengo +29 -0
- package/dist/tengo/lib/path.lib.tengo +165 -0
- package/dist/tengo/lib/pframes.constants.lib.tengo +53 -0
- package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +47 -0
- package/dist/tengo/lib/pframes.lib.tengo +84 -0
- package/dist/tengo/lib/pframes.ll.lib.tengo +86 -0
- package/dist/tengo/lib/pframes.util.lib.tengo +244 -0
- package/dist/tengo/lib/pframes.xsv.lib.tengo +178 -0
- package/dist/tengo/lib/render.lib.tengo +100 -0
- package/dist/tengo/lib/sets.lib.tengo +93 -0
- package/dist/tengo/lib/slices.lib.tengo +202 -0
- package/dist/tengo/lib/smart.lib.tengo +1005 -0
- package/dist/tengo/lib/tpl.lib.tengo +535 -0
- package/dist/tengo/lib/tpl.state-await.lib.tengo +255 -0
- package/dist/tengo/lib/tpl.util.lib.tengo +19 -0
- package/dist/tengo/lib/validation.lib.tengo +428 -0
- package/dist/tengo/lib/workdir.lib.tengo +300 -0
- package/dist/tengo/lib/workdir.proc.lib.tengo +158 -0
- package/dist/tengo/lib/workdir.save.lib.tengo +158 -0
- package/dist/tengo/lib/workflow.bobject.lib.tengo +51 -0
- package/dist/tengo/lib/workflow.bquery.lib.tengo +208 -0
- package/dist/tengo/lib/workflow.constants.lib.tengo +8 -0
- package/dist/tengo/lib/workflow.context.lib.tengo +56 -0
- package/dist/tengo/lib/workflow.lib.tengo +298 -0
- package/dist/tengo/tpl/exec.create-python-venv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.exec.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.import-xsv-map.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.map-pframe.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/index.d.ts +4 -0
- package/index.js +13 -0
- package/package.json +25 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
slices := import("@platforma-sdk/workflow-tengo:slices")
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns a slice of keys of the map.
|
|
6
|
+
*
|
|
7
|
+
* @param map map[string]any - map to extract keys from
|
|
8
|
+
* @return result: string[] - a slice of keys.
|
|
9
|
+
*/
|
|
10
|
+
getKeys := func(map) {
|
|
11
|
+
res := []
|
|
12
|
+
for k, _ in map {
|
|
13
|
+
res = append(res, k)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return slices.sortByFn(res, func(elem) { return elem })
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns true if map contains specified key. Note: current implementation is O(N)
|
|
21
|
+
*/
|
|
22
|
+
containsKey := func(map, key) {
|
|
23
|
+
for k, _ in map {
|
|
24
|
+
if key == k {
|
|
25
|
+
return true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Transforms all keys of the map with a function and returns a new map with these keys.
|
|
34
|
+
*
|
|
35
|
+
* @param map: map[key]any
|
|
36
|
+
* @param fnK: func(key): newKey - a function that gets a key and returns a new key.
|
|
37
|
+
* @return new map: map[newKey]any - a transformed map
|
|
38
|
+
*/
|
|
39
|
+
mapKeys := func(map, fnK) {
|
|
40
|
+
newM := {}
|
|
41
|
+
for k, v in map {
|
|
42
|
+
newM[fnK(k)] = v
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return newM
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Map values
|
|
49
|
+
mapValues := func(map, fnV) {
|
|
50
|
+
newM := {}
|
|
51
|
+
for k, v in map {
|
|
52
|
+
newM[k] = fnV(v)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return newM
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Map keys and values
|
|
59
|
+
map := func(map, fn) {
|
|
60
|
+
newM := {}
|
|
61
|
+
for k, v in map {
|
|
62
|
+
r := fn(k, v)
|
|
63
|
+
newM[r.key] = r.value
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return newM
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
filter := func(map, predicateFn) {
|
|
70
|
+
newM := {}
|
|
71
|
+
for k, v in map {
|
|
72
|
+
if predicateFn(k, v) {
|
|
73
|
+
newM[k] = v
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return newM
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
filterValues := func(map, predicateFnV) {
|
|
81
|
+
return filter(map, func(k, v) { return predicateFnV(v) })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
filterKeys := func(map, predicateFnK) {
|
|
85
|
+
return filter(map, func(k, v) { return predicateFnK(k) })
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
filterKeysValues := func(map, predicateFnK, predicateFnV) {
|
|
89
|
+
return filter(map, func(k, v) { return predicateFnK(k) && predicateFnV(v) })
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export ll.toStrict({
|
|
93
|
+
map : map,
|
|
94
|
+
mapKeys : mapKeys,
|
|
95
|
+
mapValues : mapValues,
|
|
96
|
+
filter : filter,
|
|
97
|
+
filterValues : filterValues,
|
|
98
|
+
filterKeys : filterKeys,
|
|
99
|
+
filterKeysValues : filterKeysValues,
|
|
100
|
+
getKeys: getKeys,
|
|
101
|
+
containsKey: containsKey
|
|
102
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for working with objects
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Deletes entries with undefined values from object
|
|
9
|
+
*/
|
|
10
|
+
deleteUndefined := func(obj) {
|
|
11
|
+
for k, v in obj {
|
|
12
|
+
if is_undefined(v) {
|
|
13
|
+
delete(obj, k)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return obj
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export ll.toStrict({
|
|
21
|
+
deleteUndefined: deleteUndefined
|
|
22
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for working with objects.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Inherit all methods and properties of a super object
|
|
9
|
+
*
|
|
10
|
+
* @param super a parent from which we get all methods
|
|
11
|
+
* @param self an object in which we set all super methods
|
|
12
|
+
* @return self
|
|
13
|
+
*/
|
|
14
|
+
inherit := func(super, self) {
|
|
15
|
+
self["super"] = super
|
|
16
|
+
|
|
17
|
+
// inherit super methods
|
|
18
|
+
for k, v in super {
|
|
19
|
+
if self[k] == undefined {
|
|
20
|
+
self[k] = v
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return ll.toStrict(self)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export ll.toStrict({
|
|
28
|
+
inherit: inherit
|
|
29
|
+
})
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
text := import("text")
|
|
3
|
+
slices := import("@platforma-sdk/workflow-tengo:slices")
|
|
4
|
+
validation := import("@platforma-sdk/workflow-tengo:validation")
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Joins path elements into a single path.
|
|
8
|
+
*
|
|
9
|
+
* @param elems: ...string - any number of elements.
|
|
10
|
+
*/
|
|
11
|
+
join := func(...elems) {
|
|
12
|
+
validation.assertJsonSchema(elems, ["string"])
|
|
13
|
+
return ll.filepathJoin(elems...)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Like join, joins elements to a single path,
|
|
18
|
+
* but can be used safely in regexps.
|
|
19
|
+
*
|
|
20
|
+
* @param elems: ...string - any number of elements.
|
|
21
|
+
*/
|
|
22
|
+
regexpJoin := func(...elems) {
|
|
23
|
+
validation.assertJsonSchema(elems, ["string"])
|
|
24
|
+
return ll.filepathRegexpJoin(elems...)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Joins elements of the filepath and canonizes it, i.e.
|
|
29
|
+
* semantically resolves ../ and ./ and changes slash
|
|
30
|
+
* to a pathSeparator.
|
|
31
|
+
*
|
|
32
|
+
* @param elems: ...string - any number of elements.
|
|
33
|
+
*/
|
|
34
|
+
canonize := func(...elems) {
|
|
35
|
+
validation.assertJsonSchema(elems, ["string"])
|
|
36
|
+
return ll.filepathCanonize(elems...)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns a path separator. "/" on Unix-like systems, "\\" on Windows.
|
|
41
|
+
*
|
|
42
|
+
* @return separator: string
|
|
43
|
+
*/
|
|
44
|
+
separator := ll.pathSeparator
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Trims a beginning of the file path following by a path separator.
|
|
48
|
+
*
|
|
49
|
+
* @param path: string - a file path
|
|
50
|
+
* @param prefix: string - the beginning of the file path
|
|
51
|
+
* @return trimmed path: string - a path without the beginning and a path separator.
|
|
52
|
+
*/
|
|
53
|
+
trimPrefix := func(path, prefix) {
|
|
54
|
+
validation.assertJsonSchema([path, prefix], ["string"])
|
|
55
|
+
return text.trim_prefix(path, prefix+separator)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_sepOrDefault := func(...sep) {
|
|
59
|
+
validation.assertJsonSchema(sep, [["or", "string", "char", "null"]])
|
|
60
|
+
|
|
61
|
+
if slices.length(sep) == 0 {
|
|
62
|
+
return separator
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return sep[0]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Splits a path to path components.
|
|
70
|
+
* If it was a file name, the last component will be this name.
|
|
71
|
+
*
|
|
72
|
+
* @param path: string - the path
|
|
73
|
+
* @param sep: string - an optional path separator.
|
|
74
|
+
* @return components: []string - all directories and a file name at the end.
|
|
75
|
+
*/
|
|
76
|
+
split := func(path, ...sep) {
|
|
77
|
+
sep = _sepOrDefault(sep...)
|
|
78
|
+
|
|
79
|
+
return text.split(path, sep)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Gets all directories with their ancestors from the root.
|
|
84
|
+
* For example, for dir1/dir2/dir3/abc.txt it gives:
|
|
85
|
+
* ["dir1", "dir1/dir2", "dir1/dir2/dir3", "dir1/dir2/dir3/abc.txt"]
|
|
86
|
+
*
|
|
87
|
+
* @param path: string - the path
|
|
88
|
+
* @param separator: string - an optional separator.
|
|
89
|
+
* @return components: []string - all directories and a file name at the end from their root.
|
|
90
|
+
*/
|
|
91
|
+
getBasenameDirs := func(path, ...sep) {
|
|
92
|
+
validation.assertJsonSchema(path, "string")
|
|
93
|
+
sep = _sepOrDefault(sep...)
|
|
94
|
+
|
|
95
|
+
dirs := split(path, sep)
|
|
96
|
+
|
|
97
|
+
dirTails := []
|
|
98
|
+
for i := 1; i <= len(dirs); i++ {
|
|
99
|
+
dirTails = append(dirTails, text.join(dirs[:i], sep))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return dirTails
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Gets an extension to the last "." symbol,
|
|
107
|
+
* or, if the name contains ".gz" or any other archive suffix,
|
|
108
|
+
* then till the next from the last "." symbol.
|
|
109
|
+
*
|
|
110
|
+
* @param path: string - a path
|
|
111
|
+
* @return extension: string - the extension without the leading "."
|
|
112
|
+
*/
|
|
113
|
+
getExtension := func(path, ...sep) {
|
|
114
|
+
validation.assertJsonSchema(path, "string")
|
|
115
|
+
ext := ""
|
|
116
|
+
sep = _sepOrDefault(sep...)
|
|
117
|
+
|
|
118
|
+
nPoints := 1
|
|
119
|
+
if text.re_match(`\.(gz|xz|bzip|zstd)$`, path) {
|
|
120
|
+
nPoints = 2
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for i := len(path) - 1; i >= 0 && path[i] != sep; i-- {
|
|
124
|
+
if path[i] == '.' {
|
|
125
|
+
ext = path[i:]
|
|
126
|
+
nPoints--
|
|
127
|
+
if nPoints == 0 {
|
|
128
|
+
break
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if len(ext) > 0 {
|
|
134
|
+
ext = ext[1:] // remove leading "."
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return ext
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Checks if the path is correct.
|
|
142
|
+
*
|
|
143
|
+
* @param path: string - a path
|
|
144
|
+
*/
|
|
145
|
+
assertIsValid := func(path) {
|
|
146
|
+
validation.assertJsonSchema(path, "string")
|
|
147
|
+
if text.contains(path, "/") {
|
|
148
|
+
ll.assert(
|
|
149
|
+
text.contains(path, separator),
|
|
150
|
+
"path to a file must be separated by OS's specific path separator. " +
|
|
151
|
+
"Did you forget to use 'path.join' or 'path.regexpJoin'?")
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export ll.toStrict({
|
|
156
|
+
join: join,
|
|
157
|
+
regexpJoin: regexpJoin,
|
|
158
|
+
canonize: canonize,
|
|
159
|
+
separator: separator,
|
|
160
|
+
trimPrefix: trimPrefix,
|
|
161
|
+
split: split,
|
|
162
|
+
getBasenameDirs: getBasenameDirs,
|
|
163
|
+
getExtension: getExtension,
|
|
164
|
+
assertIsValid: assertIsValid
|
|
165
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contain field names and other constant used in PFrames
|
|
3
|
+
* libraries and templates.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Name of the field under which the iteration value like in "map" and "aggregate" is passed
|
|
10
|
+
* to the iteration body template.
|
|
11
|
+
*/
|
|
12
|
+
VALUE_FIELD_NAME := "__value__"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Name of the field under which the iteration key like in "map" and "aggregate" is passed
|
|
16
|
+
* to the iteration body template.
|
|
17
|
+
*/
|
|
18
|
+
KEY_FIELD_NAME := "__key__"
|
|
19
|
+
|
|
20
|
+
RTYPE_P_FRAME := { Name: "PFrame", Version: "1" }
|
|
21
|
+
|
|
22
|
+
P_COLUMN_DATA_TYPE_PREFIX := "PColumnData/"
|
|
23
|
+
RTYPE_P_COLUMN_DATA_JSON := { Name: P_COLUMN_DATA_TYPE_PREFIX + "Json", Version: "1" }
|
|
24
|
+
RTYPE_P_COLUMN_DATA_BINARY := { Name: P_COLUMN_DATA_TYPE_PREFIX + "Binary", Version: "1" }
|
|
25
|
+
RTYPE_P_COLUMN_DATA_RESOURCE_MAP := { Name: P_COLUMN_DATA_TYPE_PREFIX + "ResourceMap", Version: "1" }
|
|
26
|
+
RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED := { Name: P_COLUMN_DATA_TYPE_PREFIX + "Partitioned/ResourceMap", Version: "1" }
|
|
27
|
+
RTYPE_P_COLUMN_DATA_JSON_PARTITIONED := { Name: P_COLUMN_DATA_TYPE_PREFIX + "JsonPartitioned", Version: "1" }
|
|
28
|
+
RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED := { Name: P_COLUMN_DATA_TYPE_PREFIX + "BinaryPartitioned", Version: "1" }
|
|
29
|
+
|
|
30
|
+
P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX := P_COLUMN_DATA_TYPE_PREFIX + "Partitioned/"
|
|
31
|
+
RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED := { Name: P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX + "JsonPartitioned", Version: "1" }
|
|
32
|
+
RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED := { Name: P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX + "BinaryPartitioned", Version: "1" }
|
|
33
|
+
|
|
34
|
+
KIND_P_COLUMN := "PColumn"
|
|
35
|
+
|
|
36
|
+
export ll.toStrict({
|
|
37
|
+
KIND_P_COLUMN : KIND_P_COLUMN,
|
|
38
|
+
KEY_FIELD_NAME : KEY_FIELD_NAME,
|
|
39
|
+
VALUE_FIELD_NAME : VALUE_FIELD_NAME,
|
|
40
|
+
P_COLUMN_DATA_TYPE_PREFIX : P_COLUMN_DATA_TYPE_PREFIX,
|
|
41
|
+
P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX : P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX,
|
|
42
|
+
|
|
43
|
+
RTYPE_P_FRAME : RTYPE_P_FRAME,
|
|
44
|
+
|
|
45
|
+
RTYPE_P_COLUMN_DATA_JSON : RTYPE_P_COLUMN_DATA_JSON,
|
|
46
|
+
RTYPE_P_COLUMN_DATA_BINARY : RTYPE_P_COLUMN_DATA_BINARY,
|
|
47
|
+
RTYPE_P_COLUMN_DATA_RESOURCE_MAP : RTYPE_P_COLUMN_DATA_RESOURCE_MAP,
|
|
48
|
+
RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED : RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED,
|
|
49
|
+
RTYPE_P_COLUMN_DATA_JSON_PARTITIONED : RTYPE_P_COLUMN_DATA_JSON_PARTITIONED,
|
|
50
|
+
RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED : RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED,
|
|
51
|
+
RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED : RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED,
|
|
52
|
+
RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED : RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED
|
|
53
|
+
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
pConstants := import("@platforma-sdk/workflow-tengo:pframes.constants")
|
|
2
|
+
smart := import("@platforma-sdk/workflow-tengo:smart")
|
|
3
|
+
render := import("@platforma-sdk/workflow-tengo:render")
|
|
4
|
+
file := import("@platforma-sdk/workflow-tengo:file")
|
|
5
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
6
|
+
assets := import("@platforma-sdk/workflow-tengo:assets")
|
|
7
|
+
|
|
8
|
+
// reference to the template doing nested super-partitioned export
|
|
9
|
+
nestedTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.export-single-pcolumn")
|
|
10
|
+
|
|
11
|
+
/** Implements core export logic for export-single-pcolumn and export-multiple-pcolumns templates */
|
|
12
|
+
exportPColumnData := func(data) {
|
|
13
|
+
if data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED) ||
|
|
14
|
+
data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED) ||
|
|
15
|
+
data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED) {
|
|
16
|
+
// super-partitioned data
|
|
17
|
+
|
|
18
|
+
newData := smart.structBuilder(data.info().Type, data.info().Data)
|
|
19
|
+
for key, partData in data.inputs() {
|
|
20
|
+
newData.createInputField(key).set(render.createEphemeral(nestedTpl, { data: partData }).output("result"))
|
|
21
|
+
}
|
|
22
|
+
return newData.lockAndBuild()
|
|
23
|
+
|
|
24
|
+
} else if data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP) ||
|
|
25
|
+
data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED) ||
|
|
26
|
+
data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED) {
|
|
27
|
+
// data directly referencing blob objects
|
|
28
|
+
|
|
29
|
+
newData := smart.structBuilder(data.info().Type, data.info().Data)
|
|
30
|
+
for key, partData in data.inputs() {
|
|
31
|
+
newData.createInputField(key).set(file.exportFile(partData))
|
|
32
|
+
}
|
|
33
|
+
return newData.lockAndBuild()
|
|
34
|
+
|
|
35
|
+
} else if data.checkResourceType(pConstants.RTYPE_P_COLUMN_DATA_JSON) {
|
|
36
|
+
// data embeds all information and needs no special exporting procedure
|
|
37
|
+
|
|
38
|
+
return data
|
|
39
|
+
|
|
40
|
+
} else {
|
|
41
|
+
ll.panic("unknonw resource type: %v", data.info().Type)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export ll.toStrict({
|
|
46
|
+
exportPColumnData: exportPColumnData
|
|
47
|
+
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Working with p-frames
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
6
|
+
oop := import("@platforma-sdk/workflow-tengo:oop")
|
|
7
|
+
json := import("json")
|
|
8
|
+
smart := import("@platforma-sdk/workflow-tengo:smart")
|
|
9
|
+
assets := import("@platforma-sdk/workflow-tengo:assets")
|
|
10
|
+
render := import("@platforma-sdk/workflow-tengo:render")
|
|
11
|
+
constants := import("@platforma-sdk/workflow-tengo:pframes.constants")
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Given a reference to the p-frame, converts all inner resource files into resources that can be
|
|
15
|
+
* downloaded from the UI side.
|
|
16
|
+
*/
|
|
17
|
+
exportFrame := func(pf) {
|
|
18
|
+
return render.createEphemeral(assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.export-pframe"), { pf: pf }).output("result")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Export single PColumn data
|
|
23
|
+
*/
|
|
24
|
+
exportColumnData := func(data) {
|
|
25
|
+
return render.createEphemeral(assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.export-single-pcolumn"), { data: data }).output("result")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a builder for p-frame resource.
|
|
30
|
+
*/
|
|
31
|
+
pFrameBuilder := func() {
|
|
32
|
+
r := smart.structBuilder(constants.RTYPE_P_FRAME)
|
|
33
|
+
|
|
34
|
+
self := undefined
|
|
35
|
+
self = ll.toStrict(oop.inherit(r, {
|
|
36
|
+
|
|
37
|
+
add: func(column, spec, data) {
|
|
38
|
+
if (!is_undefined(spec)) {
|
|
39
|
+
r.createInputField(column + ".spec").setRefOrJson(spec)
|
|
40
|
+
}
|
|
41
|
+
if (!is_undefined(data)) {
|
|
42
|
+
r.createInputField(column + ".data").setRefOrJson(data)
|
|
43
|
+
}
|
|
44
|
+
return self
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
build: func() {
|
|
48
|
+
return r.lockAndBuild()
|
|
49
|
+
}
|
|
50
|
+
}))
|
|
51
|
+
return self
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Creates a builder for a resource map p-column's data.
|
|
56
|
+
*/
|
|
57
|
+
pColumnResourceMapDataBuilder := func(keyLength) {
|
|
58
|
+
r := smart.structBuilder(
|
|
59
|
+
constants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP,
|
|
60
|
+
json.encode({ keyLength: 1 })
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
self := undefined
|
|
64
|
+
self = ll.toStrict(oop.inherit(r, {
|
|
65
|
+
|
|
66
|
+
add: func(key, data) {
|
|
67
|
+
ll.assert(is_array(key), "key must be an array, got ", key)
|
|
68
|
+
r.createInputField(json.encode(key)).setRefOrJson(data)
|
|
69
|
+
return self
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
build: func() {
|
|
73
|
+
return r.lockAndBuild()
|
|
74
|
+
}
|
|
75
|
+
}))
|
|
76
|
+
return self
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export ll.toStrict({
|
|
80
|
+
exportFrame: exportFrame,
|
|
81
|
+
pFrameBuilder: pFrameBuilder,
|
|
82
|
+
exportColumnData: exportColumnData,
|
|
83
|
+
pColumnResourceMapDataBuilder: pColumnResourceMapDataBuilder
|
|
84
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set of basic operations for PColumn data payload
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
6
|
+
assets := import("@platforma-sdk/workflow-tengo:assets")
|
|
7
|
+
smart := import("@platforma-sdk/workflow-tengo:smart")
|
|
8
|
+
render := import("@platforma-sdk/workflow-tengo:render")
|
|
9
|
+
pConstants := import("@platforma-sdk/workflow-tengo:pframes.constants")
|
|
10
|
+
|
|
11
|
+
llAggTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.aggregate")
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Instantiate an aggregation pipeline for the given inputs, and returns rendered ephemeral template.
|
|
15
|
+
* Use r.output("output_name") method to get corresponding result, where r is an object returned by
|
|
16
|
+
* this method.
|
|
17
|
+
*
|
|
18
|
+
* Contract for the body template:
|
|
19
|
+
*
|
|
20
|
+
* Inputs:
|
|
21
|
+
* "__key__" - will be set to the json representation of the group key (i.e. keys in all
|
|
22
|
+
* positions not specified in the indices parameter)
|
|
23
|
+
* "__value__" - "PColumnData/ResourceMap" resource with all the records in the current group
|
|
24
|
+
* ...extra - all values or references passed to optional last parameter of this method
|
|
25
|
+
* will be forwarded to the template as is
|
|
26
|
+
*
|
|
27
|
+
* Outputs:
|
|
28
|
+
* array of output names to collect from aggregation operations is specified as a parameter
|
|
29
|
+
* of this operation
|
|
30
|
+
*
|
|
31
|
+
* @param data data resource (currently only PColumnData/ResourceMap is supported)
|
|
32
|
+
* @param indices indices to aggregate over (these indices will be stripped from the input map,
|
|
33
|
+
* meaning of this parameter is the opposite of GROUP BY from SQL)
|
|
34
|
+
* @param bodyTpl reference to the template implementing particular aggregation (see contract above)
|
|
35
|
+
* @param outputs array of output settings to to collect from rendered templates
|
|
36
|
+
*
|
|
37
|
+
* Common fields for all subtypes:
|
|
38
|
+
* {
|
|
39
|
+
* name: string - name of the output
|
|
40
|
+
* path?: string[] - [optional] overrides the path inside the body template
|
|
41
|
+
* result, first name is interpreted as output name. If
|
|
42
|
+
* not specified path equals to `[name]`.
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* Variants:
|
|
46
|
+
* | { type: "Resource" } // - assume normal singular resource is produced by
|
|
47
|
+
* this output
|
|
48
|
+
* | {
|
|
49
|
+
* type: "ResourceMap",
|
|
50
|
+
* keyLength: number // - expected key length of result from each operation
|
|
51
|
+
* } // - assume each record is ResourceMap
|
|
52
|
+
* | {
|
|
53
|
+
* type: "BinaryPartitioned" | "JsonPartitioned",
|
|
54
|
+
* partitionKeyLength: number // - expected partition length of result from
|
|
55
|
+
* each operation
|
|
56
|
+
* } // - assume each record is a partitionded Json or Binary PColumn data itself
|
|
57
|
+
*
|
|
58
|
+
* @param isEph if true, body template will be rendered as ephemeral
|
|
59
|
+
* @param extra optional map of parameters to pass to the template
|
|
60
|
+
*/
|
|
61
|
+
aggregate := func(data, indices, bodyTpl, outputs, isEph, ...extra) {
|
|
62
|
+
renderInputs := {
|
|
63
|
+
params: smart.createJsonResource({
|
|
64
|
+
indices: indices,
|
|
65
|
+
eph: isEph,
|
|
66
|
+
outputs: outputs
|
|
67
|
+
}),
|
|
68
|
+
body: bodyTpl,
|
|
69
|
+
data: data
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if len(extra) == 1 {
|
|
73
|
+
for k, v in extra[0] {
|
|
74
|
+
renderInputs["__extra_" + k] = v
|
|
75
|
+
}
|
|
76
|
+
} else if len(extra) != 0 {
|
|
77
|
+
ll.panic("Wrong number of parameters for aggregate method.")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
renderResult := render.createEphemeral(llAggTpl, renderInputs)
|
|
81
|
+
return renderResult;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export ll.toStrict({
|
|
85
|
+
aggregate: aggregate
|
|
86
|
+
})
|