@platforma-sdk/workflow-tengo 5.3.5 → 5.3.7
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/index.cjs +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +7 -23
- package/dist/tengo/lib/pframes.util.lib.tengo +2 -2
- package/dist/tengo/lib/pframes.xsv-import-file.lib.tengo +10 -0
- package/dist/tengo/lib/pframes.xsv-import-pt.lib.tengo +234 -0
- package/dist/tengo/lib/pframes.xsv.lib.tengo +8 -81
- package/dist/tengo/lib/pt.expression.lib.tengo +85 -2
- package/dist/tengo/lib/pt.lib.tengo +98 -73
- package/dist/tengo/tpl/anonymize.deanonymize.plj.gz +0 -0
- package/dist/tengo/tpl/anonymize.impl.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
- package/dist/tengo/tpl/check_network.workdir_type_name_extractor.plj.gz +0 -0
- package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.delayed-compute-allocation.impl.plj.gz +0 -0
- package/dist/tengo/tpl/exec.exec-impl.plj.gz +0 -0
- package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
- package/dist/tengo/tpl/exec.load-software.impl.plj.gz +0 -0
- package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
- package/dist/tengo/tpl/exec.monetization_to_json.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/exec.python.venv-bin-path.plj.gz +0 -0
- package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-parquet-pcolumn-chunk.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-pframe-for-ui.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.parse-to-json.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
- package/dist/tengo/tpl/pt.import-dir.plj.gz +0 -0
- package/dist/tengo/tpl/pt.workflow-run.plj.gz +0 -0
- package/dist/tengo/tpl/waiter.waiter.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/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module.exports = { Templates: {
|
|
2
2
|
'll.get-field': { type: 'from-file', path: require.resolve('./tengo/tpl/ll.get-field.plj.gz') },
|
|
3
|
+
'pframes.export-parquet-pcolumn-chunk': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.export-parquet-pcolumn-chunk.plj.gz') },
|
|
3
4
|
'pframes.export-single-pcolumn': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.export-single-pcolumn.plj.gz') },
|
|
4
5
|
'pframes.import-dir': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.import-dir.plj.gz') },
|
|
5
6
|
'pframes.remove-nulls': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.remove-nulls.plj.gz') },
|
|
@@ -28,10 +29,11 @@ module.exports = { Templates: {
|
|
|
28
29
|
'pframes.parse-to-json': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.parse-to-json.plj.gz') },
|
|
29
30
|
'exec.load-software.impl': { type: 'from-file', path: require.resolve('./tengo/tpl/exec.load-software.impl.plj.gz') },
|
|
30
31
|
'exec.exec': { type: 'from-file', path: require.resolve('./tengo/tpl/exec.exec.plj.gz') },
|
|
31
|
-
'pframes.xsv-import-if-not-null': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-import-if-not-null.plj.gz') },
|
|
32
32
|
'pt.workflow-run': { type: 'from-file', path: require.resolve('./tengo/tpl/pt.workflow-run.plj.gz') },
|
|
33
33
|
'check_network.run_hello_world': { type: 'from-file', path: require.resolve('./tengo/tpl/check_network.run_hello_world.plj.gz') },
|
|
34
34
|
'check_network.run_hello_world_py': { type: 'from-file', path: require.resolve('./tengo/tpl/check_network.run_hello_world_py.plj.gz') },
|
|
35
|
+
'pframes.xsv-export-pframe': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-export-pframe.plj.gz') },
|
|
36
|
+
'pframes.xsv-import-if-not-null': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-import-if-not-null.plj.gz') },
|
|
35
37
|
'pframes.xsv-import-map': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-import-map.plj.gz') },
|
|
36
38
|
'pframes.process-pcolumn-data': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.process-pcolumn-data.plj.gz') },
|
|
37
39
|
'pframes.export-pframe': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.export-pframe.plj.gz') },
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
declare type TemplateFromFile = { readonly type: "from-file"; readonly path: string; };
|
|
2
|
-
declare type TplName = "ll.get-field" | "pframes.export-single-pcolumn" | "pframes.import-dir" | "pframes.remove-nulls" | "pt.import-dir" | "waiter.waiter" | "workdir.save" | "workflow.build-ctx" | "workflow.query-anchored" | "anonymize.deanonymize" | "anonymize.impl" | "check_network.workdir_type_name_extractor" | "exec.delayed-compute-allocation.impl" | "exec.monetization_to_json" | "exec.python.install-deps" | "exec.python.venv-bin-path" | "pframes.export-multiple-pcolumns" | "pframes.slice-data" | "check_network.create_workdir_from_storage" | "check_network.download_blob" | "check_network.upload_blob" | "check_network.upload_template" | "exec.R.create-renv" | "exec.exec-impl" | "exec.monetization_info" | "exec.python.create-venv" | "pframes.parse-to-json" | "exec.load-software.impl" | "exec.exec" | "
|
|
2
|
+
declare type TplName = "ll.get-field" | "pframes.export-parquet-pcolumn-chunk" | "pframes.export-single-pcolumn" | "pframes.import-dir" | "pframes.remove-nulls" | "pt.import-dir" | "waiter.waiter" | "workdir.save" | "workflow.build-ctx" | "workflow.query-anchored" | "anonymize.deanonymize" | "anonymize.impl" | "check_network.workdir_type_name_extractor" | "exec.delayed-compute-allocation.impl" | "exec.monetization_to_json" | "exec.python.install-deps" | "exec.python.venv-bin-path" | "pframes.export-multiple-pcolumns" | "pframes.slice-data" | "check_network.create_workdir_from_storage" | "check_network.download_blob" | "check_network.upload_blob" | "check_network.upload_template" | "exec.R.create-renv" | "exec.exec-impl" | "exec.monetization_info" | "exec.python.create-venv" | "pframes.parse-to-json" | "exec.load-software.impl" | "exec.exec" | "pt.workflow-run" | "check_network.run_hello_world" | "check_network.run_hello_world_py" | "pframes.xsv-export-pframe" | "pframes.xsv-import-if-not-null" | "pframes.xsv-import-map" | "pframes.process-pcolumn-data" | "pframes.export-pframe" | "pframes.export-pframe-for-ui";
|
|
3
3
|
declare const Templates: Record<TplName, TemplateFromFile>;
|
|
4
4
|
export { Templates };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
export const Templates = {
|
|
3
3
|
'll.get-field': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/ll.get-field.plj.gz') },
|
|
4
|
+
'pframes.export-parquet-pcolumn-chunk': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.export-parquet-pcolumn-chunk.plj.gz') },
|
|
4
5
|
'pframes.export-single-pcolumn': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.export-single-pcolumn.plj.gz') },
|
|
5
6
|
'pframes.import-dir': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.import-dir.plj.gz') },
|
|
6
7
|
'pframes.remove-nulls': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.remove-nulls.plj.gz') },
|
|
@@ -29,10 +30,11 @@ export const Templates = {
|
|
|
29
30
|
'pframes.parse-to-json': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.parse-to-json.plj.gz') },
|
|
30
31
|
'exec.load-software.impl': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/exec.load-software.impl.plj.gz') },
|
|
31
32
|
'exec.exec': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/exec.exec.plj.gz') },
|
|
32
|
-
'pframes.xsv-import-if-not-null': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-import-if-not-null.plj.gz') },
|
|
33
33
|
'pt.workflow-run': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pt.workflow-run.plj.gz') },
|
|
34
34
|
'check_network.run_hello_world': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/check_network.run_hello_world.plj.gz') },
|
|
35
35
|
'check_network.run_hello_world_py': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/check_network.run_hello_world_py.plj.gz') },
|
|
36
|
+
'pframes.xsv-export-pframe': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-export-pframe.plj.gz') },
|
|
37
|
+
'pframes.xsv-import-if-not-null': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-import-if-not-null.plj.gz') },
|
|
36
38
|
'pframes.xsv-import-map': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-import-map.plj.gz') },
|
|
37
39
|
'pframes.process-pcolumn-data': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.process-pcolumn-data.plj.gz') },
|
|
38
40
|
'pframes.export-pframe': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.export-pframe.plj.gz') },
|
|
@@ -9,6 +9,8 @@ json := import("json")
|
|
|
9
9
|
|
|
10
10
|
nestedTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.export-single-pcolumn")
|
|
11
11
|
|
|
12
|
+
parquetChunkTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.export-parquet-pcolumn-chunk")
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
exportPColumnData := func(data) {
|
|
14
16
|
ll.assert(data.info().InputsLocked, "column data resource not locked for export: %v", data.info().Type)
|
|
@@ -41,29 +43,11 @@ exportPColumnData := func(data) {
|
|
|
41
43
|
|
|
42
44
|
newData := smart.structBuilder(data.info().Type, data.info().Data)
|
|
43
45
|
for key, partData in data.inputs() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
key,
|
|
50
|
-
partDataResource.info().Type
|
|
51
|
-
)
|
|
52
|
-
ll.assert(partDataResource.info().InputsLocked, "resource %v inputs not locked", partDataResource.info().Type)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
chunkMetadata := partDataResource.getDataAsJson()
|
|
58
|
-
chunkMetadata.isDownloadable = true
|
|
59
|
-
|
|
60
|
-
parquetChunkResource := smart.structBuilder(partDataResource.info().Type, json.encode(chunkMetadata))
|
|
61
|
-
|
|
62
|
-
partDataFields := partDataResource.metaInputs()
|
|
63
|
-
parquetChunkResource.createMetaField("blob").set(file.exportFile(partDataFields["blob"]))
|
|
64
|
-
parquetChunkResource.createMetaField("mapping").set(partDataFields["mapping"])
|
|
65
|
-
|
|
66
|
-
newData.createInputField(key).set(parquetChunkResource.lockAndBuild())
|
|
46
|
+
exportedDataPart := render.createEphemeral(parquetChunkTpl, {
|
|
47
|
+
key: key,
|
|
48
|
+
data: partData
|
|
49
|
+
}).output("result")
|
|
50
|
+
newData.createInputField(key).set(exportedDataPart)
|
|
67
51
|
}
|
|
68
52
|
return newData.lockAndBuild()
|
|
69
53
|
|
|
@@ -177,7 +177,7 @@ PFCONV_IMPORT_CFG_SCHEMA := {
|
|
|
177
177
|
`columnNamePrefix,?`: `string`,
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
`storageFormat,?` : `string,regex=Binary|Json`,
|
|
180
|
+
`storageFormat,?` : `string,regex=Binary|Json|Parquet`,
|
|
181
181
|
|
|
182
182
|
|
|
183
183
|
`partitionKeyLength,?` : `number`
|
|
@@ -468,7 +468,7 @@ addColumnToWd := func(name, spec, data, execBuilder, ops) {
|
|
|
468
468
|
vt := spec.valueType
|
|
469
469
|
ll.assert(vt == "Int" || vt == "Long" || vt == "Float" || vt == "Double" || vt == "String",
|
|
470
470
|
"Unsupported value type: ", vt, spec)
|
|
471
|
-
|
|
471
|
+
|
|
472
472
|
ll.assert(!is_undefined(data) && smart.isResource(data), "data must be a resource, got: %v", data)
|
|
473
473
|
|
|
474
474
|
ll.assert(!is_undefined(execBuilder), "execBuilder must be defined")
|
|
@@ -7,6 +7,7 @@ util := import("@platforma-sdk/workflow-tengo:pframes.util")
|
|
|
7
7
|
json := import("json")
|
|
8
8
|
constants := import("@platforma-sdk/workflow-tengo:pframes.constants")
|
|
9
9
|
execConstants := import("@platforma-sdk/workflow-tengo:exec.constants")
|
|
10
|
+
xsvImportPt := import("@platforma-sdk/workflow-tengo:pframes.xsv-import-pt")
|
|
10
11
|
|
|
11
12
|
transposeXsvSw := assets.importSoftware("@platforma-open/milaboratories.software-small-binaries:table-converter")
|
|
12
13
|
pfconvSw := assets.importSoftware("@milaboratories/software-pframes-conv:main")
|
|
@@ -95,6 +96,11 @@ importFile := func(xsvFile, xsvType, spec, ...ops) {
|
|
|
95
96
|
len(spec.axes)
|
|
96
97
|
)
|
|
97
98
|
|
|
99
|
+
storageFormat := spec.storageFormat
|
|
100
|
+
if is_undefined(storageFormat) {
|
|
101
|
+
storageFormat = "Binary"
|
|
102
|
+
}
|
|
103
|
+
|
|
98
104
|
xsvFileName := "file." + xsvType
|
|
99
105
|
|
|
100
106
|
ops := renderOps({ dataOnly: false, splitDataAndSpec: false, queue: execConstants.LIGHT_QUEUE, inputCache: undefined }, ops...)
|
|
@@ -161,6 +167,10 @@ importFile := func(xsvFile, xsvType, spec, ...ops) {
|
|
|
161
167
|
xsvFile = transposeXsv.getFile(transposedFileName)
|
|
162
168
|
}
|
|
163
169
|
|
|
170
|
+
if storageFormat == "Parquet" {
|
|
171
|
+
return xsvImportPt.importFileParquet(xsvFile, xsvType, spec, ops)
|
|
172
|
+
}
|
|
173
|
+
|
|
164
174
|
|
|
165
175
|
pureSpec := util.purifySpec(spec)
|
|
166
176
|
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
validation := import("@platforma-sdk/workflow-tengo:validation")
|
|
3
|
+
objects := import("@platforma-sdk/workflow-tengo:objects")
|
|
4
|
+
util := import("@platforma-sdk/workflow-tengo:pframes.util")
|
|
5
|
+
pt := import("@platforma-sdk/workflow-tengo:pt")
|
|
6
|
+
execConstants := import("@platforma-sdk/workflow-tengo:exec.constants")
|
|
7
|
+
maps := import("@platforma-sdk/workflow-tengo:maps")
|
|
8
|
+
slices := import("@platforma-sdk/workflow-tengo:slices")
|
|
9
|
+
smart := import("@platforma-sdk/workflow-tengo:smart")
|
|
10
|
+
|
|
11
|
+
getColumnSpec := func(axesSpec, col) {
|
|
12
|
+
spec := maps.deepMerge(col.spec, {
|
|
13
|
+
kind: "PColumn",
|
|
14
|
+
axesSpec: axesSpec
|
|
15
|
+
})
|
|
16
|
+
return objects.deleteUndefined(spec)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
applyPreProcessSteps := func(colExpr, preProcessSteps) {
|
|
20
|
+
result := colExpr
|
|
21
|
+
if !is_undefined(preProcessSteps) {
|
|
22
|
+
for step in preProcessSteps {
|
|
23
|
+
if step.type == "regexpExtract" {
|
|
24
|
+
result = result.extractEcmaRegex(step.pattern)
|
|
25
|
+
} else if step.type == "regexpReplace" {
|
|
26
|
+
result = result.replaceEcmaRegex(step.pattern, step.replacement)
|
|
27
|
+
} else {
|
|
28
|
+
ll.panic("unknown preProcess step type: %v", step.type)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return result
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
applyNaRegex := func(colExpr, naRegex, colType) {
|
|
36
|
+
if is_undefined(naRegex) {
|
|
37
|
+
return colExpr.cast(colType)
|
|
38
|
+
}
|
|
39
|
+
return pt.when(colExpr.matchesEcmaRegex(naRegex)).
|
|
40
|
+
then(pt.lit(undefined).cast(colType)).
|
|
41
|
+
otherwise(colExpr.cast(colType))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
importFileParquet := func(xsvFile, xsvType, spec, ops) {
|
|
62
|
+
ll.assert(xsvType == "csv" || xsvType == "tsv", "unknown xsv type: %v", xsvType)
|
|
63
|
+
|
|
64
|
+
validation.assertType(spec, util.PFCONV_IMPORT_CFG_SCHEMA)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
ll.assert(is_undefined(spec.index), "index axis is not supported with Parquet storage format")
|
|
68
|
+
|
|
69
|
+
ll.assert(is_undefined(spec.allowArtificialColumns), "allowArtificialColumns are not supported with Parquet storage format")
|
|
70
|
+
|
|
71
|
+
if !is_undefined(spec.separator) {
|
|
72
|
+
expectedSeparator := ","
|
|
73
|
+
if xsvType == "tsv" {
|
|
74
|
+
expectedSeparator = "\t"
|
|
75
|
+
}
|
|
76
|
+
ll.assert(spec.separator == expectedSeparator,
|
|
77
|
+
"separator does not match xsvType %v, expected '%v', got '%v'",
|
|
78
|
+
xsvType, expectedSeparator, spec.separator)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
wf := pt.workflow()
|
|
82
|
+
if !is_undefined(ops.queue) {
|
|
83
|
+
if ops.queue == execConstants.HEAVY_QUEUE {
|
|
84
|
+
wf.inHeavyQueue()
|
|
85
|
+
} else if ops.queue == execConstants.MEDIUM_QUEUE {
|
|
86
|
+
wf.inMediumQueue()
|
|
87
|
+
} else if ops.queue == execConstants.LIGHT_QUEUE {
|
|
88
|
+
wf.inLightQueue()
|
|
89
|
+
} else if ops.queue == execConstants.UI_TASKS_QUEUE {
|
|
90
|
+
wf.inUiQueue()
|
|
91
|
+
} else {
|
|
92
|
+
ll.panic("Unsupported queue: %v", ops.queue)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if !is_undefined(ops.cpu) {
|
|
96
|
+
wf.cpu(ops.cpu)
|
|
97
|
+
}
|
|
98
|
+
if !is_undefined(ops.mem) {
|
|
99
|
+
wf.mem(ops.mem)
|
|
100
|
+
}
|
|
101
|
+
if !is_undefined(ops.inputCache) {
|
|
102
|
+
wf.cacheInputs(ops.inputCache)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
schema := []
|
|
106
|
+
for ax in spec.axes {
|
|
107
|
+
schema = append(schema, {
|
|
108
|
+
column: ax.column,
|
|
109
|
+
type: "String"
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
for col in spec.columns {
|
|
113
|
+
schema = append(schema, {
|
|
114
|
+
column: col.column,
|
|
115
|
+
type: "String"
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
df := wf.frame(xsvFile, {
|
|
119
|
+
xsvType: xsvType,
|
|
120
|
+
ignoreErrors: spec.skipEmptyLines == true,
|
|
121
|
+
commentPrefix: spec.commentLinePrefix,
|
|
122
|
+
schema: schema
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
allColumns := []
|
|
126
|
+
for ax in spec.axes {
|
|
127
|
+
allColumns = append(allColumns, ax.column)
|
|
128
|
+
}
|
|
129
|
+
for col in spec.columns {
|
|
130
|
+
allColumns = append(allColumns, col.column)
|
|
131
|
+
}
|
|
132
|
+
df = df.select(allColumns...)
|
|
133
|
+
|
|
134
|
+
filterConditions := []
|
|
135
|
+
for ax in spec.axes {
|
|
136
|
+
if !is_undefined(ax.filterOutRegex) {
|
|
137
|
+
filterConditions = append(filterConditions, pt.col(ax.column).matchesEcmaRegex(ax.filterOutRegex).not())
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
for col in spec.columns {
|
|
141
|
+
if !is_undefined(col.filterOutRegex) {
|
|
142
|
+
filterConditions = append(filterConditions, pt.col(col.column).matchesEcmaRegex(col.filterOutRegex).not())
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if len(filterConditions) > 0 {
|
|
146
|
+
df = df.filter(pt.and(filterConditions...))
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
projection := []
|
|
150
|
+
for ax in spec.axes {
|
|
151
|
+
colExpr := pt.col(ax.column)
|
|
152
|
+
colExpr = applyPreProcessSteps(colExpr, ax.preProcess)
|
|
153
|
+
colExpr = applyNaRegex(colExpr, ax.naRegex, ax.spec.type)
|
|
154
|
+
projection = append(projection, colExpr.alias(ax.column))
|
|
155
|
+
}
|
|
156
|
+
for col in spec.columns {
|
|
157
|
+
colExpr := pt.col(col.column)
|
|
158
|
+
colExpr = applyPreProcessSteps(colExpr, col.preProcess)
|
|
159
|
+
colExpr = applyNaRegex(colExpr, col.naRegex, col.spec.valueType)
|
|
160
|
+
projection = append(projection, colExpr.alias(col.column))
|
|
161
|
+
}
|
|
162
|
+
df = df.withColumns(projection...)
|
|
163
|
+
|
|
164
|
+
notNullConditions := []
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
for col in spec.columns {
|
|
168
|
+
if col.allowNA == false {
|
|
169
|
+
|
|
170
|
+
notNullConditions = append(notNullConditions, pt.col(col.column).isNotNull())
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if len(notNullConditions) > 0 {
|
|
174
|
+
df = df.filter(pt.and(notNullConditions...))
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
saveParams := {
|
|
178
|
+
axes: [],
|
|
179
|
+
columns: [],
|
|
180
|
+
partitionKeyLength: 0
|
|
181
|
+
}
|
|
182
|
+
if !is_undefined(spec.partitionKeyLength) {
|
|
183
|
+
saveParams.partitionKeyLength = spec.partitionKeyLength
|
|
184
|
+
}
|
|
185
|
+
for ax in spec.axes {
|
|
186
|
+
saveParams.axes = append(saveParams.axes, {
|
|
187
|
+
column: ax.column,
|
|
188
|
+
spec: maps.deepMerge({ name: ax.column }, ax.spec)
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
for col in spec.columns {
|
|
192
|
+
saveParams.columns = append(saveParams.columns, {
|
|
193
|
+
column: col.column,
|
|
194
|
+
spec: maps.deepMerge({ name: col.column }, col.spec)
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
frameName := "xsv_import_output"
|
|
199
|
+
df.saveFrameDirect(frameName, saveParams)
|
|
200
|
+
pf := wf.run().getFrameDirect(frameName)
|
|
201
|
+
|
|
202
|
+
if ops.dataOnly {
|
|
203
|
+
pfd := smart.mapBuilder()
|
|
204
|
+
for col in spec.columns {
|
|
205
|
+
id := util.xsvColumnId(col)
|
|
206
|
+
field := pf.getFutureInputField(col.column + ".data")
|
|
207
|
+
pfd.createInputField(id).set(field)
|
|
208
|
+
}
|
|
209
|
+
return pfd.lockAndBuild()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
result := {}
|
|
213
|
+
axesSpec := slices.map(spec.axes, func(ax) { return ax.spec })
|
|
214
|
+
for col in spec.columns {
|
|
215
|
+
colSpec := getColumnSpec(axesSpec, col)
|
|
216
|
+
data := pf.getFutureInputField(col.column + ".data")
|
|
217
|
+
|
|
218
|
+
id := util.xsvColumnId(col)
|
|
219
|
+
if ops.splitDataAndSpec {
|
|
220
|
+
result[id] = {
|
|
221
|
+
spec: colSpec,
|
|
222
|
+
data: data
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
result[id + ".spec"] = colSpec
|
|
226
|
+
result[id + ".data"] = data
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return result
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export ll.toStrict({
|
|
233
|
+
importFileParquet: importFileParquet
|
|
234
|
+
})
|
|
@@ -10,15 +10,10 @@ render := import("@platforma-sdk/workflow-tengo:render")
|
|
|
10
10
|
maps := import("@platforma-sdk/workflow-tengo:maps")
|
|
11
11
|
util := import("@platforma-sdk/workflow-tengo:pframes.util")
|
|
12
12
|
pBuilder := import("@platforma-sdk/workflow-tengo:pframes.builder")
|
|
13
|
-
pframesSpec := import("@platforma-sdk/workflow-tengo:pframes.spec")
|
|
14
13
|
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
15
14
|
assets := import("@platforma-sdk/workflow-tengo:assets")
|
|
16
15
|
xsvIF := import("@platforma-sdk/workflow-tengo:pframes.xsv-import-file")
|
|
17
16
|
text := import("text")
|
|
18
|
-
execConstants := import("@platforma-sdk/workflow-tengo:exec.constants")
|
|
19
|
-
pt := import("@platforma-sdk/workflow-tengo:pt")
|
|
20
|
-
slices := import("@platforma-sdk/workflow-tengo:slices")
|
|
21
|
-
canonical := import("@platforma-sdk/workflow-tengo:canonical")
|
|
22
17
|
|
|
23
18
|
importXsvIfNullTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.xsv-import-if-not-null")
|
|
24
19
|
|
|
@@ -304,84 +299,16 @@ exportFrame := func(pf, xsvType, params, ...ops) {
|
|
|
304
299
|
ll.panic("Unexpected p-frame format: %s", pf)
|
|
305
300
|
}
|
|
306
301
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
302
|
+
exportPfTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.xsv-export-pframe")
|
|
303
|
+
r := render.create(exportPfTpl, {
|
|
304
|
+
pf: pf,
|
|
305
|
+
xsvType: xsvType,
|
|
306
|
+
params: partialParams
|
|
307
|
+
}, {
|
|
308
|
+
metaInputs: objects.deleteUndefined(runMetaInputs)
|
|
314
309
|
})
|
|
315
310
|
|
|
316
|
-
|
|
317
|
-
if params.joinType == "Inner" {
|
|
318
|
-
frameInput = pt.p.inner(columnEntries...)
|
|
319
|
-
} else {
|
|
320
|
-
frameInput = pt.p.full(columnEntries...)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
numericSelector := pt.sc.numeric()
|
|
324
|
-
if is_string(params.naStr) {
|
|
325
|
-
numericSelector = numericSelector.fillNull(params.naStr)
|
|
326
|
-
}
|
|
327
|
-
stringSelector := pt.sc.string()
|
|
328
|
-
if is_string(params.nullStr) {
|
|
329
|
-
stringSelector = stringSelector.fillNull(params.nullStr)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
specDistiller := pframesSpec.createSpecDistiller(slices.map(rawColumns, func(c) { return c.spec }))
|
|
333
|
-
canonicalMap := {}
|
|
334
|
-
uniqueAxes := []
|
|
335
|
-
for column in rawColumns {
|
|
336
|
-
for axis in column.spec.axesSpec {
|
|
337
|
-
distilledAxis := specDistiller.distill(axis)
|
|
338
|
-
canonicalizedAxisSpec := canonical.encode(distilledAxis)
|
|
339
|
-
if is_undefined(canonicalMap[canonicalizedAxisSpec]) {
|
|
340
|
-
canonicalMap[canonicalizedAxisSpec] = true
|
|
341
|
-
distilledAxis.label = axis.annotations["pl7.app/label"]
|
|
342
|
-
uniqueAxes = append(uniqueAxes, distilledAxis)
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
columnSelectors := []
|
|
348
|
-
for axis in uniqueAxes {
|
|
349
|
-
label := axis.label
|
|
350
|
-
delete(axis, "label")
|
|
351
|
-
columnSelectors = append(columnSelectors, pt.sc.axis(axis).alias(label))
|
|
352
|
-
}
|
|
353
|
-
for column in rawColumns {
|
|
354
|
-
columnSelectors = append(columnSelectors, pt.col(column.id).alias(column.spec.annotations["pl7.app/label"]))
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
wf := pt.workflow()
|
|
358
|
-
if runMetaInputs.queue == execConstants.LIGHT_QUEUE {
|
|
359
|
-
wf = wf.inLightQueue()
|
|
360
|
-
} else if runMetaInputs.queue == execConstants.MEDIUM_QUEUE {
|
|
361
|
-
wf = wf.inMediumQueue()
|
|
362
|
-
} else if runMetaInputs.queue == execConstants.HEAVY_QUEUE {
|
|
363
|
-
wf = wf.inHeavyQueue()
|
|
364
|
-
} else if runMetaInputs.queue == execConstants.UI_TASKS_QUEUE {
|
|
365
|
-
wf = wf.inUiQueue()
|
|
366
|
-
} else if !is_undefined(runMetaInputs.queue) {
|
|
367
|
-
ll.panic("Unsupported queue: %v", runMetaInputs.queue)
|
|
368
|
-
}
|
|
369
|
-
if !is_undefined(runMetaInputs.cpu) {
|
|
370
|
-
wf = wf.cpu(runMetaInputs.cpu)
|
|
371
|
-
}
|
|
372
|
-
if !is_undefined(runMetaInputs.mem) {
|
|
373
|
-
wf = wf.mem(runMetaInputs.mem)
|
|
374
|
-
}
|
|
375
|
-
if !is_undefined(runMetaInputs.inputCache) {
|
|
376
|
-
wf = wf.cacheInputs(runMetaInputs.inputCache)
|
|
377
|
-
}
|
|
378
|
-
wf.frame(frameInput).
|
|
379
|
-
select(numericSelector, stringSelector).
|
|
380
|
-
select(columnSelectors...).
|
|
381
|
-
save(resultFile)
|
|
382
|
-
|
|
383
|
-
result := wf.run()
|
|
384
|
-
return result.getFile(resultFile)
|
|
311
|
+
return r.output("result")
|
|
385
312
|
}
|
|
386
313
|
|
|
387
314
|
export ll.toStrict({
|
|
@@ -110,9 +110,11 @@ _newWindowExpression = func(expression, aggregation, currentAlias) {
|
|
|
110
110
|
_getExpression: func(ctx) {
|
|
111
111
|
ll.assert(is_map(ctx), "ctx must be a map")
|
|
112
112
|
ll.assert(!is_undefined(expression), "Using this operation as a window expression is not allowed. Use it as a group by expression instead. %v", aggregation)
|
|
113
|
-
ll.assert(!is_undefined(currentAlias), "Alias is not defined for this window expression.")
|
|
114
113
|
|
|
115
114
|
valueExpr := expression(ctx)
|
|
115
|
+
if is_undefined(currentAlias) {
|
|
116
|
+
return valueExpr
|
|
117
|
+
}
|
|
116
118
|
return {type: "alias", value: valueExpr, name: currentAlias}
|
|
117
119
|
},
|
|
118
120
|
|
|
@@ -979,7 +981,11 @@ _newExpression = func(expression) {
|
|
|
979
981
|
|
|
980
982
|
|
|
981
983
|
matchesEcmaRegex: func(ecmaRegex) {
|
|
982
|
-
ll.assert(is_string(ecmaRegex)
|
|
984
|
+
ll.assert(is_string(ecmaRegex), "ecma_regex must be a string.")
|
|
985
|
+
|
|
986
|
+
if len(ecmaRegex) == 0 {
|
|
987
|
+
return self.eq("")
|
|
988
|
+
}
|
|
983
989
|
|
|
984
990
|
return _newExpression(func(ctx) {
|
|
985
991
|
valueExpr := self._getExpression(ctx)
|
|
@@ -1030,6 +1036,83 @@ _newExpression = func(expression) {
|
|
|
1030
1036
|
substitutionsOnly: substitutionsOnly
|
|
1031
1037
|
})
|
|
1032
1038
|
})
|
|
1039
|
+
},
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
replaceEcmaRegex: func(ecmaRegex, replacement) {
|
|
1060
|
+
ll.assert(is_string(ecmaRegex) && len(ecmaRegex) > 0, "ecmaRegex must be a non-empty string.")
|
|
1061
|
+
ll.assert(is_string(replacement), "replacement must be a string.")
|
|
1062
|
+
|
|
1063
|
+
return _newExpression(func(ctx) {
|
|
1064
|
+
valueExpr := self._getExpression(ctx)
|
|
1065
|
+
return {
|
|
1066
|
+
type: "replace_ecma_regex",
|
|
1067
|
+
value: valueExpr,
|
|
1068
|
+
ecmaRegex: ecmaRegex,
|
|
1069
|
+
replacement: replacement
|
|
1070
|
+
}
|
|
1071
|
+
})
|
|
1072
|
+
},
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
extractEcmaRegex: func(ecmaRegex) {
|
|
1106
|
+
ll.assert(is_string(ecmaRegex) && len(ecmaRegex) > 0, "ecmaRegex must be a non-empty string.")
|
|
1107
|
+
|
|
1108
|
+
return _newExpression(func(ctx) {
|
|
1109
|
+
valueExpr := self._getExpression(ctx)
|
|
1110
|
+
return {
|
|
1111
|
+
type: "extract_ecma_regex",
|
|
1112
|
+
value: valueExpr,
|
|
1113
|
+
ecmaRegex: ecmaRegex
|
|
1114
|
+
}
|
|
1115
|
+
})
|
|
1033
1116
|
}
|
|
1034
1117
|
})
|
|
1035
1118
|
return self
|
|
@@ -83,6 +83,8 @@ _isPEntry := func(entry) {
|
|
|
83
83
|
return ll.isMap(entry) && ll.methodExists(entry, "_getColumnsMap") && ll.methodExists(entry, "_getJoinTree");
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
_frameToPEntries := undefined
|
|
87
|
+
|
|
86
88
|
slicedColumnCounter := 0
|
|
87
89
|
|
|
88
90
|
p := ll.toStrict({
|
|
@@ -111,7 +113,7 @@ p := ll.toStrict({
|
|
|
111
113
|
slicedColumn: func(name, columnMap, axisFilters) {
|
|
112
114
|
_validateColumn(name, columnMap)
|
|
113
115
|
util.validateAxisFilters(axisFilters)
|
|
114
|
-
|
|
116
|
+
|
|
115
117
|
slicedColumnCounter += 1
|
|
116
118
|
oldName := "p_sliced_" + slicedColumnCounter
|
|
117
119
|
|
|
@@ -131,31 +133,35 @@ p := ll.toStrict({
|
|
|
131
133
|
|
|
132
134
|
inner: func(...entries) {
|
|
133
135
|
ll.assert(len(entries) > 0, "inner join requires at least one entry")
|
|
134
|
-
|
|
136
|
+
|
|
137
|
+
if len(entries) == 1 && !_isPEntry(entries[0]) {
|
|
138
|
+
entries = _frameToPEntries(entries[0])
|
|
139
|
+
}
|
|
140
|
+
|
|
135
141
|
mergedColMap := {}
|
|
136
142
|
joinTreeEntries := []
|
|
137
|
-
|
|
143
|
+
|
|
138
144
|
for entry in entries {
|
|
139
145
|
ll.assert(_isPEntry(entry), "all entries must be PEntry objects")
|
|
140
|
-
|
|
146
|
+
|
|
141
147
|
entryColMap := entry._getColumnsMap()
|
|
142
148
|
entryJoinTree := entry._getJoinTree()
|
|
143
|
-
|
|
149
|
+
|
|
144
150
|
for colName, colInfo in entryColMap {
|
|
145
151
|
if !is_undefined(mergedColMap[colName]) {
|
|
146
152
|
ll.panic("column name %s is already used, please pick a different name", colName)
|
|
147
153
|
}
|
|
148
154
|
mergedColMap[colName] = colInfo
|
|
149
155
|
}
|
|
150
|
-
|
|
156
|
+
|
|
151
157
|
joinTreeEntries = append(joinTreeEntries, entryJoinTree)
|
|
152
158
|
}
|
|
153
|
-
|
|
159
|
+
|
|
154
160
|
joinTree := {
|
|
155
161
|
type: "inner",
|
|
156
162
|
entries: joinTreeEntries
|
|
157
163
|
}
|
|
158
|
-
|
|
164
|
+
|
|
159
165
|
return _newPEntry(mergedColMap, joinTree)
|
|
160
166
|
},
|
|
161
167
|
|
|
@@ -165,31 +171,35 @@ p := ll.toStrict({
|
|
|
165
171
|
|
|
166
172
|
full: func(...entries) {
|
|
167
173
|
ll.assert(len(entries) > 0, "full join requires at least one entry")
|
|
168
|
-
|
|
174
|
+
|
|
175
|
+
if len(entries) == 1 && !_isPEntry(entries[0]) {
|
|
176
|
+
entries = _frameToPEntries(entries[0])
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
mergedColMap := {}
|
|
170
180
|
joinTreeEntries := []
|
|
171
|
-
|
|
181
|
+
|
|
172
182
|
for entry in entries {
|
|
173
183
|
ll.assert(_isPEntry(entry), "all entries must be PEntry objects")
|
|
174
|
-
|
|
184
|
+
|
|
175
185
|
entryColMap := entry._getColumnsMap()
|
|
176
186
|
entryJoinTree := entry._getJoinTree()
|
|
177
|
-
|
|
187
|
+
|
|
178
188
|
for colName, colInfo in entryColMap {
|
|
179
189
|
if !is_undefined(mergedColMap[colName]) {
|
|
180
190
|
ll.panic("column name %s is already used, please pick a different name", colName)
|
|
181
191
|
}
|
|
182
192
|
mergedColMap[colName] = colInfo
|
|
183
193
|
}
|
|
184
|
-
|
|
194
|
+
|
|
185
195
|
joinTreeEntries = append(joinTreeEntries, entryJoinTree)
|
|
186
196
|
}
|
|
187
|
-
|
|
197
|
+
|
|
188
198
|
joinTree := {
|
|
189
199
|
type: "full",
|
|
190
200
|
entries: joinTreeEntries
|
|
191
201
|
}
|
|
192
|
-
|
|
202
|
+
|
|
193
203
|
return _newPEntry(mergedColMap, joinTree)
|
|
194
204
|
},
|
|
195
205
|
|
|
@@ -201,44 +211,75 @@ p := ll.toStrict({
|
|
|
201
211
|
outer: func(primary, ...secondary) {
|
|
202
212
|
ll.assert(_isPEntry(primary), "primary entry must be a PEntry object")
|
|
203
213
|
ll.assert(len(secondary) > 0, "outer join requires at least one secondary entry")
|
|
204
|
-
|
|
214
|
+
|
|
205
215
|
mergedColMap := {}
|
|
206
|
-
|
|
216
|
+
|
|
207
217
|
primaryColMap := primary._getColumnsMap()
|
|
208
218
|
primaryJoinTree := primary._getJoinTree()
|
|
209
|
-
|
|
219
|
+
|
|
210
220
|
for colName, colInfo in primaryColMap {
|
|
211
221
|
mergedColMap[colName] = colInfo
|
|
212
222
|
}
|
|
213
|
-
|
|
223
|
+
|
|
214
224
|
secondaryJoinTrees := []
|
|
215
|
-
|
|
225
|
+
|
|
216
226
|
for entry in secondary {
|
|
217
227
|
ll.assert(_isPEntry(entry), "all secondary entries must be PEntry objects")
|
|
218
|
-
|
|
228
|
+
|
|
219
229
|
entryColMap := entry._getColumnsMap()
|
|
220
230
|
entryJoinTree := entry._getJoinTree()
|
|
221
|
-
|
|
231
|
+
|
|
222
232
|
for colName, colInfo in entryColMap {
|
|
223
233
|
if !is_undefined(mergedColMap[colName]) {
|
|
224
234
|
ll.panic("column name %s is already used, please pick a different name", colName)
|
|
225
235
|
}
|
|
226
236
|
mergedColMap[colName] = colInfo
|
|
227
237
|
}
|
|
228
|
-
|
|
238
|
+
|
|
229
239
|
secondaryJoinTrees = append(secondaryJoinTrees, entryJoinTree)
|
|
230
240
|
}
|
|
231
|
-
|
|
241
|
+
|
|
232
242
|
joinTree := {
|
|
233
243
|
type: "outer",
|
|
234
244
|
primary: primaryJoinTree,
|
|
235
245
|
secondary: secondaryJoinTrees
|
|
236
246
|
}
|
|
237
|
-
|
|
247
|
+
|
|
238
248
|
return _newPEntry(mergedColMap, joinTree)
|
|
239
249
|
}
|
|
240
250
|
})
|
|
241
251
|
|
|
252
|
+
_frameToPEntries = func(frameInput) {
|
|
253
|
+
frameResource := undefined
|
|
254
|
+
if pframesUtil.isFlatPfMap(frameInput) {
|
|
255
|
+
frameResource = frameInput
|
|
256
|
+
} else if pframesUtil.isStructuredPfMap(frameInput) {
|
|
257
|
+
pfBuilder := pframesBuilder.pFrameBuilder()
|
|
258
|
+
for key, value in frameInput {
|
|
259
|
+
pfBuilder.add(key, value.spec, value.data)
|
|
260
|
+
}
|
|
261
|
+
frameResource = pfBuilder.build()
|
|
262
|
+
} else if smart.isReference(frameInput) {
|
|
263
|
+
if smart.isField(frameInput) {
|
|
264
|
+
ll.assert(frameInput.isSet(), "frameInput must be set")
|
|
265
|
+
frameResource = frameInput.getValue()
|
|
266
|
+
} else {
|
|
267
|
+
frameResource = frameInput
|
|
268
|
+
}
|
|
269
|
+
ll.assert(frameResource.checkResourceType(pframesConstants.RTYPE_P_FRAME), "frameResource must be a PFrame resource")
|
|
270
|
+
} else {
|
|
271
|
+
ll.panic("unsupported frameInput type: %v", frameInput)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
columnsMap := pframesUtil.pFrameToColumnsMap(frameResource)
|
|
275
|
+
columnEntries := []
|
|
276
|
+
maps.forEach(columnsMap, func(frameUniqueColumnId, columnInfo) {
|
|
277
|
+
columnEntry := p.column(frameUniqueColumnId, columnInfo)
|
|
278
|
+
columnEntries = append(columnEntries, columnEntry)
|
|
279
|
+
})
|
|
280
|
+
return columnEntries
|
|
281
|
+
}
|
|
282
|
+
|
|
242
283
|
|
|
243
284
|
_detectFormatFromFileName := func(fileName) {
|
|
244
285
|
if text.has_suffix(fileName, ".csv") {
|
|
@@ -360,11 +401,12 @@ workflow := func() {
|
|
|
360
401
|
|
|
361
402
|
|
|
362
403
|
|
|
404
|
+
|
|
363
405
|
|
|
364
406
|
|
|
365
407
|
frame: func(frameInput, ...optionsRaw) {
|
|
366
408
|
ll.assert(!is_undefined(frameInput), "frameInput must be provided")
|
|
367
|
-
|
|
409
|
+
|
|
368
410
|
opts := {}
|
|
369
411
|
if len(optionsRaw) > 0 {
|
|
370
412
|
if len(optionsRaw) == 1 && is_map(optionsRaw[0]) {
|
|
@@ -374,7 +416,6 @@ workflow := func() {
|
|
|
374
416
|
}
|
|
375
417
|
}
|
|
376
418
|
|
|
377
|
-
frameResource := undefined
|
|
378
419
|
fileRef := undefined
|
|
379
420
|
fileContent := undefined
|
|
380
421
|
inputSchema := undefined
|
|
@@ -386,6 +427,7 @@ workflow := func() {
|
|
|
386
427
|
optionsSchema := undefined
|
|
387
428
|
nRowsOpt := undefined
|
|
388
429
|
ignoreErrorsOpt := undefined
|
|
430
|
+
commentPrefixOpt := undefined
|
|
389
431
|
|
|
390
432
|
if is_map(frameInput) && !is_undefined(frameInput.file) {
|
|
391
433
|
fileRef = frameInput.file
|
|
@@ -400,28 +442,9 @@ workflow := func() {
|
|
|
400
442
|
|
|
401
443
|
finalFormat = inputXsvType
|
|
402
444
|
} else if smart.isReference(frameInput) {
|
|
403
|
-
|
|
404
|
-
if smart.isField(frameInputResource) {
|
|
405
|
-
frameInputResource = frameInputResource.getValue()
|
|
406
|
-
}
|
|
407
|
-
if frameInputResource.checkResourceType(pframesConstants.RTYPE_P_FRAME) {
|
|
408
|
-
frameResource = frameInputResource
|
|
409
|
-
finalFormat = "pframe"
|
|
410
|
-
} else {
|
|
411
|
-
fileRef = frameInput
|
|
412
|
-
}
|
|
445
|
+
fileRef = frameInput
|
|
413
446
|
} else if is_string(frameInput) || is_bytes(frameInput) {
|
|
414
447
|
fileContent = frameInput
|
|
415
|
-
} else if pframesUtil.isFlatPfMap(frameInput) {
|
|
416
|
-
frameResource = frameInput
|
|
417
|
-
finalFormat = "pframe"
|
|
418
|
-
} else if pframesUtil.isStructuredPfMap(frameInput) {
|
|
419
|
-
pfBuilder := pframesBuilder.pFrameBuilder()
|
|
420
|
-
for key, value in frameInput {
|
|
421
|
-
pfBuilder.add(key, value.spec, value.data)
|
|
422
|
-
}
|
|
423
|
-
frameResource = pfBuilder.build()
|
|
424
|
-
finalFormat = "pframe"
|
|
425
448
|
} else if _isPEntry(frameInput) {
|
|
426
449
|
finalFormat = "pentry"
|
|
427
450
|
} else {
|
|
@@ -498,6 +521,13 @@ workflow := func() {
|
|
|
498
521
|
ignoreErrorsOpt = opts.ignoreErrors
|
|
499
522
|
}
|
|
500
523
|
|
|
524
|
+
if !is_undefined(opts.commentPrefix) {
|
|
525
|
+
if !is_string(opts.commentPrefix) {
|
|
526
|
+
ll.panic("'commentPrefix' option must be a string. Got: %T", opts.commentPrefix)
|
|
527
|
+
}
|
|
528
|
+
commentPrefixOpt = opts.commentPrefix
|
|
529
|
+
}
|
|
530
|
+
|
|
501
531
|
if !is_undefined(fileRef) {
|
|
502
532
|
ll.assert(
|
|
503
533
|
smart.isReference(fileRef),
|
|
@@ -511,17 +541,7 @@ workflow := func() {
|
|
|
511
541
|
|
|
512
542
|
|
|
513
543
|
step := undefined
|
|
514
|
-
if finalFormat == "pentry"
|
|
515
|
-
if finalFormat == "pframe" {
|
|
516
|
-
columnsMap := pframesUtil.pFrameToColumnsMap(frameResource)
|
|
517
|
-
columnEntries := []
|
|
518
|
-
for frameUniqueColumnId, columnInfo in columnsMap {
|
|
519
|
-
columnEntry := p.column(frameUniqueColumnId, columnInfo)
|
|
520
|
-
columnEntries = append(columnEntries, columnEntry)
|
|
521
|
-
}
|
|
522
|
-
frameInput = p.full(columnEntries...)
|
|
523
|
-
}
|
|
524
|
-
|
|
544
|
+
if finalFormat == "pentry" {
|
|
525
545
|
columnsMap := frameInput._getColumnsMap()
|
|
526
546
|
src := frameInput._getJoinTree()
|
|
527
547
|
|
|
@@ -577,13 +597,17 @@ workflow := func() {
|
|
|
577
597
|
name: finalDataFrameId
|
|
578
598
|
}
|
|
579
599
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
600
|
+
if finalFormat == "csv" {
|
|
601
|
+
step.delimiter = ","
|
|
602
|
+
} else if finalFormat == "tsv" {
|
|
603
|
+
step.delimiter = "\t"
|
|
585
604
|
}
|
|
586
605
|
|
|
606
|
+
if !is_undefined(commentPrefixOpt) {
|
|
607
|
+
step.commentPrefix = commentPrefixOpt
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
587
611
|
|
|
588
612
|
finalSchemaToUse := undefined
|
|
589
613
|
if !is_undefined(optionsSchema) {
|
|
@@ -705,16 +729,17 @@ workflow := func() {
|
|
|
705
729
|
for _, frame in inFrames {
|
|
706
730
|
for _, columnInfo in frame.columns {
|
|
707
731
|
for axis in columnInfo.spec.axesSpec {
|
|
708
|
-
|
|
709
|
-
|
|
732
|
+
distilledAxis := specDistiller.distill(axis)
|
|
733
|
+
if is_undefined(canonicalMap[distilledAxis.name]) {
|
|
734
|
+
canonicalMap[distilledAxis.name] = {}
|
|
710
735
|
}
|
|
711
|
-
canonicalizedAxisSpec := canonical.encode(
|
|
712
|
-
if is_undefined(canonicalMap[
|
|
713
|
-
canonicalMap[
|
|
714
|
-
if is_undefined(distilledAxesSpecs[
|
|
715
|
-
distilledAxesSpecs[
|
|
736
|
+
canonicalizedAxisSpec := canonical.encode(distilledAxis)
|
|
737
|
+
if is_undefined(canonicalMap[distilledAxis.name][canonicalizedAxisSpec]) {
|
|
738
|
+
canonicalMap[distilledAxis.name][canonicalizedAxisSpec] = true
|
|
739
|
+
if is_undefined(distilledAxesSpecs[distilledAxis.name]) {
|
|
740
|
+
distilledAxesSpecs[distilledAxis.name] = []
|
|
716
741
|
}
|
|
717
|
-
distilledAxesSpecs[
|
|
742
|
+
distilledAxesSpecs[distilledAxis.name] = append(distilledAxesSpecs[distilledAxis.name], distilledAxis)
|
|
718
743
|
}
|
|
719
744
|
}
|
|
720
745
|
}
|
|
@@ -830,7 +855,7 @@ workflow := func() {
|
|
|
830
855
|
ll.panic("inFile must have either file or content, got: %v", inFile)
|
|
831
856
|
}
|
|
832
857
|
}
|
|
833
|
-
|
|
858
|
+
|
|
834
859
|
outFrames := {}
|
|
835
860
|
for frameName, specsById in outFramesSpecs {
|
|
836
861
|
columnIds := []
|
|
@@ -947,7 +972,7 @@ _newDataFrameGroupBy = func(parentWorkflow, dfName, groupByExpressions) {
|
|
|
947
972
|
}
|
|
948
973
|
return aggExpr._getAggregation(ctx)
|
|
949
974
|
})
|
|
950
|
-
|
|
975
|
+
|
|
951
976
|
return {
|
|
952
977
|
type: "aggregate",
|
|
953
978
|
inputTable: dfName,
|
|
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
|
|
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
|
|
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": "5.3.
|
|
3
|
+
"version": "5.3.7",
|
|
4
4
|
"description": "Tengo SDK library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@milaboratories/software-pframes-conv": "2.2.9",
|
|
20
20
|
"@platforma-open/milaboratories.software-small-binaries": "^1.15.23",
|
|
21
|
-
"@platforma-open/milaboratories.software-ptabler": "1.12.
|
|
21
|
+
"@platforma-open/milaboratories.software-ptabler": "1.12.8",
|
|
22
22
|
"@platforma-open/milaboratories.software-ptexter": "1.1.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|