@platforma-sdk/workflow-tengo 4.9.3 → 4.11.0

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 (54) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +2 -0
  3. package/dist/index.mjs +2 -0
  4. package/dist/tengo/lib/anonymize.impl.lib.tengo +177 -0
  5. package/dist/tengo/lib/anonymize.lib.tengo +223 -0
  6. package/dist/tengo/lib/anonymize.util.lib.tengo +56 -0
  7. package/dist/tengo/lib/exec.lib.tengo +80 -1
  8. package/dist/tengo/lib/pframes.lib.tengo +48 -3
  9. package/dist/tengo/lib/pframes.spec.lib.tengo +1 -1
  10. package/dist/tengo/lib/pframes.xsv-builder.lib.tengo +77 -0
  11. package/dist/tengo/lib/pframes.xsv-import-file.lib.tengo +8 -1
  12. package/dist/tengo/lib/pframes.xsv.lib.tengo +8 -1
  13. package/dist/tengo/lib/pt.expression.lib.tengo +48 -19
  14. package/dist/tengo/lib/pt.lib.tengo +27 -1
  15. package/dist/tengo/lib/render.lib.tengo +34 -8
  16. package/dist/tengo/lib/smart.lib.tengo +30 -8
  17. package/dist/tengo/lib/tpl.base.lib.tengo +86 -12
  18. package/dist/tengo/lib/workflow.lib.tengo +1 -0
  19. package/dist/tengo/tpl/anonymize.deanonymize.plj.gz +0 -0
  20. package/dist/tengo/tpl/anonymize.impl.plj.gz +0 -0
  21. package/dist/tengo/tpl/check_network.create_workdir_from_storage.plj.gz +0 -0
  22. package/dist/tengo/tpl/check_network.download_blob.plj.gz +0 -0
  23. package/dist/tengo/tpl/check_network.run_hello_world.plj.gz +0 -0
  24. package/dist/tengo/tpl/check_network.run_hello_world_py.plj.gz +0 -0
  25. package/dist/tengo/tpl/check_network.upload_blob.plj.gz +0 -0
  26. package/dist/tengo/tpl/check_network.upload_template.plj.gz +0 -0
  27. package/dist/tengo/tpl/check_network.workdir_type_name_extractor.plj.gz +0 -0
  28. package/dist/tengo/tpl/exec.R.create-renv.plj.gz +0 -0
  29. package/dist/tengo/tpl/exec.delayed-compute-allocation.impl.plj.gz +0 -0
  30. package/dist/tengo/tpl/exec.exec-impl.plj.gz +0 -0
  31. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  32. package/dist/tengo/tpl/exec.load-software.impl.plj.gz +0 -0
  33. package/dist/tengo/tpl/exec.monetization_info.plj.gz +0 -0
  34. package/dist/tengo/tpl/exec.monetization_to_json.plj.gz +0 -0
  35. package/dist/tengo/tpl/exec.python.create-venv.plj.gz +0 -0
  36. package/dist/tengo/tpl/exec.python.install-deps.plj.gz +0 -0
  37. package/dist/tengo/tpl/exec.python.venv-bin-path.plj.gz +0 -0
  38. package/dist/tengo/tpl/ll.get-field.plj.gz +0 -0
  39. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  40. package/dist/tengo/tpl/pframes.export-pframe-for-ui.plj.gz +0 -0
  41. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  42. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  43. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  44. package/dist/tengo/tpl/pframes.process-pcolumn-data.plj.gz +0 -0
  45. package/dist/tengo/tpl/pframes.remove-nulls.plj.gz +0 -0
  46. package/dist/tengo/tpl/pframes.slice-data.plj.gz +0 -0
  47. package/dist/tengo/tpl/pframes.xsv-export-pframe.plj.gz +0 -0
  48. package/dist/tengo/tpl/pframes.xsv-import-if-not-null.plj.gz +0 -0
  49. package/dist/tengo/tpl/pframes.xsv-import-map.plj.gz +0 -0
  50. package/dist/tengo/tpl/waiter.waiter.plj.gz +0 -0
  51. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  52. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  53. package/dist/tengo/tpl/workflow.query-anchored.plj.gz +0 -0
  54. package/package.json +2 -2
@@ -2,6 +2,7 @@ ll := import("@platforma-sdk/workflow-tengo:ll")
2
2
  maps := import("@platforma-sdk/workflow-tengo:maps")
3
3
  strings := import("@platforma-sdk/workflow-tengo:strings")
4
4
  text := import("text")
5
+ times := import("times")
5
6
  pSpec := import("@platforma-sdk/workflow-tengo:pframes.spec")
6
7
  pBuilder := import("@platforma-sdk/workflow-tengo:pframes.builder")
7
8
  xsv := import("@platforma-sdk/workflow-tengo:pframes.xsv")
@@ -24,6 +25,7 @@ xsvFileBuilder := func(xsvType) {
24
25
  cpu := undefined
25
26
  mem := undefined
26
27
  queue := undefined
28
+ inputCache := undefined
27
29
 
28
30
  getSpecDistiller := func() {
29
31
  if is_undefined(distiller) {
@@ -362,6 +364,75 @@ xsvFileBuilder := func(xsvType) {
362
364
 
363
365
 
364
366
 
367
+ cacheInputs: func(time) {
368
+ ll.assert(
369
+ is_int(time),
370
+ "cache time must be an integer. " +
371
+ "Did you forget to import a standard tengo library 'times'?")
372
+ inputCache = time
373
+ return self
374
+ },
375
+
376
+
377
+
378
+
379
+
380
+
381
+ cacheInputsMillis: func(millis) {
382
+ ll.assert(is_int(millis) && millis > 0, "cache time must be a number of milliseconds")
383
+ inputCache = millis * times.millisecond
384
+ return self
385
+ },
386
+
387
+
388
+
389
+
390
+
391
+
392
+ cacheInputsSeconds: func(seconds) {
393
+ ll.assert(is_int(seconds) && seconds > 0, "cache time must be a number of seconds")
394
+ inputCache = seconds * times.second
395
+ return self
396
+ },
397
+
398
+
399
+
400
+
401
+
402
+
403
+ cacheInputsMinutes: func(minutes) {
404
+ ll.assert(is_int(minutes) && minutes > 0, "cache time must be a number of minutes")
405
+ inputCache = minutes * times.minute
406
+ return self
407
+ },
408
+
409
+
410
+
411
+
412
+
413
+
414
+ cacheInputsHours: func(hours) {
415
+ ll.assert(is_int(hours) && hours > 0, "cache time must be a number of hours")
416
+ inputCache = hours * times.hour
417
+ return self
418
+ },
419
+
420
+
421
+
422
+
423
+
424
+
425
+ cacheInputsDays: func(days) {
426
+ ll.assert(is_int(days) && days > 0, "cache time must be a number of days")
427
+ inputCache = days * times.hour * 24
428
+ return self
429
+ },
430
+
431
+
432
+
433
+
434
+
435
+
365
436
  cpu: func(amount) {
366
437
  cpu = amount
367
438
  return self
@@ -623,6 +694,9 @@ xsvFileBuilder := func(xsvType) {
623
694
  if !is_undefined(queue) {
624
695
  ops.queue = queue
625
696
  }
697
+ if !is_undefined(inputCache) {
698
+ ops.inputCache = inputCache
699
+ }
626
700
 
627
701
  return xsv.exportFrame(pFrame, xsvType, currentExportParams, ops)
628
702
  },
@@ -672,6 +746,9 @@ xsvFileBuilder := func(xsvType) {
672
746
  if !is_undefined(queue) {
673
747
  ops.queue = queue
674
748
  }
749
+ if !is_undefined(inputCache) {
750
+ ops.inputCache = inputCache
751
+ }
675
752
 
676
753
  tableResource := xsv.exportFrame(pFrame, xsvType, finalExportParams, ops)
677
754
 
@@ -79,6 +79,7 @@ getColumnSpec := func(axesSpec, col) {
79
79
 
80
80
 
81
81
 
82
+
82
83
 
83
84
 
84
85
  importFile := func(xsvFile, xsvType, spec, ...ops) {
@@ -96,7 +97,7 @@ importFile := func(xsvFile, xsvType, spec, ...ops) {
96
97
 
97
98
  xsvFileName := "file." + xsvType
98
99
 
99
- ops := renderOps({ dataOnly: false, splitDataAndSpec: false, queue: execConstants.LIGHT_QUEUE }, ops...)
100
+ ops := renderOps({ dataOnly: false, splitDataAndSpec: false, queue: execConstants.LIGHT_QUEUE, inputCache: undefined }, ops...)
100
101
 
101
102
  if ops.transpose != undefined {
102
103
 
@@ -118,6 +119,9 @@ importFile := func(xsvFile, xsvType, spec, ...ops) {
118
119
  if ops.mem != undefined {
119
120
  transposeXsv.mem(ops.mem)
120
121
  }
122
+ if ops.inputCache != undefined && ops.inputCache > 0 {
123
+ transposeXsv.cacheInputs(ops.inputCache)
124
+ }
121
125
 
122
126
  if (tops.separator != undefined) {
123
127
  transposeXsv = transposeXsv.arg("-input-separator").arg(tops.separator)
@@ -181,6 +185,9 @@ importFile := func(xsvFile, xsvType, spec, ...ops) {
181
185
  if ops.mem != undefined {
182
186
  pfconv.mem(ops.mem)
183
187
  }
188
+ if ops.inputCache != undefined && ops.inputCache > 0 {
189
+ pfconv.cacheInputs(ops.inputCache)
190
+ }
184
191
 
185
192
  pfconv = pfconv.run()
186
193
 
@@ -85,6 +85,7 @@ getColumnSpec := func(axesSpec, col) {
85
85
 
86
86
 
87
87
 
88
+
88
89
 
89
90
 
90
91
  importFile := func(xsvFile, xsvType, spec, ...ops) {
@@ -141,6 +142,7 @@ importFile := func(xsvFile, xsvType, spec, ...ops) {
141
142
 
142
143
 
143
144
 
145
+
144
146
 
145
147
 
146
148
  importFileMap := func(xsvMap, xsvType, spec, ...ops) {
@@ -151,7 +153,8 @@ importFileMap := func(xsvMap, xsvType, spec, ...ops) {
151
153
  dataOnly: false,
152
154
  splitDataAndSpec: false,
153
155
  additionalAxesSpec: [],
154
- transpose: undefined
156
+ transpose: undefined,
157
+ inputCache: undefined
155
158
  }, ops...)
156
159
 
157
160
 
@@ -172,6 +175,9 @@ importFileMap := func(xsvMap, xsvType, spec, ...ops) {
172
175
  if !is_undefined(ops.queue) {
173
176
  templateOps.queue = ops.queue
174
177
  }
178
+ if !is_undefined(ops.inputCache) && ops.inputCache > 0 {
179
+ templateOps.inputCache = ops.inputCache
180
+ }
175
181
 
176
182
  r := render.createEphemeral(importXsvMapTpl, {
177
183
  xsvMap: xsvMap,
@@ -282,6 +288,7 @@ isStructuredPfMap := func(pf) {
282
288
 
283
289
 
284
290
 
291
+
285
292
 
286
293
 
287
294
  exportFrame := func(pf, xsvType, params, ...ops) {
@@ -318,32 +318,37 @@ _newExpression = func(expression, currentAlias) {
318
318
 
319
319
 
320
320
 
321
- strSlice: func(start, ...lengthArgs) { // Primary method with optional length via varargs
322
- ll.assert(is_int(start), "start must be an integer")
323
- ll.assert(len(lengthArgs) <= 1, "strSlice expects at most one optional length argument.")
324
-
325
- exprDetails := {type: "substring", value: expression, start: start}
326
- if len(lengthArgs) == 1 {
327
- lengthVal := lengthArgs[0]
328
- ll.assert(is_int(lengthVal), "length, if provided, must be an integer")
329
- exprDetails.length = lengthVal
330
- }
331
-
332
- return _newExpression(exprDetails, undefined)
333
- },
334
-
335
321
 
336
322
 
337
323
 
338
324
 
325
+ strSlice: func(start, ...args) {
326
+ ll.assert(len(args) <= 1, "strSlice expects at most one additional argument.")
339
327
 
328
+ expr := {
329
+ type: "substring",
330
+ value: expression,
331
+ start: _mapToSingleExpressionStruct(start, "col")
332
+ }
340
333
 
341
- strSliceEnd: func(start, endIdx) { // Method with end index
342
- ll.assert(is_int(start), "start must be an integer")
343
- ll.assert(is_int(endIdx), "endIdx must be an integer")
334
+ if len(args) > 0 {
335
+ arg := args[0]
336
+ if is_map(arg) {
337
+ if arg.length != undefined && arg.end != undefined {
338
+ ll.panic("strSlice cannot have both 'length' and 'end' options.")
339
+ }
340
+ if !is_undefined(arg.length) {
341
+ expr.length = _mapToSingleExpressionStruct(arg.length, "col")
342
+ }
343
+ if !is_undefined(arg.end) {
344
+ expr.end = _mapToSingleExpressionStruct(arg.end, "col")
345
+ }
346
+ } else {
347
+ expr.length = _mapToSingleExpressionStruct(arg, "col")
348
+ }
349
+ }
344
350
 
345
- exprDetails := {type: "substring", value: expression, start: start, end: endIdx}
346
- return _newExpression(exprDetails, undefined)
351
+ return _newExpression(expr, undefined)
347
352
  },
348
353
 
349
354
 
@@ -391,6 +396,23 @@ _newExpression = func(expression, currentAlias) {
391
396
 
392
397
 
393
398
 
399
+ strReplaceAll: func(pattern, replacement, ...options) {
400
+ opts := {}
401
+ if len(options) > 0 {
402
+ opts = options[0]
403
+ }
404
+ opts.replaceAll = true
405
+ return self.strReplace(pattern, replacement, opts)
406
+ },
407
+
408
+
409
+
410
+
411
+
412
+
413
+
414
+
415
+
394
416
  strDistance: func(string2, metric, returnSimilarity) {
395
417
  ll.assert(_isExpression(string2), "string2 must be an expression object")
396
418
  ll.assert(is_string(metric), "metric must be a string")
@@ -571,6 +593,13 @@ _newExpression = func(expression, currentAlias) {
571
593
  partitionBy: [],
572
594
  descending: descendingVal
573
595
  }, undefined, undefined)
596
+ },
597
+
598
+
599
+
600
+
601
+ toString: func() {
602
+ return self.cast("string")
574
603
  }
575
604
  })
576
605
  return self
@@ -6,6 +6,7 @@ exec := import("@platforma-sdk/workflow-tengo:exec")
6
6
  json := import("json")
7
7
  text := import("text")
8
8
  slices := import("@platforma-sdk/workflow-tengo:slices")
9
+ validation := import("@platforma-sdk/workflow-tengo:validation")
9
10
  execConstants := import("@platforma-sdk/workflow-tengo:exec.constants")
10
11
 
11
12
 
@@ -166,6 +167,7 @@ workflow := func() {
166
167
  if smart.isReference(frameInput) {
167
168
  fileRef = frameInput
168
169
  } else {
170
+ validation.assertType(frameInput, ["or", "string", "bytes"])
169
171
  fileContent = frameInput
170
172
  }
171
173
  }
@@ -434,6 +436,29 @@ _newDataFrame = func(parentWorkflow, dfName) {
434
436
  return cols
435
437
  }
436
438
 
439
+ _mapExprsToStepColsAllowingStrings := func(exprs, methodName) {
440
+ ll.assert(len(exprs) > 0, methodName + " requires at least one expression argument.")
441
+ cols := []
442
+ for expr in exprs {
443
+ if is_string(expr) {
444
+
445
+ colExpr := exp.col(expr)
446
+ cols = append(cols, {
447
+ name: colExpr.getAlias(),
448
+ expression: colExpr.getExpression()
449
+ })
450
+ } else if exp._isExpression(expr) {
451
+ cols = append(cols, {
452
+ name: expr.getAlias(),
453
+ expression: expr.getExpression()
454
+ })
455
+ } else {
456
+ ll.panic("Invalid argument to " + methodName + ": Expected an expression object or string column name, got %v", expr)
457
+ }
458
+ }
459
+ return cols
460
+ }
461
+
437
462
  _addSaveStep := func(outputFile, ...options) {
438
463
  opts := {}
439
464
  if len(options) > 0 {
@@ -523,8 +548,9 @@ _newDataFrame = func(parentWorkflow, dfName) {
523
548
 
524
549
 
525
550
 
551
+
526
552
  select: func(...expressions) {
527
- stepCols := _mapExprsToStepCols(expressions, "select")
553
+ stepCols := _mapExprsToStepColsAllowingStrings(expressions, "select")
528
554
  outputDfName := parentWorkflow._newAnonymousDataFrameId()
529
555
  parentWorkflow.addRawStep({
530
556
  type: "select",
@@ -28,8 +28,21 @@ _SUBSCRIPTION_FIELD := "subscription"
28
28
 
29
29
 
30
30
 
31
+
32
+
33
+
31
34
  createUniversal := func(tpl, isEph, inputs, ...opts) {
32
- metaInputs := opts[0]
35
+ ll.assert(len(opts) <= 1, "too many arguments, expected at most one options object")
36
+ metaInputs := undefined
37
+ inputCache := undefined
38
+ if len(opts) == 1 && opts[0] {
39
+ metaInputs = opts[0].metaInputs
40
+ inputCache = opts[0].inputCache
41
+ }
42
+
43
+ if !is_undefined(inputCache) && inputCache > 0 && isEph {
44
+ ll.panic("inputCache option cannot be used with ephemeral templates")
45
+ }
33
46
 
34
47
 
35
48
  rbuilder := undefined
@@ -49,20 +62,30 @@ createUniversal := func(tpl, isEph, inputs, ...opts) {
49
62
 
50
63
 
51
64
  inputsMap := isEph ? smart.ephemeralMapBuilder() : smart.mapBuilder()
52
- for name, value in inputs {
53
- if !is_undefined(value) {
54
- inputsMap.add(name, value)
55
- }
65
+ inputAddOpts := undefined
66
+ if !is_undefined(inputCache) && inputCache > 0 {
67
+ inputAddOpts = { cache: inputCache }
56
68
  }
57
- for name, value in metaInputs {
69
+ for name, value in inputs {
58
70
  if !is_undefined(value) {
59
- if feats.serviceFields {
60
- inputsMap.addMeta(name, value)
71
+ if !is_undefined(inputAddOpts) {
72
+ inputsMap.add(name, value, inputAddOpts)
61
73
  } else {
62
74
  inputsMap.add(name, value)
63
75
  }
64
76
  }
65
77
  }
78
+ if !is_undefined(metaInputs) {
79
+ for name, value in metaInputs {
80
+ if !is_undefined(value) {
81
+ if feats.serviceFields {
82
+ inputsMap.addMeta(name, value)
83
+ } else {
84
+ inputsMap.add(name, value)
85
+ }
86
+ }
87
+ }
88
+ }
66
89
 
67
90
  rbuilder.createInputField(tplutil.INPUTS_MAP_FIELD).set(inputsMap.build())
68
91
 
@@ -154,6 +177,8 @@ createUniversal := func(tpl, isEph, inputs, ...opts) {
154
177
 
155
178
 
156
179
 
180
+
181
+
157
182
  create := func(tpl, inputs, ...opts) {
158
183
  return createUniversal(tpl, false, inputs, opts...)
159
184
  }
@@ -169,6 +194,7 @@ create := func(tpl, inputs, ...opts) {
169
194
 
170
195
 
171
196
 
197
+
172
198
  createEphemeral := func(tpl, inputs, ...opts) {
173
199
  return createUniversal(tpl, true, inputs, opts...)
174
200
  }
@@ -926,7 +926,7 @@ field = func(f) {
926
926
  "smart.field.setCache: cache time must be an integer >= millisecond. Did you forget to import a standard tengo library 'times'?")
927
927
 
928
928
  tx.cacheSetToField(self.id, time)
929
- return self
929
+ return strictSelf
930
930
  },
931
931
 
932
932
 
@@ -1013,6 +1013,7 @@ field = func(f) {
1013
1013
 
1014
1014
  setJson: func(value) {
1015
1015
  self.set(createJsonResource(value))
1016
+ return strictSelf
1016
1017
  },
1017
1018
 
1018
1019
 
@@ -1022,6 +1023,7 @@ field = func(f) {
1022
1023
 
1023
1024
  setMap: func(keyToValue) {
1024
1025
  self.set(createMapResource(keyToValue))
1026
+ return strictSelf
1025
1027
  },
1026
1028
 
1027
1029
 
@@ -1039,6 +1041,8 @@ field = func(f) {
1039
1041
  } else {
1040
1042
  ll.panic("smart resource or smart field expected (target field %v), got %#v: ", self.name(), reference)
1041
1043
  }
1044
+
1045
+ return strictSelf
1042
1046
  },
1043
1047
 
1044
1048
 
@@ -1329,7 +1333,7 @@ resourceBuilder = func(r) {
1329
1333
 
1330
1334
  structBuilder = func(resourceType, ...data) {
1331
1335
  id := undefined
1332
- if len(data) > 0 {
1336
+ if len(data) > 0 && !is_undefined(data[0]) {
1333
1337
  id = tx.createStruct(resourceType.Name, resourceType.Version, data[0])
1334
1338
  } else {
1335
1339
  id = tx.createStruct(resourceType.Name, resourceType.Version)
@@ -1356,6 +1360,15 @@ _mapBuilder := func(isEph, ...resourceType) {
1356
1360
 
1357
1361
  self := undefined
1358
1362
 
1363
+ applyCache := func(field, ...opts) {
1364
+ if len(opts) > 0 {
1365
+ opt := opts[0]
1366
+ if is_map(opt) && !is_undefined(opt.cache) && opt.cache > 0 {
1367
+ field.setCache(opt.cache)
1368
+ }
1369
+ }
1370
+ }
1371
+
1359
1372
  self = ll.toStrict(oop.inherit(builder, {
1360
1373
 
1361
1374
 
@@ -1364,8 +1377,11 @@ _mapBuilder := func(isEph, ...resourceType) {
1364
1377
 
1365
1378
 
1366
1379
 
1367
- addRef: func(key, value) {
1368
- builder.createInputField(key).set(value)
1380
+
1381
+ addRef: func(key, value, ...opts) {
1382
+ field := builder.createInputField(key)
1383
+ applyCache(field, opts...)
1384
+ field.set(value)
1369
1385
  return self
1370
1386
  },
1371
1387
 
@@ -1376,8 +1392,11 @@ _mapBuilder := func(isEph, ...resourceType) {
1376
1392
 
1377
1393
 
1378
1394
 
1379
- addJson: func(key, value) {
1380
- builder.createInputField(key).set(createJsonResource(value))
1395
+
1396
+ addJson: func(key, value, ...opts) {
1397
+ field := builder.createInputField(key)
1398
+ applyCache(field, opts...)
1399
+ field.set(createJsonResource(value))
1381
1400
  return self
1382
1401
  },
1383
1402
 
@@ -1388,8 +1407,11 @@ _mapBuilder := func(isEph, ...resourceType) {
1388
1407
 
1389
1408
 
1390
1409
 
1391
- add: func(key, value) {
1392
- builder.createInputField(key).setRefOrJson(value)
1410
+
1411
+ add: func(key, value, ...opts) {
1412
+ field := builder.createInputField(key)
1413
+ applyCache(field, opts...)
1414
+ field.setRefOrJson(value)
1393
1415
  return self
1394
1416
  },
1395
1417
 
@@ -2,6 +2,7 @@ tx := import("tx")
2
2
  ll := import("@platforma-sdk/workflow-tengo:ll")
3
3
  render := import("@platforma-sdk/workflow-tengo:render")
4
4
  smart := import("@platforma-sdk/workflow-tengo:smart")
5
+ times := import("times")
5
6
  sets := import("@platforma-sdk/workflow-tengo:sets")
6
7
  maps := import("@platforma-sdk/workflow-tengo:maps")
7
8
  tplutil := import("@platforma-sdk/workflow-tengo:tpl.util")
@@ -53,7 +54,7 @@ _unmarshal := func(resource, preprocessors) {
53
54
 
54
55
  result := {}
55
56
 
56
- for field, value in resource.inputs() {
57
+ for field, value in maps.merge(resource.inputs(), resource.metaInputs()) {
57
58
  if value.isErrorSet() {
58
59
  decodedError := value.getError().getDataAsJson()
59
60
  if is_map(decodedError) && decodedError.message != undefined {
@@ -68,16 +69,6 @@ _unmarshal := func(resource, preprocessors) {
68
69
  }
69
70
  }
70
71
 
71
- for field, value in resource.metaInputs() {
72
- if value.isErrorSet() {
73
- ll.panic("meta input %v field has error: %v", field, field.getError().getDataAsJson().message)
74
- } else if value.isSet() {
75
- result[field] = _unmarshal(value.getValue(), preprocessors)
76
- } else {
77
- result[field] = value
78
- }
79
- }
80
-
81
72
  return result
82
73
  } else {
83
74
 
@@ -232,6 +223,11 @@ tpl := func(ops) {
232
223
 
233
224
 
234
225
 
226
+ outputCache: 0,
227
+
228
+
229
+
230
+
235
231
 
236
232
 
237
233
 
@@ -251,6 +247,75 @@ tpl := func(ops) {
251
247
 
252
248
 
253
249
 
250
+ setOutputCache: func(time) {
251
+ ll.assert(is_int(time) && time >= times.millisecond,
252
+ "tpl.setOutputCache: cache time must be an integer >= millisecond. Did you forget to import a standard tengo library 'times'?")
253
+
254
+ self.outputCache = time
255
+ return self
256
+ },
257
+
258
+
259
+
260
+
261
+
262
+
263
+ setOutputCacheMillis: func(millis) {
264
+ ll.assert(is_int(millis) && millis > 0,
265
+ "tpl.setOutputCacheMillis: cache time must be a number of milliseconds (> 0)")
266
+ return self.setOutputCache(millis * times.millisecond)
267
+ },
268
+
269
+
270
+
271
+
272
+
273
+
274
+ setOutputCacheSeconds: func(seconds) {
275
+ ll.assert(is_int(seconds) && seconds > 0,
276
+ "tpl.setOutputCacheSeconds: cache time must be a number of seconds (> 0)")
277
+ return self.setOutputCache(seconds * times.second)
278
+ },
279
+
280
+
281
+
282
+
283
+
284
+
285
+ setOutputCacheMinutes: func(minutes) {
286
+ ll.assert(is_int(minutes) && minutes > 0,
287
+ "tpl.setOutputCacheMinutes: cache time must be a number of minutes (> 0)")
288
+ return self.setOutputCache(minutes * times.minute)
289
+ },
290
+
291
+
292
+
293
+
294
+
295
+
296
+ setOutputCacheHours: func(hours) {
297
+ ll.assert(is_int(hours) && hours > 0, "tpl.setOutputCacheHours: cache time must be a number of hours (> 0)")
298
+ return self.setOutputCache(hours * times.hour)
299
+ },
300
+
301
+
302
+
303
+
304
+
305
+
306
+ setOutputCacheDays: func(days) {
307
+ ll.assert(is_int(days) && days > 0, "tpl.setOutputCacheDays: cache time must be a number of days (> 0)")
308
+ return self.setOutputCache(days * 24 * times.hour)
309
+ },
310
+
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+
254
319
 
255
320
 
256
321
 
@@ -475,7 +540,10 @@ tpl := func(ops) {
475
540
 
476
541
  createOutputsAndLock: func(outputs) {
477
542
  for name in outputs {
478
- self.renderer().createOutputField(tplutil.TEMPLATE_OUTPUT_PREFIX + name)
543
+ field := self.renderer().createOutputField(tplutil.TEMPLATE_OUTPUT_PREFIX + name)
544
+ if self.outputCache > 0 {
545
+ field.setCache(self.outputCache)
546
+ }
479
547
  }
480
548
  self.renderer().lockOutputs()
481
549
  },
@@ -660,6 +728,12 @@ tpl := func(ops) {
660
728
  hasInput : self.hasInput,
661
729
  inputs : self.inputs,
662
730
  defineOutputs : self.defineOutputs,
731
+ setOutputCache : self.setOutputCache,
732
+ setOutputCacheMillis : self.setOutputCacheMillis,
733
+ setOutputCacheSeconds : self.setOutputCacheSeconds,
734
+ setOutputCacheMinutes : self.setOutputCacheMinutes,
735
+ setOutputCacheHours : self.setOutputCacheHours,
736
+ setOutputCacheDays : self.setOutputCacheDays,
663
737
  prepare : self.prepare,
664
738
  awaitState : self.awaitState,
665
739
  awaitStateIfEphemeral : self.awaitStateIfEphemeral,
@@ -405,6 +405,7 @@ export ll.toStrict({
405
405
  resolve: resolve,
406
406
  anchoredQuery: anchoredQuery,
407
407
  prepare: prepare,
408
+ rawInputs: self.rawInputs,
408
409
  body: body,
409
410
  setPreRun: setPreRun,
410
411
  blockId: blockId,