@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.
- package/README.md +6 -0
- package/dist/tengo/lib/assets.lib.tengo +64 -0
- package/dist/tengo/lib/constants.lib.tengo +75 -0
- package/dist/tengo/lib/exec.internal.lib.tengo +211 -0
- package/dist/tengo/lib/exec.lib.tengo +516 -0
- package/dist/tengo/lib/exec.package.lib.tengo +296 -0
- package/dist/tengo/lib/exec.runcmd.lib.tengo +275 -0
- package/dist/tengo/lib/exec.runenv.lib.tengo +221 -0
- package/dist/tengo/lib/exec.stream.lib.tengo +64 -0
- package/dist/tengo/lib/file.lib.tengo +112 -0
- package/dist/tengo/lib/ll.lib.tengo +233 -0
- package/dist/tengo/lib/maps.lib.tengo +102 -0
- package/dist/tengo/lib/objects.lib.tengo +22 -0
- package/dist/tengo/lib/oop.lib.tengo +29 -0
- package/dist/tengo/lib/path.lib.tengo +165 -0
- package/dist/tengo/lib/pframes.constants.lib.tengo +53 -0
- package/dist/tengo/lib/pframes.export-pcolumn.lib.tengo +47 -0
- package/dist/tengo/lib/pframes.lib.tengo +84 -0
- package/dist/tengo/lib/pframes.ll.lib.tengo +86 -0
- package/dist/tengo/lib/pframes.util.lib.tengo +244 -0
- package/dist/tengo/lib/pframes.xsv.lib.tengo +178 -0
- package/dist/tengo/lib/render.lib.tengo +100 -0
- package/dist/tengo/lib/sets.lib.tengo +93 -0
- package/dist/tengo/lib/slices.lib.tengo +202 -0
- package/dist/tengo/lib/smart.lib.tengo +1005 -0
- package/dist/tengo/lib/tpl.lib.tengo +535 -0
- package/dist/tengo/lib/tpl.state-await.lib.tengo +255 -0
- package/dist/tengo/lib/tpl.util.lib.tengo +19 -0
- package/dist/tengo/lib/validation.lib.tengo +428 -0
- package/dist/tengo/lib/workdir.lib.tengo +300 -0
- package/dist/tengo/lib/workdir.proc.lib.tengo +158 -0
- package/dist/tengo/lib/workdir.save.lib.tengo +158 -0
- package/dist/tengo/lib/workflow.bobject.lib.tengo +51 -0
- package/dist/tengo/lib/workflow.bquery.lib.tengo +208 -0
- package/dist/tengo/lib/workflow.constants.lib.tengo +8 -0
- package/dist/tengo/lib/workflow.context.lib.tengo +56 -0
- package/dist/tengo/lib/workflow.lib.tengo +298 -0
- package/dist/tengo/tpl/exec.create-python-venv.plj.gz +0 -0
- package/dist/tengo/tpl/exec.exec.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.aggregate.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-multiple-pcolumns.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.export-single-pcolumn.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.import-dir.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.import-xsv-map.plj.gz +0 -0
- package/dist/tengo/tpl/pframes.map-pframe.plj.gz +0 -0
- package/dist/tengo/tpl/workdir.save.plj.gz +0 -0
- package/dist/tengo/tpl/workflow.build-ctx.plj.gz +0 -0
- package/index.d.ts +4 -0
- package/index.js +13 -0
- 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
|
+
})
|