@platforma-sdk/workflow-tengo 4.6.1 → 4.6.3

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 (35) hide show
  1. package/dist/tengo/lib/pframes.constants.lib.tengo +2 -2
  2. package/dist/tengo/lib/pframes.data.lib.tengo +629 -0
  3. package/dist/tengo/lib/pframes.lib.tengo +2 -0
  4. package/dist/tengo/lib/smart.lib.tengo +4 -1
  5. package/dist/tengo/lib/tpl.base.lib.tengo +2 -2
  6. package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
  7. package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
  8. package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
  9. package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
  10. package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
  11. package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
  12. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  13. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  14. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  15. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  16. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  17. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  18. package/dist/tengo/tpl/exec.python.venv-bin-path.plj.gz +0 -0
  19. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  20. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  21. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  22. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  23. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  24. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  25. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  26. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  27. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  28. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  29. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  30. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  31. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  32. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  33. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  34. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  35. package/package.json +2 -2
@@ -57,8 +57,8 @@ export ll.toStrict({
57
57
  KIND_P_COLUMN : KIND_P_COLUMN,
58
58
  KEY_FIELD_NAME : KEY_FIELD_NAME,
59
59
  VALUE_FIELD_NAME : VALUE_FIELD_NAME,
60
- AGGREGATION_AXES_SPEC_FIELD_NAME : AGGREGATION_AXES_SPEC_FIELD_NAME,
61
- AGGREGATION_AXES_NAMES_FIELD_NAME : AGGREGATION_AXES_NAMES_FIELD_NAME,
60
+ AGGREGATION_AXES_SPEC_FIELD_NAME : AGGREGATION_AXES_SPEC_FIELD_NAME,
61
+ AGGREGATION_AXES_NAMES_FIELD_NAME : AGGREGATION_AXES_NAMES_FIELD_NAME,
62
62
  DISTILLED_AGGREGATION_SPEC_FIELD_NAME : DISTILLED_AGGREGATION_SPEC_FIELD_NAME,
63
63
  P_COLUMN_DATA_TYPE_PREFIX : P_COLUMN_DATA_TYPE_PREFIX,
64
64
  P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX : P_COLUMN_SUPER_PARTITIONED_DATA_TYPE_PREFIX,
@@ -0,0 +1,629 @@
1
+ ll := import("@platforma-sdk/workflow-tengo:ll")
2
+ smart := import("@platforma-sdk/workflow-tengo:smart")
3
+ json := import("json")
4
+ text := import("text")
5
+
6
+ slices := import("@platforma-sdk/workflow-tengo:slices")
7
+ maps := import("@platforma-sdk/workflow-tengo:maps")
8
+ pConstants := import("@platforma-sdk/workflow-tengo:pframes.constants")
9
+
10
+ _createPColumnDataInstance := undefined // Forward declaration
11
+
12
+ _createDecodeKeyString := func(expectedLength) {
13
+ return func(keyStr) {
14
+ decoded := json.decode(keyStr)
15
+ if !is_array(decoded) {
16
+ ll.panic("Decoded key '%v' from string '%s' is not an array(expected JSON array string).", decoded, keyStr)
17
+ }
18
+ if len(decoded) != expectedLength {
19
+ ll.panic("Decoded key array '%v' (from string '%s') length %d does not match expected top-layer key length %d.", decoded, keyStr, len(decoded), expectedLength)
20
+ }
21
+ return decoded
22
+ }
23
+ }
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+ parseData := func(inputParam, ...optsRaw) {
38
+ opts := {}
39
+ if len(optsRaw) > 0 {
40
+ if len(optsRaw) == 1 && is_map(optsRaw[0]) {
41
+ opts = optsRaw[0]
42
+ } else {
43
+ ll.panic("parseData opts must be a single map argument. Got: %v", optsRaw)
44
+ }
45
+ }
46
+
47
+ parse := opts.parse != false
48
+ recursive := opts.recursive == true
49
+
50
+ actualResource := undefined
51
+ initialSpec := undefined
52
+
53
+
54
+ isReferenceDirectly := smart.isReference(inputParam)
55
+
56
+ if !isReferenceDirectly && is_map(inputParam) && !is_undefined(inputParam.data) {
57
+ actualResource = inputParam.data
58
+ if !is_undefined(inputParam.spec) {
59
+ initialSpec = inputParam.spec
60
+ }
61
+ } else if isReferenceDirectly {
62
+ actualResource = inputParam
63
+ } else {
64
+ ll.panic(
65
+ "parseData input must be a resource (a map with an .info() method) or a map of the form {data: resource, spec: map}. Got: %v",
66
+ inputParam
67
+ )
68
+ }
69
+
70
+ if parse && !smart.isResource(actualResource) {
71
+ ll.panic("Data must be a valid resource. Got: %v", actualResource)
72
+ }
73
+
74
+ state := {
75
+ resource: actualResource,
76
+ resourceType: actualResource.info().Type,
77
+ parsed: parse,
78
+ keyLength: undefined, // For PColumnData/Json and PColumnData/ResourceMap
79
+ partitionKeyLength: undefined, // For partitioned types (top or only level for this instance)
80
+ superPartitionKeyLength: undefined, // For super-partitioned types
81
+ relevantTopLayerKeyLength: 0, // Calculated after parsing type
82
+ data: {}, // The main data store: map[stringKey] -> value | ResourceRef | PColumnDataInstance
83
+ spec: !is_undefined(opts.spec) ? opts.spec : initialSpec
84
+ }
85
+
86
+ if !parse {
87
+ return _createPColumnDataInstance(state)
88
+ }
89
+
90
+ resourceData := actualResource.getDataAsJson()
91
+ if is_undefined(resourceData) {
92
+ ll.panic("Failed to get JSON data (metadata) from resource of type %s", state.resourceType)
93
+ }
94
+
95
+
96
+ if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON ||
97
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP {
98
+ state.keyLength = resourceData.keyLength
99
+ state.relevantTopLayerKeyLength = state.keyLength
100
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED ||
101
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED ||
102
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED {
103
+ state.partitionKeyLength = resourceData.partitionKeyLength
104
+ state.relevantTopLayerKeyLength = state.partitionKeyLength
105
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED ||
106
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED {
107
+ state.superPartitionKeyLength = resourceData.superPartitionKeyLength
108
+ state.partitionKeyLength = resourceData.partitionKeyLength // This is PKL of *nested* structures
109
+ state.relevantTopLayerKeyLength = state.superPartitionKeyLength
110
+ } else {
111
+ ll.panic("Unsupported PColumn data resource type for initial key length determination: %s", state.resourceType)
112
+ }
113
+
114
+ _decodeKeyString := _createDecodeKeyString(state.relevantTopLayerKeyLength)
115
+
116
+
117
+ if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON {
118
+ state.data = resourceData.data
119
+ for key, _ in state.data { _decodeKeyString(key) }
120
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED ||
121
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP {
122
+ for key, fieldRef in actualResource.inputs() {
123
+ _decodeKeyString(key) // Validate key structure early
124
+ state.data[key] = fieldRef
125
+ }
126
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED {
127
+ tempData := {}
128
+ for key, fieldRef in actualResource.inputs() {
129
+ partKey := undefined
130
+ isIndex := false
131
+ if text.has_suffix(key, ".index") {
132
+ partKey = key[:len(key)-6]
133
+ isIndex = true
134
+ } else if text.has_suffix(key, ".values") {
135
+ partKey = key[:len(key)-7]
136
+ } else {
137
+ ll.warn("Unexpected file in BinaryPartitioned resource: %s", key)
138
+ continue
139
+ }
140
+ _decodeKeyString(partKey) // Validate key structure
141
+ if is_undefined(tempData[partKey]) { tempData[partKey] = {} }
142
+ if isIndex {
143
+ tempData[partKey].index = fieldRef
144
+ } else {
145
+ tempData[partKey].values = fieldRef
146
+ }
147
+ }
148
+ for pk, parts in tempData { // Ensure all parts have both index and values
149
+ if is_undefined(parts.index) || is_undefined(parts.values) {
150
+ ll.panic("Binary partition key %s is incomplete (missing index or values).", pk)
151
+ }
152
+ }
153
+ state.data = tempData
154
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED ||
155
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED ||
156
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED {
157
+ nestedOpts := { parse: recursive } // if not recursive, the nested resource will not be parsed
158
+ if !is_undefined(state.spec) {
159
+ nestedOpts.spec = maps.deepTransform(state.spec, {
160
+ axesSpec: func(axesSpec) {
161
+ return axesSpec[state.superPartitionKeyLength:]
162
+ }
163
+ });
164
+ }
165
+ for key, fieldRef in actualResource.inputs() {
166
+ _decodeKeyString(key)
167
+ state.data[key] = parseData(recursive ? fieldRef.getValue() : fieldRef, nestedOpts)
168
+ }
169
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP {
170
+ for key, fieldRef in actualResource.inputs() {
171
+ _decodeKeyString(key)
172
+ state.data[key] = fieldRef
173
+ }
174
+ } else {
175
+ ll.panic("Unsupported resource type for parseData data population: %s", state.resourceType)
176
+ }
177
+
178
+ return _createPColumnDataInstance(state)
179
+ }
180
+
181
+ _createPColumnDataInstance = func(state) {
182
+ _decodeKeyString := state.parsed ? _createDecodeKeyString(state.relevantTopLayerKeyLength) : undefined
183
+
184
+ self := undefined
185
+
186
+ self = ll.toStrict({
187
+ resource: state.resource,
188
+
189
+ parsed: state.parsed,
190
+
191
+ getSpec: func() {
192
+ return state.spec
193
+ },
194
+
195
+ getResourceType: func() {
196
+ return state.resourceType
197
+ },
198
+
199
+ keyLength: state.keyLength,
200
+ partitionKeyLength: state.partitionKeyLength,
201
+ superPartitionKeyLength: state.superPartitionKeyLength,
202
+
203
+ data: state.data,
204
+
205
+ parseKey: _createDecodeKeyString,
206
+
207
+ uniqueKeyValues: func(axisIdx) {
208
+ if !state.parsed {
209
+ ll.panic("uniqueKeyValues: resource is not parsed.")
210
+ }
211
+ ll.assert(is_int(axisIdx) && axisIdx >= 0, "axisIdx must be a non-negative integer.")
212
+ ll.assert(axisIdx < state.relevantTopLayerKeyLength, "axisIdx %d is out of bounds for the top-layer key structure (length %d).", axisIdx, state.relevantTopLayerKeyLength)
213
+
214
+ uniqueValsMap := {}
215
+ for keyStr, _ in state.data {
216
+ keyArray := _decodeKeyString(keyStr)
217
+ val := keyArray[axisIdx]
218
+ uniqueValsMap[string(val)] = val
219
+ }
220
+ return maps.values(uniqueValsMap)
221
+ },
222
+
223
+ createDataResource: func() {
224
+ if !is_undefined(state.resource) {
225
+
226
+ return state.resource
227
+ }
228
+
229
+ if !state.parsed {
230
+ ll.panic("createDataResource: resource is not parsed and no original resource is set.")
231
+ }
232
+
233
+ builder := undefined
234
+ if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON {
235
+ builder = smart.structBuilder(state.resourceType, json.encode({ keyLength: state.keyLength, data: state.data }))
236
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED ||
237
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED {
238
+ builder = smart.structBuilder(state.resourceType, json.encode({ partitionKeyLength: state.partitionKeyLength }))
239
+ for key, resourceRef in state.data {
240
+ builder.createInputField(key).set(resourceRef)
241
+ }
242
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED {
243
+ builder = smart.structBuilder(state.resourceType, json.encode({ partitionKeyLength: state.partitionKeyLength }))
244
+ for key, binaryParts in state.data {
245
+ builder.createInputField(key + ".index").set(binaryParts.index)
246
+ builder.createInputField(key + ".values").set(binaryParts.values)
247
+ }
248
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED ||
249
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED ||
250
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED {
251
+ builder = smart.structBuilder(state.resourceType, json.encode({
252
+ superPartitionKeyLength: state.superPartitionKeyLength,
253
+ partitionKeyLength: state.partitionKeyLength
254
+ }))
255
+ for key, item in state.data {
256
+ builder.createInputField(key).set(item.createDataResource())
257
+ }
258
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP {
259
+ builder = smart.structBuilder(state.resourceType, json.encode({ keyLength: state.keyLength }))
260
+ for key, resRef in state.data {
261
+ builder.createInputField(key).set(resRef)
262
+ }
263
+ } else {
264
+ ll.panic("Unsupported resource type for createDataResource: %s", state.resourceType)
265
+ }
266
+
267
+ return builder.lockAndBuild()
268
+ },
269
+
270
+ filter: func(slicingParams) {
271
+ if len(slicingParams) == 0 {
272
+ return self
273
+ }
274
+
275
+ if !state.parsed {
276
+ ll.panic("filter: resource is not parsed.")
277
+ }
278
+
279
+ slicingParams = maps.clone(slicingParams)
280
+ slices.quickSortInPlaceFn(slicingParams, func(a, b) {
281
+ return a[0] < b[0]
282
+ })
283
+
284
+ _validateSlicingParamFormat := func(sp) {
285
+ if !is_array(sp) || len(sp) != 2 { ll.panic("Invalid slicing param: %v", sp) }
286
+ if !is_int(sp[0]) || sp[0] < 0 { ll.panic("Invalid axisIdx: %v", sp[0]) }
287
+ }
288
+
289
+ fixedAxesGlobal := {}
290
+ for param in slicingParams {
291
+ _validateSlicingParamFormat(param) // Corrected variable name from p to param
292
+ if fixedAxesGlobal[param[0]] { ll.panic("Duplicate axisIdx %d", param[0]) }
293
+ if param[0] >= state.relevantTopLayerKeyLength {
294
+ ll.panic("Slicing axis %d out of bounds for RTLKL %d", param[0], state.relevantTopLayerKeyLength)
295
+ }
296
+ fixedAxesGlobal[param[0]] = true
297
+ }
298
+
299
+ _matchesFilter := func(keyArray) {
300
+ for param in slicingParams {
301
+ axisIdx := param[0]
302
+ value := param[1]
303
+ if keyArray[axisIdx] != value {
304
+ return false
305
+ }
306
+ }
307
+ return true
308
+ }
309
+
310
+ _transformKey := func(keyArray) {
311
+ newKeyArray := []
312
+ for i, value in keyArray { if !fixedAxesGlobal[i] { newKeyArray = append(newKeyArray, value) } }
313
+ return newKeyArray
314
+ }
315
+
316
+ newSpec := undefined
317
+
318
+ if !is_undefined(state.spec) {
319
+ newSpec = maps.deepTransform(state.spec, {
320
+ axesSpec: func(axesSpec) {
321
+ updatedAxesSpec := []
322
+ for i, axisSpecEntry in axesSpec { if !fixedAxesGlobal[i] { updatedAxesSpec = append(updatedAxesSpec, axisSpecEntry) } }
323
+ return updatedAxesSpec
324
+ }
325
+ })
326
+ }
327
+
328
+ if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED ||
329
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED ||
330
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED {
331
+
332
+ newData := {}
333
+ for superKeyStr, item in state.data {
334
+ superKeyArray := _decodeKeyString(superKeyStr)
335
+ if _matchesFilter(superKeyArray) {
336
+ newSuperKeyArray := _transformKey(superKeyArray)
337
+ newData[string(json.encode(newSuperKeyArray))] = item // Nested item taken as is
338
+ }
339
+ }
340
+
341
+ newSuperPartitionKeyLength := state.superPartitionKeyLength - len(slicingParams)
342
+
343
+ if newSuperPartitionKeyLength < 0 {
344
+ ll.panic("Internal filter error: newSuperPartitionKeyLength is negative.")
345
+ }
346
+
347
+ if newSuperPartitionKeyLength == 0 {
348
+
349
+
350
+ if len(newData) > 1 {
351
+ ll.panic("Filter error: too many items (%d) after reducing super-partition key length to 0. Expected 0 or 1.", len(newData))
352
+ }
353
+
354
+ newInstanceOpts := {
355
+ parsed: true,
356
+ spec: newSpec
357
+ }
358
+
359
+ if len(newData) == 0 {
360
+
361
+ newInstanceOpts.data = {}
362
+
363
+ if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED {
364
+ partitionKeyLength := state.partitionKeyLength
365
+ newInstanceOpts.resourceType = pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED
366
+ newInstanceOpts.partitionKeyLength = partitionKeyLength
367
+ newInstanceOpts.relevantTopLayerKeyLength = partitionKeyLength
368
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED {
369
+ partitionKeyLength := state.partitionKeyLength
370
+ newInstanceOpts.resourceType = pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED
371
+ newInstanceOpts.partitionKeyLength = partitionKeyLength
372
+ newInstanceOpts.relevantTopLayerKeyLength = partitionKeyLength
373
+ } else { // RTYPE_P_COLUMN_DATA_RESOURCE_MAP_PARTITIONED (PColumnData/Partitioned/ResourceMap)
374
+ keyLength := state.keyLength
375
+ newInstanceOpts.resourceType = pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP
376
+ newInstanceOpts.keyLength = keyLength
377
+ newInstanceOpts.relevantTopLayerKeyLength = keyLength
378
+ }
379
+
380
+ return _createPColumnDataInstance(newInstanceOpts)
381
+ } else { // len(newData) == 1
382
+ singleNestedItem := newData["[]"] // This is a PColumnData instance
383
+ if is_undefined(singleNestedItem) || is_undefined(singleNestedItem.getResourceType()) {
384
+ ll.panic("Filter error: expected a PColumnData instance for key '[]' when unwrapping, got %v", singleNestedItem)
385
+ }
386
+ return singleNestedItem
387
+ }
388
+ } else { // newSuperPartitionKeyLength > 0, still super-partitioned
389
+ return _createPColumnDataInstance({
390
+ parsed: true,
391
+ resourceType: state.resourceType,
392
+ superPartitionKeyLength: newSuperPartitionKeyLength,
393
+ partitionKeyLength: state.partitionKeyLength, // This is PKL of nested structures or KL of nested ResourceMap. It doesn't change by slicing super keys.
394
+ relevantTopLayerKeyLength: newSuperPartitionKeyLength,
395
+ data: newData,
396
+ spec: newSpec,
397
+ isRecursive: state.isRecursive,
398
+ originalResource: undefined
399
+ })
400
+ }
401
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED ||
402
+ state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED {
403
+ newData := {}
404
+ for keyStr, item in state.data {
405
+ keyArray := _decodeKeyString(keyStr)
406
+ if _matchesFilter(keyArray) {
407
+ newKeyArray := _transformKey(keyArray)
408
+ newData[string(json.encode(newKeyArray))] = item
409
+ }
410
+ }
411
+ newPartitionKeyLength := state.partitionKeyLength - len(slicingParams)
412
+ return _createPColumnDataInstance({
413
+ parsed: true,
414
+ resourceType: state.resourceType,
415
+ partitionKeyLength: newPartitionKeyLength,
416
+ relevantTopLayerKeyLength: newPartitionKeyLength,
417
+ data: newData,
418
+ spec: newSpec,
419
+ isRecursive: state.isRecursive
420
+ })
421
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP {
422
+ newData := {}
423
+ for keyStr, item in state.data {
424
+ keyArray := _decodeKeyString(keyStr)
425
+ if _matchesFilter(keyArray) {
426
+ newKeyArray := _transformKey(keyArray)
427
+ newData[string(json.encode(newKeyArray))] = item
428
+ }
429
+ }
430
+ newKeyLength := state.keyLength - len(slicingParams)
431
+ return _createPColumnDataInstance({
432
+ parsed: true,
433
+ resourceType: state.resourceType,
434
+ keyLength: newKeyLength,
435
+ relevantTopLayerKeyLength: newKeyLength,
436
+ data: newData,
437
+ spec: newSpec,
438
+ isRecursive: state.isRecursive
439
+ })
440
+ } else if state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON {
441
+ newData := {}
442
+ for keyStr, val in state.data {
443
+ keyArray := _decodeKeyString(keyStr)
444
+ if _matchesFilter(keyArray) {
445
+ newKeyArray := _transformKey(keyArray)
446
+ newData[string(json.encode(newKeyArray))] = val
447
+ }
448
+ }
449
+ newKeyLength := state.keyLength - len(slicingParams)
450
+ return _createPColumnDataInstance({
451
+ parsed: true,
452
+ resourceType: state.resourceType,
453
+ keyLength: newKeyLength,
454
+ relevantTopLayerKeyLength: newKeyLength,
455
+ data: newData,
456
+ spec: newSpec,
457
+ isRecursive: state.isRecursive,
458
+ originalResource: undefined
459
+ })
460
+ } else {
461
+ ll.panic("Filtering not supported for type %s", state.resourceType)
462
+ }
463
+ },
464
+
465
+ partition: func(...axesToPartitionBy) {
466
+ if !state.parsed {
467
+ ll.panic("partition: resource is not parsed.")
468
+ }
469
+ if len(axesToPartitionBy) == 0 {
470
+ ll.panic("partition: at least one axis index must be provided.")
471
+ }
472
+
473
+
474
+ seenAxesValidation := {}
475
+ for _, axisIdx in axesToPartitionBy {
476
+ if !is_int(axisIdx) || axisIdx < 0 {
477
+ ll.panic("partition: axis index '%v' must be a non-negative integer.", axisIdx)
478
+ }
479
+ if axisIdx >= state.relevantTopLayerKeyLength {
480
+ ll.panic("partition: axis index %d is out of bounds for the top-layer key structure (length %d). Current type: %s", axisIdx, state.relevantTopLayerKeyLength, state.resourceType)
481
+ }
482
+ if seenAxesValidation[axisIdx] {
483
+ ll.panic("partition: duplicate axis index %d provided.", axisIdx)
484
+ }
485
+ seenAxesValidation[axisIdx] = true
486
+ }
487
+
488
+ resultPartitions := {}
489
+
490
+ for keyStr, _ in state.data {
491
+ keyArray := _decodeKeyString(keyStr)
492
+
493
+ currentPartitionTuple := []
494
+ for _, axisIdx in axesToPartitionBy {
495
+ currentPartitionTuple = append(currentPartitionTuple, keyArray[axisIdx])
496
+ }
497
+ partitionMapKeyStr := string(json.encode(currentPartitionTuple))
498
+
499
+ if is_undefined(resultPartitions[partitionMapKeyStr]) {
500
+ slicingParamsForThisPartition := []
501
+ for i, axisIdx in axesToPartitionBy {
502
+ slicingParamsForThisPartition = append(slicingParamsForThisPartition, [axisIdx, currentPartitionTuple[i]])
503
+ }
504
+ resultPartitions[partitionMapKeyStr] = self.filter(slicingParamsForThisPartition)
505
+ }
506
+ }
507
+ return resultPartitions
508
+ },
509
+
510
+ forEach: func(userCallback) {
511
+ if !state.parsed {
512
+ ll.panic("forEach: resource is not parsed.")
513
+ }
514
+ if !is_callable(userCallback) {
515
+ ll.panic("forEach: provided argument is not a function.")
516
+ }
517
+
518
+ maps.forEach(state.data, func(keyStr, value) {
519
+ decodedKey := _decodeKeyString(keyStr)
520
+ userCallback(decodedKey, value)
521
+ })
522
+ },
523
+
524
+ flatten: func() {
525
+ if !state.parsed {
526
+ ll.panic("flatten: resource is not parsed.")
527
+ }
528
+
529
+ isJsonSuper := state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED
530
+ isBinarySuper := state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED
531
+ isResourceMapSuper := state.resourceType == pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP_SUPER_PARTITIONED
532
+
533
+ if !(isJsonSuper || isBinarySuper || isResourceMapSuper) {
534
+ return self // Not a type that can be flattened
535
+ }
536
+
537
+ finalResourceType := undefined
538
+ usePartitionKeyLengthForFinal := false
539
+ if isJsonSuper {
540
+ finalResourceType = pConstants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED
541
+ usePartitionKeyLengthForFinal = true
542
+ } else if isBinarySuper {
543
+ finalResourceType = pConstants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED
544
+ usePartitionKeyLengthForFinal = true
545
+ } else { // isResourceMapSuper
546
+ finalResourceType = pConstants.RTYPE_P_COLUMN_DATA_RESOURCE_MAP
547
+
548
+ }
549
+
550
+ newCombinedKeyLength := -1
551
+ if usePartitionKeyLengthForFinal {
552
+ if is_undefined(state.superPartitionKeyLength) || is_undefined(state.partitionKeyLength) {
553
+ ll.panic(
554
+ "Flatten setup error: superPartitionKeyLength (%v) or partitionKeyLength (%v) is undefined for super-type %s. These are needed to determine combined key length.",
555
+ state.superPartitionKeyLength, state.partitionKeyLength, state.resourceType
556
+ )
557
+ }
558
+ newCombinedKeyLength = state.superPartitionKeyLength + state.partitionKeyLength
559
+ } else {
560
+ if is_undefined(state.partitionKeyLength) || is_undefined(state.keyLength) {
561
+ ll.panic(
562
+ "Flatten setup error: partitionKeyLength (%v) or keyLength (%v) is undefined for super-type %s. These are needed to determine combined key length.",
563
+ state.partitionKeyLength, state.keyLength, state.resourceType
564
+ )
565
+ }
566
+ newCombinedKeyLength = state.partitionKeyLength + state.keyLength
567
+ }
568
+
569
+ newData := {}
570
+
571
+ self.forEach(func(superKeyArray, nestedPCDInstance) {
572
+ if !nestedPCDInstance.parsed {
573
+ ll.panic("Flatten error: Nested PCD for superKey '%s' (superType %s) is not parsed or missing resourceType.", superKeyArray, state.resourceType)
574
+ }
575
+ if nestedPCDInstance.getResourceType() != finalResourceType {
576
+ ll.panic("Flatten error: For superKey '%s' (superType %s), expected nested type %s, got %s.",
577
+ superKeyArray, state.resourceType, finalResourceType, nestedPCDInstance.getResourceType())
578
+ }
579
+
580
+ if !usePartitionKeyLengthForFinal { // Nested is ResourceMap
581
+ if is_undefined(nestedPCDInstance.keyLength) {
582
+ ll.panic("Flatten error: Nested ResourceMap PCD for superKey '%s' (superType %s) is missing its 'keyLength'.",
583
+ superKeyArray, state.resourceType)
584
+ }
585
+ if nestedPCDInstance.keyLength != state.keyLength {
586
+ ll.panic("Flatten error: Nested ResourceMap PCD for superKey '%s' (superType %s) has keyLength %d, expected %d.",
587
+ superKeyArray, state.resourceType, nestedPCDInstance.keyLength, state.keyLength)
588
+ }
589
+ } else { // Nested is JsonPartitioned or BinaryPartitioned
590
+ if is_undefined(nestedPCDInstance.partitionKeyLength) {
591
+ ll.panic("Flatten error: Nested Partitioned PCD for superKey '%s' (superType %s) is missing its 'partitionKeyLength'.",
592
+ superKeyArray, state.resourceType)
593
+ }
594
+ if nestedPCDInstance.partitionKeyLength != state.partitionKeyLength {
595
+ ll.panic("Flatten error: Nested Partitioned PCD for superKey '%s' (superType %s) has partitionKeyLength %d, expected %d.",
596
+ superKeyArray, state.resourceType, nestedPCDInstance.partitionKeyLength, state.partitionKeyLength)
597
+ }
598
+ }
599
+
600
+ nestedPCDInstance.forEach(func(nestedKeyArray, valueOrParts) {
601
+ combinedKeyArray := superKeyArray + nestedKeyArray
602
+ newData[string(json.encode(combinedKeyArray))] = valueOrParts
603
+ })
604
+ })
605
+
606
+ newInstanceOpts := {
607
+ parsed: true,
608
+ resourceType: finalResourceType,
609
+ relevantTopLayerKeyLength: newCombinedKeyLength,
610
+ data: newData,
611
+ spec: state.spec // User's comment update incorporated
612
+ }
613
+
614
+ if usePartitionKeyLengthForFinal {
615
+ newInstanceOpts.partitionKeyLength = newCombinedKeyLength
616
+ } else { // For ResourceMap, the length field is 'keyLength'
617
+ newInstanceOpts.keyLength = newCombinedKeyLength
618
+ }
619
+
620
+ return _createPColumnDataInstance(newInstanceOpts)
621
+ }
622
+ })
623
+
624
+ return self
625
+ }
626
+
627
+ export ll.toStrict({
628
+ parseData: parseData
629
+ })
@@ -14,6 +14,7 @@ pSpec := import("@platforma-sdk/workflow-tengo:pframes.spec")
14
14
  validation := import("@platforma-sdk/workflow-tengo:validation")
15
15
  constants := import("@platforma-sdk/workflow-tengo:pframes.constants")
16
16
  xsvBuilder := import("@platforma-sdk/workflow-tengo:pframes.xsv-builder")
17
+ pColumnData := import("@platforma-sdk/workflow-tengo:pframes.data")
17
18
 
18
19
  llProcessTpl := assets.importTemplate("@platforma-sdk/workflow-tengo:pframes.process-pcolumn-data")
19
20
 
@@ -607,6 +608,7 @@ processColumn := func(input, bodyTpl, outputs, ...opts) {
607
608
  }
608
609
 
609
610
  export ll.toStrict({
611
+ parseData: pColumnData.parseData,
610
612
  processColumn: processColumn,
611
613
  exportFrame: exportFrame,
612
614
  pFrameBuilder: builder.pFrameBuilder,
@@ -366,7 +366,10 @@ resource = func(r) {
366
366
 
367
367
 
368
368
  info: func() {
369
- return tx.getResource(self.id)
369
+ _resourceInfo := tx.getResource(self.id)
370
+
371
+ _resourceInfo.Type = { Name: _resourceInfo.Type.Name, Version: _resourceInfo.Type.Version }
372
+ return _resourceInfo
370
373
  },
371
374
 
372
375
 
@@ -96,11 +96,11 @@ AWAIT_TEMPLATES := {
96
96
  ["spec", "ResourceReady"]
97
97
  ],
98
98
  "PColumnBundle": [
99
- [{ wildcard: "*" }, "ref", "ResourceReady"],
99
+ [{ wildcard: "*" }, { match: "^ref$" }, "ResourceReady"], // optional ref field
100
100
  [{ wildcard: "*" }, "spec", "ResourceReady"]
101
101
  ],
102
102
  "PColumnBundleWithPartitions": [
103
- [{ wildcard: "*" }, "ref", "ResourceReady"],
103
+ [{ wildcard: "*" }, { match: "^ref$" }, "ResourceReady"], // optional ref field
104
104
  [{ wildcard: "*" }, "spec", "ResourceReady"],
105
105
  [{ wildcard: "*" }, "data", "InputsLocked"]
106
106
  ]
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.6.1",
3
+ "version": "4.6.3",
4
4
  "description": "Tengo SDK library",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "@platforma-open/milaboratories.software-ptabler": "1.6.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@platforma-sdk/tengo-builder": "^2.1.5"
24
+ "@platforma-sdk/tengo-builder": "^2.1.6"
25
25
  },
26
26
  "scripts": {
27
27
  "type-check": "pl-tengo check",