@platforma-sdk/workflow-tengo 1.2.6

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 (51) hide show
  1. package/README.md +6 -0
  2. package/dist/tengo/lib/assets.lib.tengo +64 -0
  3. package/dist/tengo/lib/constants.lib.tengo +75 -0
  4. package/dist/tengo/lib/exec.internal.lib.tengo +211 -0
  5. package/dist/tengo/lib/exec.lib.tengo +516 -0
  6. package/dist/tengo/lib/exec.package.lib.tengo +296 -0
  7. package/dist/tengo/lib/exec.runcmd.lib.tengo +275 -0
  8. package/dist/tengo/lib/exec.runenv.lib.tengo +221 -0
  9. package/dist/tengo/lib/exec.stream.lib.tengo +64 -0
  10. package/dist/tengo/lib/file.lib.tengo +112 -0
  11. package/dist/tengo/lib/ll.lib.tengo +233 -0
  12. package/dist/tengo/lib/maps.lib.tengo +102 -0
  13. package/dist/tengo/lib/objects.lib.tengo +22 -0
  14. package/dist/tengo/lib/oop.lib.tengo +29 -0
  15. package/dist/tengo/lib/path.lib.tengo +165 -0
  16. package/dist/tengo/lib/pframes.constants.lib.tengo +53 -0
  17. package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +47 -0
  18. package/dist/tengo/lib/pframes.lib.tengo +84 -0
  19. package/dist/tengo/lib/pframes.ll.lib.tengo +86 -0
  20. package/dist/tengo/lib/pframes.util.lib.tengo +244 -0
  21. package/dist/tengo/lib/pframes.xsv.lib.tengo +178 -0
  22. package/dist/tengo/lib/render.lib.tengo +100 -0
  23. package/dist/tengo/lib/sets.lib.tengo +93 -0
  24. package/dist/tengo/lib/slices.lib.tengo +202 -0
  25. package/dist/tengo/lib/smart.lib.tengo +1005 -0
  26. package/dist/tengo/lib/tpl.lib.tengo +535 -0
  27. package/dist/tengo/lib/tpl.state-await.lib.tengo +255 -0
  28. package/dist/tengo/lib/tpl.util.lib.tengo +19 -0
  29. package/dist/tengo/lib/validation.lib.tengo +428 -0
  30. package/dist/tengo/lib/workdir.lib.tengo +300 -0
  31. package/dist/tengo/lib/workdir.proc.lib.tengo +158 -0
  32. package/dist/tengo/lib/workdir.save.lib.tengo +158 -0
  33. package/dist/tengo/lib/workflow.bobject.lib.tengo +51 -0
  34. package/dist/tengo/lib/workflow.bquery.lib.tengo +208 -0
  35. package/dist/tengo/lib/workflow.constants.lib.tengo +8 -0
  36. package/dist/tengo/lib/workflow.context.lib.tengo +56 -0
  37. package/dist/tengo/lib/workflow.lib.tengo +298 -0
  38. package/dist/tengo/tpl/exec.create-python-venv.plj.gz +0 -0
  39. package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
  40. package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
  41. package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
  42. package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
  43. package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
  44. package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
  45. package/dist/tengo/tpl/pframes.import-xsv-map.plj.gz +0 -0
  46. package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
  47. package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
  48. package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
  49. package/index.d.ts +4 -0
  50. package/index.js +13 -0
  51. package/package.json +25 -0
@@ -0,0 +1,1005 @@
1
+ /*
2
+ * Library provides smart.Resource and smart.Field primitives.
3
+ */
4
+
5
+ tx := import("tx")
6
+ ll := import("@platforma-sdk/workflow-tengo:ll")
7
+ oop := import("@platforma-sdk/workflow-tengo:oop")
8
+ maps := import("@platforma-sdk/workflow-tengo:maps")
9
+ json := import("json")
10
+ constants := import("@platforma-sdk/workflow-tengo:constants")
11
+
12
+ //////////////// definitions ////////////////
13
+
14
+ /**
15
+ * A read-only wrapper object around raw platforma resource
16
+ */
17
+ resource := undefined
18
+
19
+ /**
20
+ * A wrapper object around raw platforma resource field
21
+ */
22
+ field := undefined
23
+
24
+ /**
25
+ * A convenient builder for resource objects
26
+ */
27
+ resourceBuilder := undefined
28
+
29
+ /**
30
+ * Builder for structural resource
31
+ *
32
+ * @param resourceType { Name: "", Version: "" }
33
+ */
34
+ structBuilder := undefined
35
+
36
+ /**
37
+ * Builder for map resource
38
+ */
39
+ mapBuilder := undefined
40
+
41
+ /**
42
+ * Builder for ephemeral map resource
43
+ */
44
+ ephemeralMapBuilder := undefined
45
+
46
+ /**
47
+ * Builder for emphemeral resources
48
+ *
49
+ * @param resourceType { Name: "", Version: "" }
50
+ */
51
+ ephemeralBuilder := undefined
52
+
53
+ /**
54
+ * Create value resource
55
+ *
56
+ * @param resourceType { Name: "", Version: "" }
57
+ * @param data optional data
58
+ */
59
+ createValueResource := undefined
60
+
61
+ /**
62
+ * Create Json resource
63
+ *
64
+ * @param value value to save in the resource
65
+ */
66
+ createJsonResource := undefined
67
+
68
+ /**
69
+ * Create map resource
70
+ *
71
+ * @param keyToValue: map[string]anyResource
72
+ * @return resource
73
+ */
74
+ createMapResource := undefined
75
+
76
+ /**
77
+ * Create binary map resource
78
+ *
79
+ * @param keyToValue: map[string]valueResource
80
+ * @return resource
81
+ */
82
+ createBinaryMapResource := undefined
83
+
84
+ /**
85
+ * Create blob map resource
86
+ *
87
+ * @param keyToValue: map[string]blobResource
88
+ * @return resource
89
+ */
90
+ createBlobMapResource := undefined
91
+
92
+ ////////////////// helpers ///////////////////////////
93
+
94
+ // internal helper function
95
+ isFieldId := func(val) {
96
+ return ll.isStrict(val) && ll.fromStrict(val)["ResourceID"] != undefined
97
+ }
98
+
99
+ /**
100
+ * Returns true if given object is a smart.Resource
101
+ */
102
+ isResource := func(f) {
103
+ return ll.isStrict(f) && ll.fromStrict(f)["_type"] == "resource"
104
+ }
105
+
106
+ /**
107
+ * Returns true if given object is a smart.Field
108
+ */
109
+ isField := func(f) {
110
+ return ll.isStrict(f) && ll.fromStrict(f)["_type"] == "field"
111
+ }
112
+
113
+ /**
114
+ * Returns true if given object is a smart.Field or smart.Resource
115
+ */
116
+ isReference := func(f) {
117
+ return isField(f) || isResource(f)
118
+ }
119
+
120
+ /**
121
+ * Gets future field by given field name and field type.
122
+ *
123
+ * @param from: reference - whether a resource or a field we get a field from.
124
+ * @param name: field name
125
+ * @param fieldType: field type: input, output
126
+ * @return field: smart field
127
+ */
128
+ _getFutureField := func(from, name, fieldType) {
129
+ ll.assert(isReference(from), "'from' must be either a resource or a field, got: %#v", from)
130
+
131
+ futureField := tx.createFutureFieldID(fieldType, name)
132
+ f := field(futureField.ResourceFID)
133
+ f.set(from)
134
+
135
+ return field(futureField.ResultFID)
136
+ }
137
+ /**
138
+ * Returns true if given object is a StdMap resource
139
+ */
140
+ isMapResource := func(r) {
141
+ return isResource(r) && (
142
+ r.info().Type.Name == constants.RTYPE_MAP.Name ||
143
+ r.info().Type.Name == constants.RTYPE_MAP_ALT.Name) // @TODO get rid of alt name
144
+
145
+ }
146
+
147
+ /**
148
+ * Returns true if given object is an ephemeral std map resource
149
+ */
150
+ isEphMapResource := func(r) {
151
+ return isResource(r) && r.info().Type.Name == constants.RTYPE_MAP_EPH.Name
152
+ }
153
+
154
+ /**
155
+ * Returns true if given object is an ephemeral std map resource with locked inputs (so the list of inputs is final)
156
+ */
157
+ isLockedEphMapResource := func(r) {
158
+ return isEphMapResource(r) && r.info().InputsLocked
159
+ }
160
+
161
+ /**
162
+ * Returns true if given object is a map or ephemeral map resource
163
+ */
164
+ isAnyMapResource := func(r) {
165
+ return isMapResource(r) || isEphMapResource(r)
166
+ }
167
+
168
+ /**
169
+ * Returns true if given object is a json resource
170
+ */
171
+ isJsonResource := func(r) {
172
+ return isResource(r) && r.info().Type.Name == constants.RTYPE_JSON.Name
173
+ }
174
+
175
+ // deep check whether map has resources somewhere inside
176
+ _hasReferenceValues := func(object) {
177
+ if isReference(object) {
178
+ // first check is reference since resource/field will return true on ll.isMap
179
+ return true
180
+ } else if ll.isMap(object) {
181
+ for _, v in object {
182
+ if _hasReferenceValues(v) {
183
+ return true
184
+ }
185
+ }
186
+ } else if is_array(object) {
187
+ for v in object {
188
+ if _hasReferenceValues(v) {
189
+ return true
190
+ }
191
+ }
192
+ }
193
+ return false
194
+ }
195
+
196
+ /**
197
+ * Convert given object to resource. If object is a true json, then
198
+ * a simple Json resource will be created, otherwise a resource map.
199
+ */
200
+ _toRefOrJson := func(object) {
201
+ if isReference(object) {
202
+ // first check is reference since resource/field will return true on ll.isMap
203
+ return object
204
+ } else if ll.isMap(object) {
205
+
206
+ // just json if there are no nested resources
207
+ if !_hasReferenceValues(object) {
208
+ return createJsonResource(object)
209
+ }
210
+
211
+ mb := mapBuilder()
212
+ for k, v in object {
213
+ mb.add(k, _toRefOrJson(v))
214
+ }
215
+
216
+ return mb.build()
217
+ } else if is_array(object) {
218
+
219
+ // assert we are not having refs inside
220
+ ll.assert(!_hasReferenceValues(object), "array can't contain references")
221
+
222
+ return createJsonResource(object)
223
+ } else {
224
+ return createJsonResource(object)
225
+ }
226
+ }
227
+
228
+ resourceTypesEqual := func(rType1, rType2) {
229
+ return rType1.Name == rType2.Name && rType1.Version == rType2.Version
230
+ }
231
+
232
+ ////////////////// implementation ///////////////////////////
233
+
234
+ /**
235
+ * @param r either resource id or resource info
236
+ */
237
+ resource = func(r) {
238
+ self := undefined
239
+ strictSelf := undefined
240
+
241
+ if isResource(r) {
242
+ return r
243
+ }
244
+
245
+ id := ll.isStrict(r) ? r.ID : r
246
+
247
+ if !is_int(id) {
248
+ ll.panic("resource id should be int for ", r)
249
+ }
250
+
251
+ if id == 0 {
252
+ ll.panic("null resource id for ", r)
253
+ }
254
+
255
+ self = {
256
+ _type: "resource",
257
+
258
+ /**
259
+ * Resource id (int64)
260
+ */
261
+ id: id,
262
+
263
+ /**
264
+ * Resource info:
265
+ *
266
+ * ID: int64
267
+ * Data: byte[],
268
+ * Type: { Name: string, Version: string }
269
+ * Inputs: strict map
270
+ * Outputs: strict map
271
+ * Dynamic: strict map
272
+ * OTW: strict map
273
+ * ResourceReady: bool
274
+ * AllInputsSet: bool
275
+ * AllOutputsSet: bool
276
+ * IsDuplicate: bool
277
+ * InputsLocked: bool
278
+ * OutputsLocked: bool
279
+ * HasErrors: bool
280
+ */
281
+ info: func() {
282
+ return tx.getResource(self.id)
283
+ },
284
+
285
+ /**
286
+ * Returns true if resource has type equal to the one provided as an agrument.
287
+ *
288
+ * @param expectedType type to compare resource type with
289
+ * @return true if type matches, false otherwise
290
+ */
291
+ checkResourceType: func(expectedType) {
292
+ return resourceTypesEqual(self.info().Type, expectedType)
293
+ },
294
+
295
+ /**
296
+ * Resource is ready when all inputs are set to the terminal values.
297
+ */
298
+ isReady: func() {
299
+ return self.info().ResourceReady
300
+ },
301
+
302
+ /**
303
+ * Get raw resource data
304
+ *
305
+ * @return data: []byte - raw resource data
306
+ */
307
+ getData: func() {
308
+ if self.hasError() {
309
+ ll.panic("resource has errors: ", self.info())
310
+ }
311
+ return self.info().Data;
312
+ },
313
+
314
+ /**
315
+ * Get resource data as Json
316
+ */
317
+ getDataAsJson: func() {
318
+ return json.decode(self.getData());
319
+ },
320
+
321
+ /**
322
+ * Whether this resource has error
323
+ */
324
+ hasError: func() {
325
+ return self._hasField("OneTimeWritables", "resourceError")
326
+ },
327
+
328
+ /**
329
+ * Whether any of the input fields have errors. The resource itself may still not have
330
+ * error status because error propagation was not yet happened.
331
+ */
332
+ hasInputErrors: func() {
333
+ return self.info().HasErrors
334
+ },
335
+
336
+ /**
337
+ * Return error set in the resource
338
+ */
339
+ getError: func() {
340
+ if !self.info().HasErrors {
341
+ ll.panic("no error set in resource")
342
+ }
343
+ return self.getField("resourceError").getValue()
344
+ },
345
+
346
+ _hasField: func(fieldMapName, fieldName) {
347
+ return ll.fromStrict(self.info()[fieldMapName])[fieldName] != undefined
348
+ },
349
+
350
+ /**
351
+ * Whether ressource has input field with specified name
352
+ *
353
+ * @param name field name
354
+ */
355
+ hasInputField: func(name) {
356
+ return self._hasField("Inputs", name)
357
+ },
358
+
359
+ /**
360
+ * Whether ressource has output field with specified name
361
+ *
362
+ * @param name field name
363
+ */
364
+ hasOutputField: func(name) {
365
+ return self._hasField("Outputs", name)
366
+ },
367
+
368
+ /**
369
+ * Whether ressource has any field with specified name
370
+ *
371
+ * @param name field name
372
+ */
373
+ hasField: func(name) {
374
+ return self._hasField("Inputs", name) ||
375
+ self._hasField("Outputs", name) ||
376
+ self._hasField("DynamicFields", name) ||
377
+ self._hasField("OneTimeWritables", name)
378
+ },
379
+
380
+ // cached _inputs
381
+ _inputs: undefined,
382
+ /**
383
+ * Returns resource inputs map name -> smart.Field
384
+ */
385
+ inputs: func() {
386
+ if self._inputs == undefined {
387
+ info := self.info()
388
+ inputs := maps.mapValues(info.Inputs, field)
389
+ if !info.InputsLocked {
390
+ return inputs
391
+ }
392
+ self._inputs = inputs
393
+ }
394
+ return self._inputs
395
+ },
396
+
397
+ // cached _outputs
398
+ _outputs: undefined,
399
+ /**
400
+ * Returns resource outputs map name -> smart.Field
401
+ */
402
+ outputs: func() {
403
+ if(self._outputs == undefined) {
404
+ info := self.info()
405
+ outputs := ll.toStrict(maps.mapValues(info.Outputs, field))
406
+ if !info.OutputsLocked {
407
+ return outputs
408
+ }
409
+ self._outputs = outputs
410
+ }
411
+ return self._outputs
412
+ },
413
+
414
+ /**
415
+ * Get smart.Field by name
416
+ *
417
+ * @param name field name
418
+ */
419
+ getField: func(name) {
420
+ if(!self.hasField(name)) {
421
+ ll.panic("field %v is not found", name)
422
+ }
423
+
424
+ return field(ll.fieldId(self.id, name))
425
+ },
426
+
427
+ /**
428
+ * Get future field given field name and field type.
429
+ *
430
+ * @param name: field name
431
+ * @param fieldType: field type: input, output
432
+ * @return field: smart field
433
+ */
434
+ getFutureField: func(name, fieldType) {
435
+ return _getFutureField(strictSelf, name, fieldType)
436
+ },
437
+
438
+ /**
439
+ * Get future input field given field name or a path
440
+ *
441
+ * @param nameOrPath field name or an array representing a path to be traversed
442
+ * @return field: smart field
443
+ */
444
+ getFutureInputField: func(nameOrPath) {
445
+ if is_array(nameOrPath) {
446
+ current := strictSelf
447
+ for name in nameOrPath {
448
+ current = current.getFutureField(name, "input")
449
+ }
450
+ return current
451
+ } else {
452
+ return self.getFutureField(nameOrPath, "input")
453
+ }
454
+ },
455
+
456
+ /**
457
+ * Get future output field given field name
458
+ *
459
+ * @param name field name
460
+ * @return field: smart field
461
+ */
462
+ getFutureOutputField: func(name) {
463
+ return self.getFutureField(name, "output")
464
+ },
465
+
466
+ /**
467
+ * Get a resource set in field of a given field name
468
+ *
469
+ * @param name field name
470
+ */
471
+ get: func(name) {
472
+ return self.getField(name).getValue()
473
+ },
474
+
475
+ /**
476
+ * Gets value from key value storage associated with resource if corresponding
477
+ * record exists.
478
+ *
479
+ * @param key string key
480
+ * @return bytes or undefined
481
+ */
482
+ kvGet: func(key) {
483
+ return tx.resourceKeyValueGet(self.id, key)
484
+ },
485
+
486
+ /**
487
+ * Sets bytes or string value to a key value storage associated
488
+ * with resource.
489
+ *
490
+ * @param key string key
491
+ * @param value to be set
492
+ */
493
+ kvSet: func(key, value) {
494
+ tx.resourceKeyValueSet(self.id, key, value)
495
+ },
496
+
497
+ /**
498
+ * Gets value as string from key value storage associated with resource if
499
+ * corresponding record exists.
500
+ *
501
+ * @param key string key
502
+ * @return string or undefined
503
+ */
504
+ kvGetAsString: func(key) {
505
+ value := tx.resourceKeyValueGet(self.id, key)
506
+ if is_undefined(value) {
507
+ return undefined
508
+ } else {
509
+ return string(value)
510
+ }
511
+ },
512
+
513
+ /**
514
+ * Gets value from key value storage associated with resource and
515
+ * decodes as json if corresponding record exists.
516
+ *
517
+ * @param key string key
518
+ * @return value or undefined
519
+ */
520
+ kvGetAsJson: func(key) {
521
+ bytes := self.kvGet(key)
522
+ if is_undefined(bytes){
523
+ return undefined
524
+ } else {
525
+ return json.decode(bytes)
526
+ }
527
+ },
528
+
529
+ /**
530
+ * Sets json value to a key value storage associated with resource.
531
+ *
532
+ * @param key string key
533
+ * @param value to be set
534
+ */
535
+ kvSetJson: func(key, value) {
536
+ self.kvSet(key, json.encode(value))
537
+ }
538
+ }
539
+
540
+ strictSelf = ll.toStrict(self)
541
+
542
+ return strictSelf
543
+ }
544
+
545
+ field = func(f) {
546
+ self := undefined
547
+ strictSelf := undefined
548
+
549
+ self = {
550
+ _type: "field",
551
+
552
+ /**
553
+ * Field id struct:
554
+ *
555
+ * ResourceID: int64
556
+ * Name: string
557
+ *
558
+ */
559
+ id: isFieldId(f) ? f : f.ID,
560
+
561
+ /**
562
+ * Field name
563
+ */
564
+ name: func() {
565
+ return self.id.Name
566
+ },
567
+
568
+ /**
569
+ * Associated smart.Resource
570
+ */
571
+ resource: func() {
572
+ return resource(self.id.ResourceID)
573
+ },
574
+
575
+ /**
576
+ * Field info:
577
+ *
578
+ * ID: { ResourceId: int64, Name: string }
579
+ * Value: int64 - value resource id
580
+ * Error: int64 - error resource id
581
+ * IsSet: bool - whether field is set
582
+ */
583
+ info: func() {
584
+ return tx.getField(self.id)
585
+ },
586
+
587
+ /**
588
+ * Whether the field points to resource or error
589
+ */
590
+ isSet: func() {
591
+ return self.info().IsSet
592
+ },
593
+
594
+ /**
595
+ * Whether field is resolved to a value
596
+ */
597
+ isValueSet: func() {
598
+ return self.info().Value != 0
599
+ },
600
+
601
+ /**
602
+ * Whether field is resolved to a error
603
+ */
604
+ isErrorSet: func() {
605
+ return self.info().Error != 0
606
+ },
607
+
608
+ /**
609
+ * Returns a smart.Resource object from the resolved field value
610
+ */
611
+ getValue: func() {
612
+ if self.isErrorSet() {
613
+ err := self.getError().getDataAsJson()
614
+ if !is_undefined(err.message) {
615
+ err = err.message
616
+ }
617
+ ll.panic("failed to get the value of field %v, error is not empty: %v", self.name(), err)
618
+ }
619
+
620
+ ll.assert(self.isSet(), "field value is not set; ", self.name())
621
+
622
+ return resource(self.info().Value)
623
+ },
624
+
625
+ /**
626
+ * Returns a smart.Resource object from the resolved field error
627
+ */
628
+ getError: func() {
629
+ return resource(self.info().Error)
630
+ },
631
+
632
+ /**
633
+ * Set (resolve) this field to a Json resource
634
+ *
635
+ * @param value any
636
+ */
637
+ setJson: func(value) {
638
+ self.set(createJsonResource(value))
639
+ },
640
+
641
+ /**
642
+ * Set (resolve) this field to a Map resource
643
+ *
644
+ * @param keyToValue any
645
+ */
646
+ setMap: func(keyToValue) {
647
+ self.set(createMapResource(keyToValue))
648
+ },
649
+
650
+ /**
651
+ * Set (resolve) this field to either another resource or field
652
+ *
653
+ * @param reference smart.resource or smart.field
654
+ */
655
+ set: func(reference) {
656
+ ll.assert(!self.isSet(), "field ", self.name(), " is already set")
657
+
658
+ if isResource(reference) {
659
+ tx.setFieldToResource(self.id, reference.id)
660
+ } else if isField(reference) {
661
+ tx.setFieldToField(self.id, reference.id)
662
+ } else {
663
+ ll.panic("smart resource or smart field expected (target field %v), got %#v: ", self.name(), reference)
664
+ }
665
+ },
666
+
667
+ /**
668
+ * Sets this field to either another resource, field or a JSON value.
669
+ *
670
+ * @param refOrJson: resource|field|JSON
671
+ * @return nothing
672
+ */
673
+ setRefOrJson: func(refOrJson) {
674
+ if is_undefined(refOrJson) {
675
+ ll.panic("attempt to assign undefined value to field %v", self.name())
676
+ }
677
+ self.set(_toRefOrJson(refOrJson))
678
+ },
679
+
680
+ /**
681
+ * Returns a json encoded data of the resolved value resource
682
+ */
683
+ getValueAsJson: func() {
684
+ return self.getValue().getDataAsJson()
685
+ },
686
+
687
+ /**
688
+ * Get future field given field name and field type.
689
+ *
690
+ * @param name: field name
691
+ * @param fieldType: field type: input, output
692
+ * @return field: smart field
693
+ */
694
+ getFutureField: func(name, fieldType) {
695
+ return _getFutureField(strictSelf, name, fieldType)
696
+ },
697
+
698
+ /**
699
+ * Get future input field given field name or a path
700
+ *
701
+ * @param nameOrPath field name or an array representing a path to be traversed
702
+ * @return field: smart field
703
+ */
704
+ getFutureInputField: func(nameOrPath) {
705
+ if is_array(nameOrPath) {
706
+ current := strictSelf
707
+ for name in nameOrPath {
708
+ current = current.getFutureField(name, "input")
709
+ }
710
+ return current
711
+ } else {
712
+ return self.getFutureField(nameOrPath, "input")
713
+ }
714
+ },
715
+
716
+ /**
717
+ * Get future output field given field name
718
+ *
719
+ * @param name field name
720
+ * @return field: smart field
721
+ */
722
+ getFutureOutputField: func(name) {
723
+ return self.getFutureField(name, "output")
724
+ }
725
+ }
726
+
727
+ strictSelf = ll.toStrict(self)
728
+
729
+ return strictSelf
730
+ }
731
+
732
+
733
+ /**
734
+ * Universal resource builder.
735
+ *
736
+ * @param r either resource id or resource info
737
+ */
738
+ resourceBuilder = func(r) {
739
+ super := resource(r)
740
+
741
+ self := undefined
742
+
743
+ // Mutator methods of the builder cannot be used after it was built.
744
+ built := false
745
+ assertNotBuilt := func() {
746
+ ll.assert(!built, "builder methods must not be used after a build() was called")
747
+ }
748
+
749
+ self = ll.toStrict(oop.inherit(super, {
750
+ /**
751
+ * Create new field with given name and field type.
752
+ *
753
+ * @param name field name
754
+ * @param fieldType: field type - input, output, dynamic, service, OTW. Use F_TYPE_* constants.
755
+ */
756
+ createField: func(name, fieldType) {
757
+ assertNotBuilt()
758
+ fid := ll.fieldId(super.id, name)
759
+ tx.createField(fid, fieldType)
760
+ return field(fid)
761
+ },
762
+
763
+ /**
764
+ * Create new input field with given name.
765
+ *
766
+ * @param name field name
767
+ */
768
+ createInputField: func(name) {
769
+ assertNotBuilt()
770
+ return self.createField(name, "input")
771
+ },
772
+
773
+ /**
774
+ * Create new output field with given name.
775
+ *
776
+ * @param name field name
777
+ */
778
+ createOutputField: func(name) {
779
+ assertNotBuilt()
780
+ return self.createField(name, "output")
781
+ },
782
+
783
+ /**
784
+ * Lock resource outputs
785
+ */
786
+ lockOutputs: func() {
787
+ assertNotBuilt()
788
+ tx.lockOutputs(super.id)
789
+ },
790
+
791
+ /**
792
+ * Lock resource inputs
793
+ */
794
+ lockInputs: func() {
795
+ assertNotBuilt()
796
+ tx.lockInputs(super.id)
797
+ },
798
+
799
+ /**
800
+ * Lock both resource inputs and outputs
801
+ */
802
+ lock: func() {
803
+ assertNotBuilt()
804
+ self.lockInputs()
805
+ self.lockOutputs()
806
+ },
807
+
808
+ /**
809
+ * Lock inputs and outputs and return resulting smart.Resource
810
+ */
811
+ lockAndBuild: func() {
812
+ self.lock()
813
+ built = true
814
+ return super
815
+ },
816
+
817
+ /**
818
+ * Lock outputs and return resulting smart.Resource
819
+ */
820
+ lockOutputsAndBuild: func() {
821
+ self.lockOutputs()
822
+ built = true
823
+ return super
824
+ },
825
+
826
+ /**
827
+ * Lock inputs and return resulting smart.Resource
828
+ */
829
+ lockInputsAndBuild: func() {
830
+ self.lockInputs()
831
+ built = true
832
+ return super
833
+ },
834
+
835
+ /**
836
+ * Return smart.Resource without locking inputs and outputs
837
+ */
838
+ buildUnlocked: func() {
839
+ built = true
840
+ return super
841
+ }
842
+ }))
843
+
844
+ return self
845
+ }
846
+
847
+ /**
848
+ * Creates a structural resource and returns a builder from it.
849
+ *
850
+ * @params resourceType a resource type
851
+ * @params data, optional, bytes that will go in Data of the resource.
852
+ */
853
+ structBuilder = func(resourceType, ...data) {
854
+ id := undefined
855
+ if len(data) > 0 {
856
+ id = tx.createStruct(resourceType.Name, resourceType.Version, data[0])
857
+ } else {
858
+ id = tx.createStruct(resourceType.Name, resourceType.Version)
859
+ }
860
+
861
+ return resourceBuilder(id)
862
+ }
863
+
864
+ /**
865
+ * @param isEph: is ephemeral map
866
+ */
867
+ _mapBuilder := func(isEph) {
868
+ builder := isEph ? ephemeralBuilder(constants.RTYPE_MAP_EPH) : structBuilder(constants.RTYPE_MAP)
869
+ // ensure no outputs will be created
870
+ builder.lockOutputs()
871
+
872
+ self := undefined
873
+
874
+ self = ll.toStrict(oop.inherit(builder, {
875
+ /**
876
+ * Adds a reference to the map by a given key.
877
+ *
878
+ * @param key: string - how the field will be named in the map
879
+ * @param value: reference - a field or resource that will be set in the field
880
+ * @return self: mapBuilder
881
+ */
882
+ addRef: func(key, value) {
883
+ builder.createInputField(key).set(value)
884
+ return self
885
+ },
886
+
887
+ /**
888
+ * Adds a primitive value that can be converted to JSON to the map.
889
+ *
890
+ * @param key: string - how the field will be named in the map
891
+ * @param value: any - a primitive value, e.g. Tengo's map.
892
+ * @return self: mapBuilder
893
+ */
894
+ addJson: func(key, value) {
895
+ builder.createInputField(key).set(createJsonResource(value))
896
+ return self
897
+ },
898
+
899
+ /**
900
+ * Adds object automatically converting non-reference objects into Json values.
901
+ *
902
+ * @param key: string - how the field will be named in the map
903
+ * @param value: any - a reference or a primitive value
904
+ * @return self: mapBuilder
905
+ */
906
+ add: func(key, value) {
907
+ builder.createInputField(key).setRefOrJson(value)
908
+ return self
909
+ },
910
+
911
+
912
+ /**
913
+ * Creates a map in the platforma
914
+ *
915
+ * @return nothing
916
+ */
917
+ build: func() {
918
+ return builder.lockAndBuild()
919
+ }
920
+ }))
921
+
922
+ return self
923
+ }
924
+
925
+ mapBuilder = func() {
926
+ return _mapBuilder(false)
927
+ }
928
+
929
+ ephemeralMapBuilder = func() {
930
+ return _mapBuilder(true)
931
+ }
932
+
933
+ ephemeralBuilder = func(resourceType, ...data) {
934
+ id := undefined
935
+ if (len(data) > 0) {
936
+ id = tx.createEphemeral(resourceType.Name, resourceType.Version, data[0])
937
+ } else {
938
+ id = tx.createEphemeral(resourceType.Name, resourceType.Version)
939
+ }
940
+
941
+ return resourceBuilder(id)
942
+ }
943
+
944
+ createValueResource = func(resourceType, data) {
945
+ ll.assert(data != undefined, "can't create resource with undefined data")
946
+ return resource(tx.createValue(resourceType.Name, resourceType.Version, data))
947
+ }
948
+
949
+ createJsonResource = func(value) {
950
+ ll.assert(value != undefined, "can't create Json value from undefined")
951
+
952
+ // important: strict map can't be encoded to JSON
953
+
954
+ ll.assert(!ll.isStrict(value), "can't encode strict map: ", value)
955
+ // value = ll.ensureNonStrict(value)
956
+
957
+ encoded := json.encode(value)
958
+ return createValueResource(constants.RTYPE_JSON, encoded)
959
+ }
960
+
961
+ createMapResourceWithType := func(resourceType, keyToValue) {
962
+ builder := structBuilder(resourceType)
963
+
964
+ for key, value in keyToValue {
965
+ builder.createInputField(key).setRefOrJson(value)
966
+ }
967
+
968
+ return builder.lockAndBuild()
969
+ }
970
+
971
+ createMapResource = func(keyToValue) {
972
+ return createMapResourceWithType(constants.RTYPE_MAP, keyToValue)
973
+ }
974
+
975
+ createBinaryMapResource = func(keyToValue) {
976
+ return createMapResourceWithType(constants.RTYPE_BINARY_MAP, keyToValue)
977
+ }
978
+
979
+ createBlobMapResource = func(keyToValue) {
980
+ return createMapResourceWithType(constants.RTYPE_BLOB_MAP, keyToValue)
981
+ }
982
+
983
+ export ll.toStrict({
984
+ isResource: isResource,
985
+ isField: isField,
986
+ isReference: isReference,
987
+ isMapResource: isMapResource,
988
+ isEphMapResource: isEphMapResource,
989
+ isAnyMapResource: isAnyMapResource,
990
+ isLockedEphMapResource: isLockedEphMapResource,
991
+ isJsonResource: isJsonResource,
992
+ resource: resource,
993
+ field: field,
994
+ resourceBuilder: resourceBuilder,
995
+ structBuilder: structBuilder,
996
+ mapBuilder: mapBuilder,
997
+ ephemeralMapBuilder: ephemeralMapBuilder,
998
+ ephemeralBuilder: ephemeralBuilder,
999
+ createValueResource: createValueResource,
1000
+ createJsonResource: createJsonResource,
1001
+ createMapResourceWithType: createMapResourceWithType,
1002
+ createMapResource: createMapResource,
1003
+ createBinaryMapResource: createBinaryMapResource,
1004
+ createBlobMapResource: createBlobMapResource
1005
+ })