@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.
Files changed (51) hide show
  1. package/README.md +6 -0
  2. package/dist/tengo/lib/assets.lib.tengo +64 -0
  3. package/dist/tengo/lib/constants.lib.tengo +75 -0
  4. package/dist/tengo/lib/exec.internal.lib.tengo +211 -0
  5. package/dist/tengo/lib/exec.lib.tengo +516 -0
  6. package/dist/tengo/lib/exec.package.lib.tengo +296 -0
  7. package/dist/tengo/lib/exec.runcmd.lib.tengo +275 -0
  8. package/dist/tengo/lib/exec.runenv.lib.tengo +221 -0
  9. package/dist/tengo/lib/exec.stream.lib.tengo +64 -0
  10. package/dist/tengo/lib/file.lib.tengo +112 -0
  11. package/dist/tengo/lib/ll.lib.tengo +233 -0
  12. package/dist/tengo/lib/maps.lib.tengo +102 -0
  13. package/dist/tengo/lib/objects.lib.tengo +22 -0
  14. package/dist/tengo/lib/oop.lib.tengo +29 -0
  15. package/dist/tengo/lib/path.lib.tengo +165 -0
  16. package/dist/tengo/lib/pframes.constants.lib.tengo +53 -0
  17. package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +47 -0
  18. package/dist/tengo/lib/pframes.lib.tengo +84 -0
  19. package/dist/tengo/lib/pframes.ll.lib.tengo +86 -0
  20. package/dist/tengo/lib/pframes.util.lib.tengo +244 -0
  21. package/dist/tengo/lib/pframes.xsv.lib.tengo +178 -0
  22. package/dist/tengo/lib/render.lib.tengo +100 -0
  23. package/dist/tengo/lib/sets.lib.tengo +93 -0
  24. package/dist/tengo/lib/slices.lib.tengo +202 -0
  25. package/dist/tengo/lib/smart.lib.tengo +1005 -0
  26. package/dist/tengo/lib/tpl.lib.tengo +535 -0
  27. package/dist/tengo/lib/tpl.state-await.lib.tengo +255 -0
  28. package/dist/tengo/lib/tpl.util.lib.tengo +19 -0
  29. package/dist/tengo/lib/validation.lib.tengo +428 -0
  30. package/dist/tengo/lib/workdir.lib.tengo +300 -0
  31. package/dist/tengo/lib/workdir.proc.lib.tengo +158 -0
  32. package/dist/tengo/lib/workdir.save.lib.tengo +158 -0
  33. package/dist/tengo/lib/workflow.bobject.lib.tengo +51 -0
  34. package/dist/tengo/lib/workflow.bquery.lib.tengo +208 -0
  35. package/dist/tengo/lib/workflow.constants.lib.tengo +8 -0
  36. package/dist/tengo/lib/workflow.context.lib.tengo +56 -0
  37. package/dist/tengo/lib/workflow.lib.tengo +298 -0
  38. package/dist/tengo/tpl/exec.create-python-venv.plj.gz +0 -0
  39. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  40. package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
  41. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  42. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  43. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  44. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  45. package/dist/tengo/tpl/pframes.import-xsv-map.plj.gz +0 -0
  46. package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
  47. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  48. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  49. package/index.d.ts +4 -0
  50. package/index.js +13 -0
  51. 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
+ })