@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,244 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
validation := import("@platforma-sdk/workflow-tengo:validation")
|
|
3
|
+
constants := import("@platforma-sdk/workflow-tengo:pframes.constants")
|
|
4
|
+
objects := import("@platforma-sdk/workflow-tengo:objects")
|
|
5
|
+
|
|
6
|
+
_PRE_PROCESS_STEP_SCHEMA := [`or`,
|
|
7
|
+
{
|
|
8
|
+
// Replace cell value with the first full RegEx match
|
|
9
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match
|
|
10
|
+
`type`: `string,regex=regexpExtract`,
|
|
11
|
+
// String representing ECMAScript RegEx
|
|
12
|
+
// If there are no or more than one matches - result would become NA
|
|
13
|
+
`pattern`: `string`
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
// Perform JS String.prototype.replace() operation
|
|
17
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
|
|
18
|
+
`type`: `string,regex=regexpReplace`,
|
|
19
|
+
// String representing ECMAScript RegEx with at least one capturing group.
|
|
20
|
+
// If you need to reorder capturing groups - use RegExp matching the whole string
|
|
21
|
+
// (must start with string begin anchor ^, end with string end anchor $).
|
|
22
|
+
// Use regex playground https://regexr.com/ to test your ideas.
|
|
23
|
+
`pattern`: `string`,
|
|
24
|
+
// Replacement pattern used to construct result string from captured groups
|
|
25
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement
|
|
26
|
+
// Empty string as result would become NA.
|
|
27
|
+
`replacement`: `string`
|
|
28
|
+
}]
|
|
29
|
+
|
|
30
|
+
_SPEC_AXES_SCHEMA := {
|
|
31
|
+
// Column label from XSV
|
|
32
|
+
`column`: `string`,
|
|
33
|
+
// Pre-processing operations to be performed just after reading XSV, before any other operations
|
|
34
|
+
`preProcess,omitempty`: [_PRE_PROCESS_STEP_SCHEMA],
|
|
35
|
+
// Should the N/A values (or empty rows) be allowed;
|
|
36
|
+
// default: false
|
|
37
|
+
`allowNA,omitempty`: `bool`,
|
|
38
|
+
// Specification of the axis
|
|
39
|
+
`spec`: {
|
|
40
|
+
// Type of the axis value
|
|
41
|
+
`type`: `string,regex=Int|Long|Float|Double|String|Bytes`,
|
|
42
|
+
// Name of the axis to be used in spec;
|
|
43
|
+
// default: column label
|
|
44
|
+
`name,omitempty`: `string`,
|
|
45
|
+
// Auxiliary information to the axis name, type and parents to form a unique identifier;
|
|
46
|
+
// default: empty
|
|
47
|
+
`domain,omitempty`: { any: `string` },
|
|
48
|
+
// Any additional information attached to the axis that does not affect its identifier;
|
|
49
|
+
// default: "pl7.app/label": Column label from XSV
|
|
50
|
+
`annotations,omitempty`: { any: `string` },
|
|
51
|
+
// A list of zero-based indices of parent axes in the overall axes specification;
|
|
52
|
+
// default: empty
|
|
53
|
+
`parentAxes,omitempty`: [`number`]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_SPEC_COLUMN_SCHEMA := {
|
|
58
|
+
// Column label from XSV
|
|
59
|
+
`column`: `string`,
|
|
60
|
+
// ID of the column to be used in spec and as a saved filename;
|
|
61
|
+
// default: column label with all special characters replaced with '_'
|
|
62
|
+
`id,omitempty`: `string`,
|
|
63
|
+
// Pre-processing operations to be performed just after reading XSV, before any other operations;
|
|
64
|
+
// warning: when pre-processing is used, spec valueType must be set
|
|
65
|
+
`preProcess,omitempty`: [_PRE_PROCESS_STEP_SCHEMA],
|
|
66
|
+
// Should the N/A values (or empty rows) be allowed;
|
|
67
|
+
// default: true
|
|
68
|
+
`allowNA,omitempty`: `bool`,
|
|
69
|
+
// Specification of the column
|
|
70
|
+
`spec,omitempty`: {
|
|
71
|
+
// Type of column values;
|
|
72
|
+
// default: automatically detected to be one of Long, Double, String
|
|
73
|
+
`type,omitempty`: `string,regex=Int|Long|Float|Double|String|Bytes`,
|
|
74
|
+
// Name of the column to be used in spec;
|
|
75
|
+
// default: column label
|
|
76
|
+
`name,omitempty`: `string`,
|
|
77
|
+
// Auxiliary information to the column name, type and parents to form a unique identifier;
|
|
78
|
+
// default: empty
|
|
79
|
+
`domain,omitempty`: { any: `string` },
|
|
80
|
+
// Any additional information attached to the axis that does not affect its identifier;
|
|
81
|
+
// default: "pl7.app/label": Column label from XSV
|
|
82
|
+
`annotations,omitempty`: { any: `string` },
|
|
83
|
+
// A list of zero-based indices of parent axes in the overall axes specification;
|
|
84
|
+
// default: empty
|
|
85
|
+
`parentAxes,omitempty`: [ `number` ]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_SPEC_INDEX_SCHEMA := {
|
|
90
|
+
// Name of the axis
|
|
91
|
+
`name`: `string`,
|
|
92
|
+
// Auxiliary information to the column name, type and parents to form a unique identifier;
|
|
93
|
+
// default: empty
|
|
94
|
+
`domain,omitempty`: { any: `string` },
|
|
95
|
+
// Any additional information attached to the axis that does not affect its identifier;
|
|
96
|
+
// default: "pl7.app/label": name
|
|
97
|
+
`annotations,omitempty`: { any: `string` },
|
|
98
|
+
// A list of zero-based indices of parent axes in the overall axes specification;
|
|
99
|
+
// default: empty
|
|
100
|
+
`parentAxes,omitempty`: [`number`]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
PFCONV_CFG_SCHEMA := {
|
|
104
|
+
// Columns would be stored using specified format;
|
|
105
|
+
// default: Binary
|
|
106
|
+
`storageFormat,omitempty` : `string,regex=Binary|Json`,
|
|
107
|
+
// Partitioning key length;
|
|
108
|
+
// default: 0
|
|
109
|
+
`partitionKeyLength,omitempty` : `number`,
|
|
110
|
+
// XSV columns to use as PColumn axes, order of axes in resulting columns
|
|
111
|
+
// would match the order of spec entries provided here
|
|
112
|
+
`axes`: [_SPEC_AXES_SCHEMA],
|
|
113
|
+
// XSV columns to use as PColumn values, each exported individually
|
|
114
|
+
`columns`: [_SPEC_COLUMN_SCHEMA],
|
|
115
|
+
// Axis of type Int with XSV row numbers (would be the last one);
|
|
116
|
+
// default: do not create additional axis with indexes
|
|
117
|
+
`index,omitempty`: _SPEC_INDEX_SCHEMA,
|
|
118
|
+
// String representing NA values of types Int, Long, Float, Double
|
|
119
|
+
// default: NaN
|
|
120
|
+
`naStr,omitempty`: `string`,
|
|
121
|
+
// String representing NA values of types String, Bytes
|
|
122
|
+
// default: null
|
|
123
|
+
`nullStr,omitempty`: `string`,
|
|
124
|
+
// Single ASCII character to be used as separator;
|
|
125
|
+
// default: ',' for .csv, '\t' for .tsv
|
|
126
|
+
`separator,omitempty`: `string`,
|
|
127
|
+
// Interpret empty string as NA value
|
|
128
|
+
// default: true
|
|
129
|
+
`emptyStrAsNA,omitempty`: `bool`,
|
|
130
|
+
// Prefix all column names with given string;
|
|
131
|
+
// default: names would be preserved
|
|
132
|
+
`columnNamePrefix,omitempty`: `string`,
|
|
133
|
+
// Resolve duplicates by adding sequential suffixes to column labels;
|
|
134
|
+
// default: true
|
|
135
|
+
`allowColumnLabelDuplicates,omitempty`: `bool`,
|
|
136
|
+
// When columns spec is provided but no such column was found in XSV - create such column
|
|
137
|
+
// filled with NA values instead of failing;
|
|
138
|
+
// default: false
|
|
139
|
+
`allowArtificialColumns,omitempty`: `bool`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get column id from the column spec
|
|
145
|
+
*/
|
|
146
|
+
xsvColumnId := func(c) {
|
|
147
|
+
id := c.id
|
|
148
|
+
if is_undefined(id) {
|
|
149
|
+
id = c.column
|
|
150
|
+
}
|
|
151
|
+
return id
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Removes all annotations & domain information from spec, to pass it to pfconv
|
|
156
|
+
*/
|
|
157
|
+
purifySpec := func(spec) {
|
|
158
|
+
newSpec := copy(spec)
|
|
159
|
+
|
|
160
|
+
newAxes := []
|
|
161
|
+
for ax in spec.axes {
|
|
162
|
+
newAxes = append(newAxes, {
|
|
163
|
+
column: ax.column,
|
|
164
|
+
spec: { type: ax.spec.type }
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
newSpec.axes = newAxes
|
|
168
|
+
|
|
169
|
+
newCols := []
|
|
170
|
+
for col in spec.columns {
|
|
171
|
+
newCols = append(newCols, objects.deleteUndefined({
|
|
172
|
+
column: col.column,
|
|
173
|
+
id: col.id,
|
|
174
|
+
allowNA: col.allowNA,
|
|
175
|
+
spec: { valueType: col.spec.valueType }
|
|
176
|
+
}))
|
|
177
|
+
}
|
|
178
|
+
newSpec.columns = newCols
|
|
179
|
+
|
|
180
|
+
validation.assertJsonSchema(newSpec, PFCONV_CFG_SCHEMA)
|
|
181
|
+
|
|
182
|
+
return newSpec
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Split given pfconv config into:
|
|
187
|
+
*
|
|
188
|
+
* (1) purified cfg with minimal required settings to be passed to the pfconv binary,
|
|
189
|
+
* to maximize caching retention when domains and annotations changes
|
|
190
|
+
* (2) complete columns specs, that can be directly rendered into BObjectSpecs and
|
|
191
|
+
* returned as workflow exports
|
|
192
|
+
*
|
|
193
|
+
* This method comes in handy in situations where actual csv -> pframe export is broadcasted
|
|
194
|
+
* onto multiple objects, and then converges, so that each export operation only requires purified
|
|
195
|
+
* config, and only data is saved for such operations, and actual specs are added somewhere
|
|
196
|
+
* upstream.
|
|
197
|
+
*
|
|
198
|
+
* @param cfg full pfconv config object
|
|
199
|
+
* @param ops additional options
|
|
200
|
+
* {
|
|
201
|
+
* additionalAxesSpec - array of additional axes spec to prepend to each column spec
|
|
202
|
+
* }
|
|
203
|
+
*
|
|
204
|
+
* @return {
|
|
205
|
+
* purifiedCfg - purified pfconv config
|
|
206
|
+
* columnsSpec - map of full column specs by ids from the original cfg
|
|
207
|
+
* }
|
|
208
|
+
*/
|
|
209
|
+
decomposePfconvCfg := func(cfg, ...ops) {
|
|
210
|
+
ll.assert(len(ops) <= 1, "too many options for decomposePfconvCfg: %v", len(ops))
|
|
211
|
+
|
|
212
|
+
axesSpec := []
|
|
213
|
+
if len(ops) == 1 && !is_undefined(ops[0].additionalAxesSpec) {
|
|
214
|
+
axesSpec = ops[0].additionalAxesSpec
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for axis in cfg.axes {
|
|
218
|
+
axesSpec = append(axesSpec, axis.spec)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
columnsSpec := {}
|
|
222
|
+
|
|
223
|
+
for column in cfg.columns {
|
|
224
|
+
id := xsvColumnId(column)
|
|
225
|
+
ll.assert(is_undefined(columnsSpec[id]), "repeated column spec id in pfconv cfg: %v", id)
|
|
226
|
+
columnsSpec[id] = column.spec
|
|
227
|
+
columnsSpec[id].axesSpec = axesSpec
|
|
228
|
+
// make sure spec contain correct kind value
|
|
229
|
+
columnsSpec[id].kind = "PColumn"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
purifiedCfg: purifySpec(cfg),
|
|
234
|
+
columnsSpec: columnsSpec
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export ll.toStrict({
|
|
239
|
+
PFCONV_CFG_SCHEMA: PFCONV_CFG_SCHEMA,
|
|
240
|
+
|
|
241
|
+
xsvColumnId: xsvColumnId,
|
|
242
|
+
purifySpec: purifySpec,
|
|
243
|
+
decomposePfconvCfg: decomposePfconvCfg
|
|
244
|
+
})
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library providing xsv <> p-frames conversion utils.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
validation := import("@platforma-sdk/workflow-tengo:validation")
|
|
6
|
+
constants := import("@platforma-sdk/workflow-tengo:pframes.constants")
|
|
7
|
+
objects := import("@platforma-sdk/workflow-tengo:objects")
|
|
8
|
+
render := import("@platforma-sdk/workflow-tengo:render")
|
|
9
|
+
exec := import("@platforma-sdk/workflow-tengo:exec")
|
|
10
|
+
json := import("json")
|
|
11
|
+
util := import("@platforma-sdk/workflow-tengo:pframes.util")
|
|
12
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
13
|
+
assets := import("@platforma-sdk/workflow-tengo:assets")
|
|
14
|
+
|
|
15
|
+
pfconvSw := assets.importSoftware("@milaboratories/software-pframes-conv:main")
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Calculate axes spec from pfconv spec
|
|
19
|
+
*/
|
|
20
|
+
getAxesSpec := func(spec) {
|
|
21
|
+
axes := []
|
|
22
|
+
for ax in spec.axes {
|
|
23
|
+
axes = append(axes, ax.spec)
|
|
24
|
+
}
|
|
25
|
+
return axes
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
renderOps := func(defaults, ...ops) {
|
|
29
|
+
o := { }
|
|
30
|
+
|
|
31
|
+
for k, v in defaults {
|
|
32
|
+
o[k] = v
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if len(ops) > 0 {
|
|
36
|
+
for k, v in ops[0] {
|
|
37
|
+
o[k] = v
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return o
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getColumnSpec := func(axesSpec, col) {
|
|
44
|
+
spec := {
|
|
45
|
+
kind: constants.KIND_P_COLUMN,
|
|
46
|
+
axesSpec: axesSpec
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for k, v in col.spec {
|
|
50
|
+
spec[k] = v
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return objects.deleteUndefined(spec)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Imports xsv data into p-frame. The resulting map resource contains all columns specified in the params (column identifiers as
|
|
58
|
+
* provided by the spec used as map keys). Resulting p-columns will be always single-partitioned at most.
|
|
59
|
+
*
|
|
60
|
+
* @param xsvFile: reference - a reference to a file
|
|
61
|
+
* @param xsvType: string - either csv or tsv
|
|
62
|
+
* @param spec: object - xsv conversion specification
|
|
63
|
+
* @param ops: dict - additional params (internal)
|
|
64
|
+
* @return map: reference - a reference to a map resource storing imported data.
|
|
65
|
+
*/
|
|
66
|
+
importFile := func(xsvFile, xsvType, spec, ...ops) {
|
|
67
|
+
ll.assert(xsvType == "csv" || xsvType == "tsv", "expected one of [tsv, csv] types")
|
|
68
|
+
|
|
69
|
+
validation.assertJsonSchema(spec, util.PFCONV_CFG_SCHEMA)
|
|
70
|
+
|
|
71
|
+
xsvFileName := "file." + xsvType
|
|
72
|
+
|
|
73
|
+
// import p-frame from directory tpl
|
|
74
|
+
importDirTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.import-dir")
|
|
75
|
+
|
|
76
|
+
// spec without any metadata (for caching purposes)
|
|
77
|
+
pureSpec := util.purifySpec(spec)
|
|
78
|
+
|
|
79
|
+
// convert csv to p-frame and read resulting data
|
|
80
|
+
pfconv := exec.builder().
|
|
81
|
+
software(pfconvSw).
|
|
82
|
+
arg("importCsv").
|
|
83
|
+
arg(xsvFileName).
|
|
84
|
+
arg("-p").arg("spec.json").
|
|
85
|
+
arg("-o").arg("out").
|
|
86
|
+
addFile(xsvFileName, xsvFile).
|
|
87
|
+
writeFile("spec.json", json.encode(pureSpec)).
|
|
88
|
+
processWorkdir("pf", importDirTpl, pureSpec).
|
|
89
|
+
run()
|
|
90
|
+
|
|
91
|
+
ops := renderOps({ dataOnly: false }, ops...)
|
|
92
|
+
|
|
93
|
+
// p-columns data
|
|
94
|
+
pf := pfconv.getProcessorResult("pf")
|
|
95
|
+
if ops.dataOnly {
|
|
96
|
+
return pf
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
axesSpec := getAxesSpec(spec)
|
|
100
|
+
|
|
101
|
+
result := {}
|
|
102
|
+
for col in spec.columns {
|
|
103
|
+
id := util.xsvColumnId(col)
|
|
104
|
+
|
|
105
|
+
result[id + ".data"] = pf.getFutureInputField(id)
|
|
106
|
+
result[id + ".spec"] = getColumnSpec(axesSpec, col)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return result
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Imports a map with xsv files into a p-frame. The resulting map resource contains all columns specified in the params (column identifiers as
|
|
114
|
+
* provided by the spec used as map keys). Resulting p-columns may be double-partitioned.
|
|
115
|
+
*
|
|
116
|
+
* @param xsvFile: reference - a reference to a file
|
|
117
|
+
* @param xsvType: string - either csv or tsv
|
|
118
|
+
* @param spec: object - xsv conversion specification
|
|
119
|
+
* @param ops: object - additional options
|
|
120
|
+
* {
|
|
121
|
+
* dataOnly: boolean - set to true to completely skip creation of specs
|
|
122
|
+
* splitDataAndSpec: boolean - if true, resulting map will have nested structures,
|
|
123
|
+
* with "spec" + "data" fields in nested maps
|
|
124
|
+
* additionalAxesSpec: AxisSpec[] - array of additional axes spec to prepend to
|
|
125
|
+
* each column spec
|
|
126
|
+
* }
|
|
127
|
+
* @return map: reference - a reference to a map resource storing imported data.
|
|
128
|
+
*/
|
|
129
|
+
importFileMap := func(xsvMap, xsvType, spec, ...ops) {
|
|
130
|
+
|
|
131
|
+
importXsvMapTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.import-xsv-map")
|
|
132
|
+
|
|
133
|
+
ops := renderOps({
|
|
134
|
+
dataOnly: false,
|
|
135
|
+
splitDataAndSpec: false,
|
|
136
|
+
additionalAxesSpec: []
|
|
137
|
+
}, ops...)
|
|
138
|
+
|
|
139
|
+
// spec without any metadata (for caching purposes)
|
|
140
|
+
decomposedSpec := util.decomposePfconvCfg(spec, { additionalAxesSpec: ops.additionalAxesSpec })
|
|
141
|
+
pureSpec := decomposedSpec.purifiedCfg
|
|
142
|
+
columnsSpec := decomposedSpec.columnsSpec
|
|
143
|
+
|
|
144
|
+
r := render.createEphemeral(importXsvMapTpl, {
|
|
145
|
+
xsvMap: xsvMap,
|
|
146
|
+
xsvType: xsvType,
|
|
147
|
+
spec: pureSpec,
|
|
148
|
+
ops: { dataOnly: true }
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
if ops.dataOnly && ops.splitDataAndSpec {
|
|
152
|
+
ll.panic("Can't use both options dataOnly and splitDataAndSpec at the same time.")
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
result := {}
|
|
156
|
+
axesSpec := getAxesSpec(spec)
|
|
157
|
+
for c in spec.columns {
|
|
158
|
+
id := util.xsvColumnId(c)
|
|
159
|
+
if ops.dataOnly {
|
|
160
|
+
result[id] = r.output(id)
|
|
161
|
+
} else if ops.splitDataAndSpec {
|
|
162
|
+
result[id] = {
|
|
163
|
+
data: r.output(id),
|
|
164
|
+
spec: columnsSpec[id]
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
result[id + ".data"] = r.output(id)
|
|
168
|
+
result[id + ".spec"] = columnsSpec[id]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return result
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export ll.toStrict({
|
|
176
|
+
importFile: importFile,
|
|
177
|
+
importFileMap: importFileMap
|
|
178
|
+
})
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Create renderer objects to render templates from the code
|
|
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
|
+
tplutil := import("@platforma-sdk/workflow-tengo:tpl.util")
|
|
9
|
+
constants := import("@platforma-sdk/workflow-tengo:constants")
|
|
10
|
+
oop := import("@platforma-sdk/workflow-tengo:oop")
|
|
11
|
+
validation := import("@platforma-sdk/workflow-tengo:validation")
|
|
12
|
+
tx := import("tx")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_SUBSCRIPTION_FIELD := "subscription"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a render template resource.
|
|
19
|
+
*
|
|
20
|
+
* @param tpl: template resource (see assets.importTemplate())
|
|
21
|
+
* @param isEph: whether template is ephemeral
|
|
22
|
+
* @param inputs: a map of inputs to be passed to the template
|
|
23
|
+
* @return renderer: a smart resource with additional output("name") method
|
|
24
|
+
*/
|
|
25
|
+
createUniversal := func(tpl, isEph, inputs) {
|
|
26
|
+
|
|
27
|
+
// build renderer resource
|
|
28
|
+
rbuilder := undefined
|
|
29
|
+
if isEph {
|
|
30
|
+
rbuilder = smart.ephemeralBuilder(constants.RTYPE_RENDER_EPH_TEMPLATE)
|
|
31
|
+
} else {
|
|
32
|
+
rbuilder = smart.structBuilder(constants.RTYPE_RENDER_TEMPLATE)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if isEph {
|
|
36
|
+
// create internal subscription field
|
|
37
|
+
rbuilder.createField(_SUBSCRIPTION_FIELD, "OTW")
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// template input
|
|
41
|
+
rbuilder.createInputField(tplutil.TEMPLATE_FIELD).set(tpl)
|
|
42
|
+
|
|
43
|
+
// inputs input
|
|
44
|
+
inputsMap := isEph ? smart.ephemeralMapBuilder() : smart.mapBuilder()
|
|
45
|
+
for name, value in inputs {
|
|
46
|
+
inputsMap.add(name, value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
rbuilder.createInputField(tplutil.INPUTS_MAP_FIELD).set(inputsMap.build())
|
|
50
|
+
// build
|
|
51
|
+
renderer := rbuilder.lockInputsAndBuild()
|
|
52
|
+
|
|
53
|
+
self := undefined
|
|
54
|
+
self = ll.toStrict(oop.inherit(renderer, {
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Returns an output field with a given name
|
|
58
|
+
*/
|
|
59
|
+
output: func(name, ...cache) {
|
|
60
|
+
ll.assert(len(cache) == 0 || is_int(cache[0]), "cache should be a number (milliseconds)")
|
|
61
|
+
out := renderer.getFutureOutputField(tplutil.TEMPLATE_OUTPUT_PREFIX + name)
|
|
62
|
+
if len(cache) > 0 && cache[0] > 0 {
|
|
63
|
+
cache = cache[0]
|
|
64
|
+
tx.cacheSetToField(out.id, cache)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return out
|
|
68
|
+
}
|
|
69
|
+
}))
|
|
70
|
+
|
|
71
|
+
return self
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Creates a render template resource.
|
|
76
|
+
*
|
|
77
|
+
* @param tpl: template resource (see assets.importTemplate())
|
|
78
|
+
* @param inputs: a map of inputs to be passed to the template
|
|
79
|
+
* @return renderer: a smart resource with additional output("name") method
|
|
80
|
+
*/
|
|
81
|
+
create := func(tpl, inputs) {
|
|
82
|
+
return createUniversal(tpl, false, inputs)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Creates ephemeral render template resource.
|
|
87
|
+
*
|
|
88
|
+
* @param tpl: template resource (see assets.importTemplate())
|
|
89
|
+
* @param inputs: a map of inputs to be passed to the template
|
|
90
|
+
* @return renderer: a smart resource with additional output("name") method
|
|
91
|
+
*/
|
|
92
|
+
createEphemeral := func(tpl, inputs) {
|
|
93
|
+
return createUniversal(tpl, true, inputs)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export ll.toStrict({
|
|
97
|
+
createUniversal: createUniversal,
|
|
98
|
+
create: create,
|
|
99
|
+
createEphemeral: createEphemeral
|
|
100
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Functions for working with sets of elements,
|
|
3
|
+
* in Tengo they are just maps with truthy values.
|
|
4
|
+
* Keys of the map can be only either strings or numbers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
8
|
+
maps := import("@platforma-sdk/workflow-tengo:maps")
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Turns a slice to a set of values.
|
|
12
|
+
*
|
|
13
|
+
* @param slice: slice<string|number>
|
|
14
|
+
* @return result: set<string|number>
|
|
15
|
+
*/
|
|
16
|
+
fromSlice := func(slice) {
|
|
17
|
+
set := {}
|
|
18
|
+
for _, elem in slice {
|
|
19
|
+
set[elem] = true
|
|
20
|
+
}
|
|
21
|
+
return set
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert given set to slice
|
|
26
|
+
*
|
|
27
|
+
* @param set: set - a set of values to be converted to slice
|
|
28
|
+
* @return slice: []<string|number>
|
|
29
|
+
*/
|
|
30
|
+
toSlice := func(set) {
|
|
31
|
+
sl := []
|
|
32
|
+
for v, _ in set {
|
|
33
|
+
sl = append(sl, v)
|
|
34
|
+
}
|
|
35
|
+
return sl
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Checks if a set has an element.
|
|
40
|
+
*
|
|
41
|
+
* @param set a set of any elements
|
|
42
|
+
* @param element any
|
|
43
|
+
* @return found: bool
|
|
44
|
+
*/
|
|
45
|
+
hasElement := func(set, element) {
|
|
46
|
+
return !is_undefined(set[element])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Adds elements to the set.
|
|
51
|
+
*
|
|
52
|
+
* @param set a set
|
|
53
|
+
* @param elements a slice of elements
|
|
54
|
+
* @return: result: set<string|number> - a changed old set with all old and new elements.
|
|
55
|
+
*/
|
|
56
|
+
add := func(set, ...elements) {
|
|
57
|
+
for _, elem in elements {
|
|
58
|
+
set[elem] = true
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return set
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Returns a set of key of the map.
|
|
66
|
+
*
|
|
67
|
+
* @param map a map
|
|
68
|
+
* @return result: set<string|number>
|
|
69
|
+
*/
|
|
70
|
+
fromMapKeys := func(map) {
|
|
71
|
+
keys := maps.getKeys(map)
|
|
72
|
+
return fromSlice(keys)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Transforms all keys of the map with a function and returns a new map with these keys.
|
|
77
|
+
*
|
|
78
|
+
* @param set: set
|
|
79
|
+
* @param fn: func(elem): newElem - a function that gets an element and returns a new element.
|
|
80
|
+
* @return new set: map[newElem]any - a transformed set
|
|
81
|
+
*/
|
|
82
|
+
map := func(set, fn) {
|
|
83
|
+
return maps.mapKeys(set, fn)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export ll.toStrict({
|
|
87
|
+
fromSlice: fromSlice,
|
|
88
|
+
toSlice: toSlice,
|
|
89
|
+
hasElement: hasElement,
|
|
90
|
+
add: add,
|
|
91
|
+
fromMapKeys: fromMapKeys,
|
|
92
|
+
map: map
|
|
93
|
+
})
|