@platforma-sdk/workflow-tengo 5.3.3 → 5.3.5

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 (52) hide show
  1. package/dist/index.cjs +2 -2
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +2 -2
  4. package/dist/tengo/lib/exec.lib.tengo +4 -0
  5. package/dist/tengo/lib/exec.monetization_internal.lib.tengo +8 -0
  6. package/dist/tengo/lib/pframes.spec.lib.tengo +6 -0
  7. package/dist/tengo/lib/pframes.util.lib.tengo +404 -1
  8. package/dist/tengo/lib/pframes.xsv.lib.tengo +117 -65
  9. package/dist/tengo/lib/pt.expression.lib.tengo +828 -268
  10. package/dist/tengo/lib/pt.lib.tengo +567 -216
  11. package/dist/tengo/lib/pt.util.lib.tengo +231 -15
  12. package/dist/tengo/lib/slices.lib.tengo +20 -1
  13. package/dist/tengo/lib/smart.lib.tengo +0 -1
  14. package/dist/tengo/tpl/anonymize.deanonymize.plj.gz +0 -0
  15. package/dist/tengo/tpl/anonymize.impl.plj.gz +0 -0
  16. package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
  17. package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
  18. package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
  19. package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
  20. package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
  21. package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
  22. package/dist/tengo/tpl/check_network.workdir_type_name_extractor.plj.gz +0 -0
  23. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  24. package/dist/tengo/tpl/exec.delayed-compute-allocation.impl.plj.gz +0 -0
  25. package/dist/tengo/tpl/exec.exec-impl.plj.gz +0 -0
  26. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  27. package/dist/tengo/tpl/exec.load-software.impl.plj.gz +0 -0
  28. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  29. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  30. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  31. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  32. package/dist/tengo/tpl/exec.python.venv-bin-path.plj.gz +0 -0
  33. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  34. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  35. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  36. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  37. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  38. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  39. package/dist/tengo/tpl/pframes.parse-to-json.plj.gz +0 -0
  40. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  41. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  42. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  43. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  44. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  45. package/dist/tengo/tpl/pt.import-dir.plj.gz +0 -0
  46. package/dist/tengo/tpl/pt.workflow-run.plj.gz +0 -0
  47. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  48. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  49. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  50. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  51. package/package.json +4 -4
  52. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
package/dist/index.cjs CHANGED
@@ -28,11 +28,11 @@ module.exports = { Templates: {
28
28
  'pframes.parse-to-json': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.parse-to-json.plj.gz') },
29
29
  'exec.load-software.impl': { type: 'from-file', path: require.resolve('./tengo/tpl/exec.load-software.impl.plj.gz') },
30
30
  'exec.exec': { type: 'from-file', path: require.resolve('./tengo/tpl/exec.exec.plj.gz') },
31
- 'pframes.xsv-export-pframe': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-export-pframe.plj.gz') },
32
31
  'pframes.xsv-import-if-not-null': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-import-if-not-null.plj.gz') },
33
- 'pframes.xsv-import-map': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-import-map.plj.gz') },
32
+ 'pt.workflow-run': { type: 'from-file', path: require.resolve('./tengo/tpl/pt.workflow-run.plj.gz') },
34
33
  'check_network.run_hello_world': { type: 'from-file', path: require.resolve('./tengo/tpl/check_network.run_hello_world.plj.gz') },
35
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-import-map': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.xsv-import-map.plj.gz') },
36
36
  'pframes.process-pcolumn-data': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.process-pcolumn-data.plj.gz') },
37
37
  'pframes.export-pframe': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.export-pframe.plj.gz') },
38
38
  'pframes.export-pframe-for-ui': { type: 'from-file', path: require.resolve('./tengo/tpl/pframes.export-pframe-for-ui.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" | "pframes.xsv-export-pframe" | "pframes.xsv-import-if-not-null" | "pframes.xsv-import-map" | "check_network.run_hello_world" | "check_network.run_hello_world_py" | "pframes.process-pcolumn-data" | "pframes.export-pframe" | "pframes.export-pframe-for-ui";
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" | "pframes.xsv-import-if-not-null" | "pt.workflow-run" | "check_network.run_hello_world" | "check_network.run_hello_world_py" | "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
@@ -29,11 +29,11 @@ export const Templates = {
29
29
  'pframes.parse-to-json': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.parse-to-json.plj.gz') },
30
30
  'exec.load-software.impl': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/exec.load-software.impl.plj.gz') },
31
31
  'exec.exec': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/exec.exec.plj.gz') },
32
- 'pframes.xsv-export-pframe': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-export-pframe.plj.gz') },
33
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') },
34
- 'pframes.xsv-import-map': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-import-map.plj.gz') },
33
+ 'pt.workflow-run': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pt.workflow-run.plj.gz') },
35
34
  'check_network.run_hello_world': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/check_network.run_hello_world.plj.gz') },
36
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-import-map': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.xsv-import-map.plj.gz') },
37
37
  'pframes.process-pcolumn-data': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.process-pcolumn-data.plj.gz') },
38
38
  'pframes.export-pframe': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.export-pframe.plj.gz') },
39
39
  'pframes.export-pframe-for-ui': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/pframes.export-pframe-for-ui.plj.gz') }
@@ -691,6 +691,8 @@ builder := func() {
691
691
 
692
692
 
693
693
 
694
+
695
+
694
696
  addFile: func(fileName, file, ...opts) {
695
697
  ll.assert(is_string(fileName), "exec.builder().addFile: fileName must be a string")
696
698
  ll.assert(smart.isReference(file), "exec.builder().addFile: file must be a reference")
@@ -721,6 +723,8 @@ builder := func() {
721
723
 
722
724
 
723
725
 
726
+
727
+
724
728
  writeFile: func(fileName, data, ...opts) {
725
729
  validation.assertType(data, ["or",
726
730
  "string",
@@ -142,6 +142,10 @@ _validateArgToLastRun := func(arg) {
142
142
  }
143
143
 
144
144
 
145
+
146
+
147
+
148
+
145
149
  addArgToLastRun := func(mnz, fileName, arg) {
146
150
  validation.assertType(mnz, schema,
147
151
  "monetization.addArgToLastRun(): monetization object does not fit json schema")
@@ -290,6 +294,10 @@ _extractOption := func(...opts) {
290
294
  }
291
295
 
292
296
 
297
+
298
+
299
+
300
+
293
301
  addOptionalArg := func(mnz, fileName, ...opts) {
294
302
  opt := _extractOption(opts...)
295
303
  if !is_undefined(opt) {
@@ -36,6 +36,10 @@ P_COLUMN_SPEC_SCHEMA := ["and", P_UNTYPED_SPEC_SCHEMA, {
36
36
  `axesSpec,?`: [ P_AXIS_SPEC_SCHEMA ]
37
37
  }]
38
38
 
39
+ P_COLUMN_STRICT_SPEC_SCHEMA := ["and", P_COLUMN_SPEC_SCHEMA, {
40
+ `valueType`: `string,regex=Int|Long|Float|Double|String`
41
+ }]
42
+
39
43
  P_OBJECT_SPEC_SCHEMA := ["or", P_COLUMN_SPEC_SCHEMA, {
40
44
  `kind`: `string`,
41
45
  `annotations,?`: { any: `string` }
@@ -308,6 +312,7 @@ makeTrace := func(input, ...steps) {
308
312
 
309
313
 
310
314
  createSpecDistiller := func(specs) {
315
+ ll.assert(is_array(specs), "specs must be an array")
311
316
 
312
317
 
313
318
  domainsValues := {}
@@ -535,6 +540,7 @@ export ll.toStrict({
535
540
  P_AXIS_SPEC_SCHEMA: P_AXIS_SPEC_SCHEMA,
536
541
  P_COLUMN_OWN_SPEC_SCHEMA: P_COLUMN_OWN_SPEC_SCHEMA,
537
542
  P_COLUMN_SPEC_SCHEMA: P_COLUMN_SPEC_SCHEMA,
543
+ P_COLUMN_STRICT_SPEC_SCHEMA: P_COLUMN_STRICT_SPEC_SCHEMA,
538
544
  P_OBJECT_SPEC_SCHEMA: P_OBJECT_SPEC_SCHEMA,
539
545
 
540
546
  KIND_P_COLUMN: KIND_P_COLUMN,
@@ -2,6 +2,14 @@ ll := import("@platforma-sdk/workflow-tengo:ll")
2
2
  validation := import("@platforma-sdk/workflow-tengo:validation")
3
3
  objects := import("@platforma-sdk/workflow-tengo:objects")
4
4
  slices := import("@platforma-sdk/workflow-tengo:slices")
5
+ text := import("text")
6
+ smart := import("@platforma-sdk/workflow-tengo:smart")
7
+ constants := import("@platforma-sdk/workflow-tengo:pframes.constants")
8
+ pSpec := import("@platforma-sdk/workflow-tengo:pframes.spec")
9
+ path := import("@platforma-sdk/workflow-tengo:path")
10
+ json := import("json")
11
+ sets := import("@platforma-sdk/workflow-tengo:sets")
12
+ maps := import("@platforma-sdk/workflow-tengo:maps")
5
13
 
6
14
  _PRE_PROCESS_STEP_SCHEMA := [`or`,
7
15
  {
@@ -397,6 +405,397 @@ calculateGroupAxesIndices := func(numberOfAxes, aggregationIndices) {
397
405
  return groupIndices
398
406
  }
399
407
 
408
+
409
+
410
+
411
+ pFrameToColumnsMap := func(pf) {
412
+ columnsById := {}
413
+
414
+ addColumnSegment := func(key, value) {
415
+ columnId := key[0:(len(key) - 5)]
416
+ if is_undefined(columnsById[columnId]) {
417
+ columnsById[columnId] = {}
418
+ }
419
+
420
+ if text.has_suffix(key, ".spec") {
421
+ if smart.isResource(value) {
422
+ ll.assert(value.isFinal(), "Resource is not final")
423
+ value = value.getDataAsJson()
424
+ }
425
+ columnsById[columnId].spec = value
426
+ } else if text.has_suffix(key, ".data") {
427
+ columnsById[columnId].data = value
428
+ } else {
429
+ ll.panic("unknown suffix: %s", key)
430
+ }
431
+ }
432
+
433
+ if smart.isResource(pf) {
434
+ ll.assert(pf.checkResourceType(constants.RTYPE_P_FRAME), "Unexpected resource type: %v", pf.info().Type)
435
+ ll.assert(pf.info().InputsLocked, "PFrame resource does not have inputs locked")
436
+ for key, field in pf.inputs() {
437
+ addColumnSegment(key, field.getValue())
438
+ }
439
+ } else if ll.isMap(pf) {
440
+ for key, value in pf {
441
+ addColumnSegment(key, value)
442
+ }
443
+ } else {
444
+ ll.panic("unknown pf format: %v", pf)
445
+ }
446
+
447
+ return columnsById
448
+ }
449
+
450
+
451
+
452
+
453
+
454
+
455
+
456
+
457
+
458
+
459
+
460
+
461
+
462
+
463
+ addColumnToWd := func(name, spec, data, execBuilder, ops) {
464
+ ll.assert(is_string(name), "name must be a string, got: %v", name)
465
+
466
+ ll.assert(!is_undefined(spec), "spec must be defined")
467
+ validation.assertType(spec, pSpec.P_COLUMN_SPEC_SCHEMA)
468
+ vt := spec.valueType
469
+ ll.assert(vt == "Int" || vt == "Long" || vt == "Float" || vt == "Double" || vt == "String",
470
+ "Unsupported value type: ", vt, spec)
471
+
472
+ ll.assert(!is_undefined(data) && smart.isResource(data), "data must be a resource, got: %v", data)
473
+
474
+ ll.assert(!is_undefined(execBuilder), "execBuilder must be defined")
475
+ if !is_undefined(ops) {
476
+ ll.assert(is_map(ops), "ops must be a map, got: %v", ops)
477
+ validation.assertType(ops, {
478
+ `__options__,closed`: true,
479
+ `folder,?`: "string"
480
+ })
481
+ }
482
+
483
+ partitions := undefined
484
+ if !is_undefined(ops.partitions) {
485
+ partitions = {}
486
+ for idx, keys in ops.partitions {
487
+ partitions[idx] = sets.fromSlice(keys)
488
+ }
489
+ }
490
+
491
+ makePath := func(fileName) {
492
+ if is_undefined(ops.folder) {
493
+ return fileName
494
+ }
495
+ return path.join(ops.folder, fileName)
496
+ }
497
+
498
+ if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_JSON)) {
499
+
500
+ ll.assert(is_undefined(partitions), "Partitions filter enabled while non-partitioned column exported")
501
+
502
+ jdataFile := "res" + data.id + ".jdata"
503
+
504
+
505
+ execBuilder.writeFile(makePath(jdataFile), json.encode(data.getDataAsJson().data))
506
+
507
+
508
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
509
+ type: "JsonPartitioned",
510
+ partitionKeyLength: 0,
511
+ parts: { "[]": jdataFile }
512
+ }))
513
+
514
+
515
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
516
+
517
+ } else if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_JSON_PARTITIONED)) {
518
+
519
+
520
+ i := 0
521
+ parts := {}
522
+
523
+
524
+ inputs := data.inputs()
525
+ for k in maps.getKeys(inputs) {
526
+ v := inputs[k].getValue()
527
+
528
+ part := "res" + v.id + ".jdata"
529
+
530
+ parts[k] = part
531
+ execBuilder.addFile(makePath(part), v)
532
+ }
533
+
534
+
535
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
536
+ type: "JsonPartitioned",
537
+ partitionKeyLength: data.getDataAsJson().partitionKeyLength,
538
+ parts: parts
539
+ }))
540
+
541
+
542
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
543
+
544
+ } else if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_JSON_SUPER_PARTITIONED)) {
545
+
546
+ superPartitionKeyLength := data.getDataAsJson().superPartitionKeyLength
547
+ partitionKeyLength := data.getDataAsJson().partitionKeyLength
548
+
549
+
550
+ parts := {}
551
+
552
+
553
+ for supKey, supData in data.inputs() {
554
+ supKeyArray := json.decode(supKey)
555
+
556
+
557
+ inputs := supData.getValue().inputs()
558
+ for k in maps.getKeys(inputs) {
559
+ v := inputs[k].getValue()
560
+
561
+ innerKeyArray := json.decode(k)
562
+ keyArray := supKeyArray + innerKeyArray
563
+ key := json.encode(keyArray)
564
+
565
+ part := "res" + v.id + ".jdata"
566
+ parts[key] = part
567
+ execBuilder.addFile(makePath(part), v)
568
+ }
569
+ }
570
+
571
+
572
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
573
+ type: "JsonPartitioned",
574
+ partitionKeyLength: superPartitionKeyLength + partitionKeyLength,
575
+ parts: parts
576
+ }))
577
+
578
+
579
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
580
+
581
+ } else if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_BINARY_PARTITIONED)) {
582
+
583
+
584
+ parts := {}
585
+
586
+
587
+ inputs := data.inputs()
588
+ for k in maps.getKeys(inputs) {
589
+ v := inputs[k].getValue()
590
+
591
+ if text.has_suffix(k, ".index") {
592
+ key := k[0:(len(k) - 6)]
593
+ indexFile := "res" + v.id + ".index"
594
+
595
+ if is_undefined(parts[key]) {
596
+ parts[key] = {}
597
+ }
598
+ parts[key].index = indexFile
599
+ execBuilder.addFile(makePath(indexFile), v)
600
+ } else if text.has_suffix(k, ".values") {
601
+ key := k[0:(len(k) - 7)]
602
+ valuesFile := "res" + v.id + ".values"
603
+
604
+ if is_undefined(parts[key]) {
605
+ parts[key] = {}
606
+ }
607
+ parts[key].values = valuesFile
608
+ execBuilder.addFile(makePath(valuesFile), v)
609
+ } else {
610
+ ll.panic("unknown suffix: expected .index or .values, got ", k)
611
+ }
612
+ }
613
+
614
+
615
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
616
+ type: "BinaryPartitioned",
617
+ partitionKeyLength: data.getDataAsJson().partitionKeyLength,
618
+ parts: parts
619
+ }))
620
+
621
+
622
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
623
+
624
+ } else if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_BINARY_SUPER_PARTITIONED)) {
625
+
626
+ superPartitionKeyLength := data.getDataAsJson().superPartitionKeyLength
627
+ partitionKeyLength := data.getDataAsJson().partitionKeyLength
628
+
629
+
630
+ parts := {}
631
+
632
+
633
+ for supKey, supData in data.inputs() {
634
+ supKeyArray := json.decode(supKey)
635
+
636
+
637
+ inputs := supData.getValue().inputs()
638
+ for k in maps.getKeys(inputs) {
639
+ v := inputs[k].getValue()
640
+
641
+ if text.has_suffix(k, ".index") {
642
+ innerKeyArray := json.decode(k[0:(len(k) - 6)])
643
+ keyArray := supKeyArray + innerKeyArray
644
+
645
+ key := json.encode(keyArray)
646
+ indexFile := "res" + v.id + ".index"
647
+
648
+ if is_undefined(parts[key]) {
649
+ parts[key] = {}
650
+ }
651
+ parts[key].index = indexFile
652
+ execBuilder.addFile(makePath(indexFile), v)
653
+
654
+ } else if text.has_suffix(k, ".values") {
655
+ innerKeyArray := json.decode(k[0:(len(k) - 7)])
656
+ keyArray := supKeyArray + innerKeyArray
657
+
658
+ key := json.encode(keyArray)
659
+ valuesFile := "res" + v.id + ".values"
660
+
661
+ if is_undefined(parts[key]) {
662
+ parts[key] = {}
663
+ }
664
+ parts[key].values = valuesFile
665
+ execBuilder.addFile(makePath(valuesFile), v)
666
+ } else {
667
+ ll.panic("unknown suffix: expected .index or .values, got ", k)
668
+ }
669
+ }
670
+ }
671
+
672
+
673
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
674
+ type: "BinaryPartitioned",
675
+ partitionKeyLength: superPartitionKeyLength + partitionKeyLength,
676
+ parts: parts
677
+ }))
678
+
679
+
680
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
681
+
682
+ } else if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_PARQUET_PARTITIONED)) {
683
+
684
+
685
+ parts := {}
686
+
687
+
688
+ inputs := data.inputs()
689
+ for k in maps.getKeys(inputs) {
690
+ v := inputs[k]
691
+
692
+ parquetChunkResource := v.getValue()
693
+ parquetChunkMetadata := parquetChunkResource.getDataAsJson()
694
+ parquetChunkMapping := parquetChunkResource.metaInputs()["mapping"].getValue().getDataAsJson()
695
+ parquetChunkData := parquetChunkResource.metaInputs()["blob"].getValue()
696
+
697
+ parquetChunkDataPath := "res" + parquetChunkData.id + ".parquet"
698
+ parts[k] = maps.merge({ data: parquetChunkDataPath }, parquetChunkMetadata, parquetChunkMapping)
699
+
700
+ execBuilder.addFile(makePath(parquetChunkDataPath), parquetChunkData)
701
+ }
702
+
703
+
704
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
705
+ type: "ParquetPartitioned",
706
+ partitionKeyLength: data.getDataAsJson().partitionKeyLength,
707
+ parts: parts
708
+ }))
709
+
710
+
711
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
712
+
713
+ } else if (data.checkResourceType(constants.RTYPE_P_COLUMN_DATA_PARQUET_SUPER_PARTITIONED)) {
714
+
715
+ superPartitionKeyLength := data.getDataAsJson().superPartitionKeyLength
716
+ partitionKeyLength := data.getDataAsJson().partitionKeyLength
717
+
718
+
719
+ parts := {}
720
+
721
+
722
+ for supKey, supData in data.inputs() {
723
+ supKeyArray := json.decode(supKey)
724
+
725
+
726
+ inputs := supData.getValue().inputs()
727
+ for k in maps.getKeys(inputs) {
728
+ v := inputs[k]
729
+ innerKeyArray := json.decode(k)
730
+
731
+ keyArray := supKeyArray + innerKeyArray
732
+ key := json.encode(keyArray)
733
+
734
+ parquetChunkResource := v.getValue()
735
+ parquetChunkMetadata := parquetChunkResource.getDataAsJson()
736
+ parquetChunkMapping := parquetChunkResource.metaInputs()["mapping"].getValue().getDataAsJson()
737
+ parquetChunkData := parquetChunkResource.metaInputs()["blob"].getValue()
738
+
739
+ parquetChunkDataPath := "res" + parquetChunkData.id + ".parquet"
740
+ parts[key] = maps.merge({ data: parquetChunkDataPath }, parquetChunkMetadata, parquetChunkMapping)
741
+
742
+ execBuilder.addFile(makePath(parquetChunkDataPath), parquetChunkData)
743
+ }
744
+ }
745
+
746
+
747
+ execBuilder.writeFile(makePath(name + ".datainfo"), json.encode({
748
+ type: "ParquetPartitioned",
749
+ partitionKeyLength: superPartitionKeyLength + partitionKeyLength,
750
+ parts: parts
751
+ }))
752
+
753
+
754
+ execBuilder.writeFile(makePath(name + ".spec"), json.encode(spec))
755
+
756
+ } else {
757
+ ll.panic("unsupported p-column data type", data.info().Type)
758
+ }
759
+ }
760
+
761
+ isFlatPfMap := func(pf) {
762
+ if !is_map(pf) {
763
+ return false
764
+ }
765
+
766
+ for key, _ in pf {
767
+ if !text.has_suffix(key, ".spec") && !text.has_suffix(key, ".data") {
768
+ return false
769
+ }
770
+ }
771
+
772
+ return true
773
+ }
774
+
775
+ isStructuredPfMap := func(pf) {
776
+ if !is_map(pf) {
777
+ return false
778
+ }
779
+
780
+ for _, value in pf {
781
+ if !is_map(value) {
782
+ return false
783
+ }
784
+
785
+ for k, _ in value {
786
+ if k != "spec" && k != "data" {
787
+ return false
788
+ }
789
+ }
790
+
791
+ if is_undefined(value.spec) || is_undefined(value.data) {
792
+ return false
793
+ }
794
+ }
795
+
796
+ return true
797
+ }
798
+
400
799
  export ll.toStrict({
401
800
  PFCONV_IMPORT_CFG_SCHEMA: PFCONV_IMPORT_CFG_SCHEMA,
402
801
  PFCONV_EXPORT_CFG_SCHEMA: PFCONV_EXPORT_CFG_SCHEMA,
@@ -405,5 +804,9 @@ export ll.toStrict({
405
804
  xsvColumnId: xsvColumnId,
406
805
  purifySpec: purifySpec,
407
806
  decomposePfconvImportCfg: decomposePfconvImportCfg,
408
- calculateGroupAxesIndices: calculateGroupAxesIndices
807
+ calculateGroupAxesIndices: calculateGroupAxesIndices,
808
+ pFrameToColumnsMap: pFrameToColumnsMap,
809
+ addColumnToWd: addColumnToWd,
810
+ isFlatPfMap: isFlatPfMap,
811
+ isStructuredPfMap: isStructuredPfMap
409
812
  })