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