@platforma-sdk/workflow-tengo 4.1.0 → 4.1.2

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 (31) hide show
  1. package/dist/tengo/lib/exec.lib.tengo +38 -4
  2. package/dist/tengo/lib/exec.monetization_internal.lib.tengo +1 -4
  3. package/dist/tengo/lib/pframes.bundle.lib.tengo +106 -24
  4. package/dist/tengo/lib/pframes.constants.lib.tengo +7 -0
  5. package/dist/tengo/lib/pframes.lib.tengo +53 -15
  6. package/dist/tengo/lib/pframes.ll.lib.tengo +6 -0
  7. package/dist/tengo/lib/pframes.spec.lib.tengo +9 -2
  8. package/dist/tengo/lib/workflow.bquery.lib.tengo +19 -2
  9. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  10. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  11. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  12. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  13. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  14. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  15. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  16. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  17. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  18. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  19. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  20. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  21. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  22. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  23. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  24. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  25. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  26. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  27. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  28. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  29. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  30. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  31. package/package.json +1 -1
@@ -91,6 +91,9 @@ builder := func() {
91
91
  stderrToValue := false
92
92
  stderrToStdout := false
93
93
 
94
+ saveStdout := true
95
+ saveStderr := true
96
+
94
97
  self = ll.toStrict({
95
98
 
96
99
 
@@ -668,16 +671,45 @@ builder := func() {
668
671
 
669
672
 
670
673
 
674
+ dontSaveStdout: func() {
675
+ saveStdout = false
676
+ return self
677
+ },
678
+
679
+
680
+
681
+
682
+ dontSaveStderr: func() {
683
+ saveStderr = false
684
+ return self
685
+ },
686
+
687
+
688
+
689
+
690
+ dontSaveStdoutOrStderr: func() {
691
+ saveStdout = false
692
+ saveStderr = false
693
+ return self
694
+ },
695
+
696
+
697
+
698
+
671
699
 
672
700
 
673
701
  run: func() {
674
702
  if stderrToStdout {
675
703
  stderr = stdout
676
704
  }
677
- sets.add(filesToStream, stdout)
678
- sets.add(filesToStream, stderr)
679
- sets.add(filesToSave, stdout)
680
- sets.add(filesToSave, stderr)
705
+ if saveStdout {
706
+ sets.add(filesToStream, stdout)
707
+ sets.add(filesToSave, stdout)
708
+ }
709
+ if saveStderr {
710
+ sets.add(filesToStream, stderr)
711
+ sets.add(filesToSave, stderr)
712
+ }
681
713
  if stdoutToValue {
682
714
  sets.add(filesContentToSave, stdout)
683
715
  }
@@ -702,6 +734,8 @@ builder := func() {
702
734
  envs: envs,
703
735
  secrets: secrets,
704
736
  queue: queue,
737
+
738
+
705
739
  stdout: stdout,
706
740
  stderr: stderr,
707
741
  nErrorLines: nErrorLines
@@ -33,10 +33,7 @@ mnzClientStdoutSchema := ["or",
33
33
  "result,?": {
34
34
  productKey: "string",
35
35
  canRun: "boolean",
36
- mnz: {
37
- type: "string",
38
- details: "any"
39
- }
36
+ mnz: "any"
40
37
  }
41
38
  }
42
39
  }]
@@ -48,6 +48,12 @@ strings := import("@platforma-sdk/workflow-tengo:strings")
48
48
 
49
49
 
50
50
 
51
+
52
+
53
+
54
+
55
+
56
+
51
57
 
52
58
 
53
59
 
@@ -65,6 +71,59 @@ createBuilder := func(ctx) {
65
71
 
66
72
  queries := {}
67
73
 
74
+ anchoredQueryOpts := {
75
+ ignoreMissingDomains: true
76
+ }
77
+
78
+ addSingleInner := func(id, ...queryKey) {
79
+ ll.assert(len(queryKey) <= 1, "addSingle accepts at most one optional queryKey argument")
80
+
81
+ decodedId := undefined
82
+ if is_string(id) {
83
+ decodedId = json.decode(id)
84
+ } else if is_map(id) {
85
+ decodedId = id
86
+ } else {
87
+ ll.panic("Invalid column ID type. Expected string or object.")
88
+ }
89
+
90
+ isFiltered := is_map(decodedId) && !is_undefined(decodedId.source) && !is_undefined(decodedId.axisFilters)
91
+ if isFiltered && len(queryKey) > 0 {
92
+ ll.panic("FilteredPColumnId cannot be used with a queryKey.")
93
+ }
94
+
95
+ defaultKey := undefined
96
+ valueToStore := undefined
97
+ if isFiltered {
98
+ defaultKey = canonical.encode(decodedId.source)
99
+ valueToStore = decodedId.source
100
+ } else {
101
+
102
+ defaultKey = is_string(id) ? id : canonical.encode(decodedId)
103
+ valueToStore = decodedId // Store the decoded map itself
104
+ }
105
+
106
+ keyToUse := defaultKey
107
+ if len(queryKey) == 1 {
108
+ keyToUse = queryKey[0]
109
+ }
110
+
111
+ queries[keyToUse] = valueToStore
112
+ }
113
+
114
+ addMultiInner := func(query, ...queryKey) {
115
+ ll.assert(len(queryKey) <= 1, "addMulti accepts at most one optional queryKey argument")
116
+
117
+ keyToUse := undefined
118
+ if len(queryKey) == 1 {
119
+ keyToUse = queryKey[0]
120
+ } else {
121
+ keyToUse = canonical.encode(query)
122
+ }
123
+
124
+ queries[keyToUse] = query
125
+ }
126
+
68
127
  self := undefined
69
128
  self = {
70
129
 
@@ -72,6 +131,16 @@ createBuilder := func(ctx) {
72
131
 
73
132
 
74
133
 
134
+ ignoreMissingDomains: func() {
135
+ anchoredQueryOpts.ignoreMissingDomains = true
136
+ return self
137
+ },
138
+
139
+
140
+
141
+
142
+
143
+
75
144
  addRef: func(ref) {
76
145
  refKey := canonical.encode(ref)
77
146
 
@@ -79,6 +148,8 @@ createBuilder := func(ctx) {
79
148
  if !is_string(refs[refKey]) {
80
149
  refs[refKey] = ref
81
150
  }
151
+
152
+ return self
82
153
  },
83
154
 
84
155
 
@@ -95,6 +166,8 @@ createBuilder := func(ctx) {
95
166
  } else {
96
167
  refs[refKey] = ref
97
168
  }
169
+
170
+ return self
98
171
  },
99
172
 
100
173
 
@@ -104,29 +177,34 @@ createBuilder := func(ctx) {
104
177
 
105
178
 
106
179
 
180
+
181
+
182
+ addSingle: func(id, ...queryKey) {
183
+ addSingleInner(id, queryKey...)
184
+ return self
185
+ },
186
+
187
+
188
+
189
+
190
+
191
+
192
+
107
193
  addById: func(id) {
108
- encodedId := undefined
109
- decodedId := undefined
110
-
111
- if is_string(id) {
112
- decodedId = json.decode(id)
113
- encodedId = id
114
- } else if is_map(id) {
115
- decodedId = id
116
- } else {
117
- ll.panic("Invalid column ID type. Expected string or object.")
118
- }
194
+ addSingleInner(id)
195
+ return self
196
+ },
119
197
 
120
- if is_map(decodedId) && !is_undefined(decodedId.source) && !is_undefined(decodedId.axisFilters) {
121
198
 
122
- columnKey := canonical.encode(decodedId.source)
123
- queries[columnKey] = decodedId.source
124
- } else {
125
- if is_undefined(encodedId) {
126
- encodedId = canonical.encode(decodedId)
127
- }
128
- queries[encodedId] = decodedId
129
- }
199
+
200
+
201
+
202
+
203
+
204
+
205
+ addMulti: func(query, ...queryKey) {
206
+ addMultiInner(query, queryKey...)
207
+ return self
130
208
  },
131
209
 
132
210
 
@@ -135,8 +213,10 @@ createBuilder := func(ctx) {
135
213
 
136
214
 
137
215
 
138
- addQuery: func(queryId, query) {
139
- queries[queryId] = query
216
+
217
+ addQuery: func(queryKey, query) {
218
+ addMultiInner(query, queryKey)
219
+ return self
140
220
  },
141
221
 
142
222
 
@@ -145,6 +225,8 @@ createBuilder := func(ctx) {
145
225
 
146
226
 
147
227
  build: func() {
228
+
229
+
148
230
  resolveResult := bquery.anchoredQuery(ctx, anchors, queries)
149
231
 
150
232
  bundle := smart.mapBuilder(pConstants.RTYPE_P_COLUMN_BUNDLE)
@@ -157,8 +239,8 @@ createBuilder := func(ctx) {
157
239
  }
158
240
  }
159
241
 
160
- for queryId, query in queries {
161
- bundle.addRef(queryId, resolveResult.getResult(queryId))
242
+ for queryKey, query in queries {
243
+ bundle.addRef(queryKey, resolveResult.getResult(queryKey))
162
244
  }
163
245
 
164
246
  return bundle.build()
@@ -29,6 +29,12 @@ AGGREGATION_AXES_SPEC_FIELD_NAME := "__aggregation_axes_spec__"
29
29
 
30
30
  AGGREGATION_AXES_NAMES_FIELD_NAME := "__aggregation_axes_names__"
31
31
 
32
+
33
+
34
+
35
+
36
+ DISTILLED_AGGREGATION_SPEC_FIELD_NAME := "__distilled_aggregation_spec__"
37
+
32
38
  RTYPE_P_FRAME := { Name: "PFrame", Version: "1" }
33
39
 
34
40
  P_COLUMN_DATA_TYPE_PREFIX := "PColumnData/"
@@ -53,6 +59,7 @@ export ll.toStrict({
53
59
  VALUE_FIELD_NAME : VALUE_FIELD_NAME,
54
60
  AGGREGATION_AXES_SPEC_FIELD_NAME : AGGREGATION_AXES_SPEC_FIELD_NAME,
55
61
  AGGREGATION_AXES_NAMES_FIELD_NAME : AGGREGATION_AXES_NAMES_FIELD_NAME,
62
+ DISTILLED_AGGREGATION_SPEC_FIELD_NAME : DISTILLED_AGGREGATION_SPEC_FIELD_NAME,
56
63
  P_COLUMN_DATA_TYPE_PREFIX : P_COLUMN_DATA_TYPE_PREFIX,
57
64
  P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX : P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX,
58
65
 
@@ -38,6 +38,22 @@ pColumnResourceMapDataBuilder := func(keyLength) {
38
38
  ll.panic("pframes.pColumnResourceMapDataBuilder is not supported any more; use pcolumn.resourceMapBuilder")
39
39
  }
40
40
 
41
+ __primitiveValueTypes := { "Int": true, "Long": true, "Float": true, "Double": true, "String": true, "Bytes": true }
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
41
57
 
42
58
 
43
59
 
@@ -194,12 +210,16 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
194
210
  opts.passAggregationAxesNames = false
195
211
  }
196
212
 
213
+ if is_undefined(opts.passDistilledAggregationSpec) {
214
+ opts.passDistilledAggregationSpec = false
215
+ }
216
+
197
217
  if is_undefined(opts.isEphemeral) {
198
218
  opts.isEphemeral = false
199
219
  }
200
220
 
201
- if (opts.passAggregationAxesSpec || opts.passAggregationAxesNames) && is_undefined(opts.aggregate) {
202
- ll.panic("can't use passAggregationAxesSpec or passAggregationAxesNames without aggregate")
221
+ if (opts.passAggregationAxesSpec || opts.passAggregationAxesNames || opts.passDistilledAggregationSpec) && is_undefined(opts.aggregate) {
222
+ ll.panic("can't use passAggregationAxesSpec, passAggregationAxesNames or passDistilledAggregationSpec without aggregate")
203
223
  }
204
224
 
205
225
 
@@ -214,13 +234,22 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
214
234
  passKey: opts.passKey
215
235
  }
216
236
 
237
+
238
+
239
+ isPotentiallyPartitioned := __primitiveValueTypes[input.spec.valueType]
240
+
217
241
  extra := opts.extra
218
242
  if is_undefined(extra) {
219
243
  extra = {}
220
244
  }
221
245
 
222
246
  iterationAxesSpec := input.spec.axesSpec
223
- processTemplateParams.expectedKeyLength = len(input.spec.axesSpec)
247
+
248
+
249
+ if !isPotentiallyPartitioned {
250
+ processTemplateParams.expectedKeyLength = len(input.spec.axesSpec)
251
+ }
252
+
224
253
  if !is_undefined(opts.aggregate) {
225
254
  aggregationIndices := pSpec.matchAxes(input.spec.axesSpec, opts.aggregate)
226
255
  processTemplateParams.aggregationIndices = aggregationIndices
@@ -249,6 +278,23 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
249
278
 
250
279
  extra[constants.AGGREGATION_AXES_NAMES_FIELD_NAME] = smart.createJsonResource(aggregationAxesNames)
251
280
  }
281
+
282
+ if opts.passDistilledAggregationSpec {
283
+ distiller := pSpec.createSpecDistiller([input.spec])
284
+ distilledSpec := distiller.distill(input.spec)
285
+
286
+ passSpec := maps.deepTransform(distilledSpec, {
287
+ axesSpec: func(axesSpec) {
288
+ aggregationAxesSpec := []
289
+ for i in aggregationIndices {
290
+ aggregationAxesSpec = append(aggregationAxesSpec, axesSpec[i])
291
+ }
292
+ return aggregationAxesSpec
293
+ }
294
+ })
295
+
296
+ extra[constants.DISTILLED_AGGREGATION_SPEC_FIELD_NAME] = smart.createJsonResource(passSpec)
297
+ }
252
298
  }
253
299
 
254
300
  processedOutputs := []
@@ -457,7 +503,7 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
457
503
  sep = separator[0]
458
504
  }
459
505
 
460
- for name, output in outputsMap {
506
+ maps.forEach(outputsMap, func(name, output) {
461
507
  if output.type == "Xsv" {
462
508
 
463
509
  for columnName, spec in outputSpecs[name] {
@@ -475,7 +521,7 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
475
521
  renderResult.output(name)
476
522
  )
477
523
  }
478
- }
524
+ })
479
525
 
480
526
  return builder
481
527
  },
@@ -498,11 +544,7 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
498
544
 
499
545
 
500
546
  listOutputs: func() {
501
- outputs := []
502
- for name, _ in outputsMap {
503
- outputs = append(outputs, name)
504
- }
505
- return slices.quickSort(outputs)
547
+ return maps.getKeys(outputsMap)
506
548
  },
507
549
 
508
550
 
@@ -534,11 +576,7 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
534
576
  ll.panic("output is not Xsv: " + name)
535
577
  }
536
578
 
537
- columns := []
538
- for columnName, _ in outputSpecs[name] {
539
- columns = append(columns, columnName)
540
- }
541
- return slices.quickSort(columns)
579
+ return maps.getKeys(outputSpecs[name])
542
580
  },
543
581
 
544
582
 
@@ -55,6 +55,12 @@ llProcessTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.pro
55
55
 
56
56
 
57
57
 
58
+
59
+
60
+
61
+
62
+
63
+
58
64
 
59
65
 
60
66
 
@@ -101,7 +101,9 @@ _P_MATCHER_SCHEMA := {
101
101
  }
102
102
 
103
103
  _normalizeMatcher := func(matcher) {
104
- if is_string(matcher) {
104
+ if is_int(matcher) {
105
+ return matcher
106
+ } else if is_string(matcher) {
105
107
  return { name: matcher }
106
108
  } else {
107
109
  validation.assertType(matcher, _P_MATCHER_SCHEMA)
@@ -136,7 +138,11 @@ matchAxis := func(axesSpec, matcher) {
136
138
  matcher = _normalizeMatcher(matcher)
137
139
  found := -1
138
140
  for idx, axisSpec in axesSpec {
139
- if !_checkAxisMatch(axisSpec, matcher) {
141
+ if is_int(matcher) {
142
+ if idx != matcher {
143
+ continue
144
+ }
145
+ } else if !_checkAxisMatch(axisSpec, matcher) {
140
146
  continue
141
147
  }
142
148
  if found != -1 {
@@ -175,6 +181,7 @@ matchAxis := func(axesSpec, matcher) {
175
181
 
176
182
 
177
183
 
184
+
178
185
 
179
186
 
180
187
  matchAxes := func(axesSpec, matchers, ...opts) {
@@ -276,6 +276,13 @@ resolve := func(ref, ctx, ...options) {
276
276
  }
277
277
 
278
278
 
279
+ _ANCHORED_QUERY_DEFAULT_OPTIONS := {
280
+
281
+ ignoreMissingDomains: false
282
+ }
283
+
284
+
285
+
279
286
 
280
287
 
281
288
 
@@ -297,11 +304,18 @@ resolve := func(ref, ctx, ...options) {
297
304
 
298
305
 
299
306
 
300
- anchoredQuery := func(ctx, anchors, queryMap) {
307
+ anchoredQuery := func(ctx, anchors, queryMap, ...opts) {
301
308
 
302
309
  validation.assertType(queryMap, _QUERY_MAP_SCHEMA, "invalid query map schema")
303
310
 
304
311
 
312
+ normalizedOpts := _ANCHORED_QUERY_DEFAULT_OPTIONS
313
+ if len(opts) > 0 {
314
+ ll.assert(len(opts) == 1 && is_map(opts[0]), "expected single map for opts, got: ", opts)
315
+ normalizedOpts = maps.deepMerge(normalizedOpts, opts[0])
316
+ }
317
+
318
+
305
319
  resolvedAnchors := {}
306
320
  for anchorId, anchorValue in anchors {
307
321
  opts := { spec: true, data: true }
@@ -340,7 +354,10 @@ anchoredQuery := func(ctx, anchors, queryMap) {
340
354
  queryResult := render.createEphemeral(queryAnchoredTpl, {
341
355
  ctx: ctx,
342
356
  anchorSpecs: smart.createMapResource(maps.mapValues(resolvedAnchors, func(v) { return v.inputs().spec })),
343
- queryMap: processedQueryMap
357
+ request: {
358
+ queryMap: processedQueryMap,
359
+ opts: normalizedOpts
360
+ }
344
361
  })
345
362
 
346
363
 
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": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "Tengo SDK library",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",