@naanlang/naan 1.0.6 → 1.0.8
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/LICENSE.md +3 -4
- package/README.md +20 -2
- package/bin/index.js +2 -2
- package/dist/env_web.js +91 -18
- package/dist/naan.min.js +7 -7
- package/frameworks/browser/browser.nlg +92 -3
- package/frameworks/browser/https_request.nlg +2 -2
- package/frameworks/browser/sworker.js +17 -17
- package/frameworks/browser/terminals.nlg +14 -12
- package/frameworks/browser/workers.nlg +13 -6
- package/frameworks/client/psm_client.nlg +1 -0
- package/frameworks/common/common.nlg +39 -8
- package/frameworks/node/filesystem.nlg +32 -26
- package/frameworks/node/gitter.nlg +9 -4
- package/frameworks/node/https_request.nlg +19 -14
- package/frameworks/project/build.nlg +187 -74
- package/frameworks/project/projects.nlg +42 -17
- package/frameworks/running/running.nlg +33 -11
- package/frameworks/running/taskexec.nlg +1 -1
- package/frameworks/storage/file_manager.nlg +2 -1
- package/frameworks/storage/psm.nlg +20 -4
- package/frameworks/storage/psm_dbtables.nlg +13 -3
- package/lib/browser/env_web.js +93 -20
- package/lib/browser/env_webworker.js +10 -0
- package/lib/core/naanlib.js +7 -7
- package/package.json +2 -1
- package/plugins/serviceAws/aws/aws-sdk-node.min.js +1 -1
- package/plugins/serviceAws/aws/aws-sdk.min.js +1 -1
- package/plugins/serviceAws/aws/lambda_ws_init.nlg +2 -1
- package/plugins/serviceAws/aws_dynamo.nlg +45 -26
- package/plugins/serviceAws/aws_dynextra.nlg +157 -32
- package/plugins/serviceAws/aws_lambda.nlg +4 -8
- package/plugins/serviceAws/aws_s3.nlg +74 -28
- package/plugins/serviceAws/aws_sqs.nlg +113 -0
- package/plugins/serviceAws/dbt_aws.nlg +73 -24
- package/plugins/serviceAws/psm_aws.nlg +30 -11
- package/plugins/serviceAws/serviceAws.nlg +2 -4
- package/plugins/serviceYC/generic_api.yaml +36 -0
- package/plugins/serviceYC/naanide-relay-index.js +148 -0
- package/plugins/serviceYC/serviceYC.nlg +59 -0
- package/plugins/serviceYC/yc_function.nlg +161 -0
- package/test/test_01_core.nlg +2 -2
- package/test/test_02_context.nlg +2 -2
- package/test/test_05_strings.nlg +11 -1
- package/test/test_06_lingoparse.nlg +43 -14
|
@@ -515,6 +515,8 @@ closure DynaConverter(local conv) {
|
|
|
515
515
|
closure DynaTable(dyna, tablename, local table) {
|
|
516
516
|
table = new(object, this)
|
|
517
517
|
table.name = tablename
|
|
518
|
+
if dyna.ycdb
|
|
519
|
+
table.ycdb = true // Yandex Cloud version of DynamoDB
|
|
518
520
|
|
|
519
521
|
// info
|
|
520
522
|
//
|
|
@@ -650,7 +652,7 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
650
652
|
// Ensure that the table is ready before executing an operation. This returns an error tuple or
|
|
651
653
|
// false to proceed.
|
|
652
654
|
//
|
|
653
|
-
function preflightError(op) {
|
|
655
|
+
function preflightError(op, local result) {
|
|
654
656
|
if !dyna.aws
|
|
655
657
|
return (list(Error("DynaTable.".concat(op, ": not logged into AWS"))))
|
|
656
658
|
if !table.hashKey {
|
|
@@ -665,7 +667,7 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
665
667
|
// Make a dynamoDB key dictionary for the table using the specified primary key, which can be a
|
|
666
668
|
// tuple of hash/range or just a hash if only a hash is needed for this table.
|
|
667
669
|
//
|
|
668
|
-
|
|
670
|
+
table.makeDynKey = function makeDynKey(primaryKey, local hashValue, rangeValue, key) {
|
|
669
671
|
if tuple(primaryKey)
|
|
670
672
|
`(hashValue, rangeValue) = primaryKey
|
|
671
673
|
else
|
|
@@ -681,7 +683,7 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
681
683
|
//
|
|
682
684
|
// Get a record from the table with the specified hash value, and optional range value.
|
|
683
685
|
//
|
|
684
|
-
table.getRecord = closure getRecord(hashValue, rangeValue, local
|
|
686
|
+
table.getRecord = closure getRecord(hashValue, rangeValue, local params, pending) {
|
|
685
687
|
if preflightError(this)
|
|
686
688
|
return
|
|
687
689
|
params = {
|
|
@@ -706,7 +708,7 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
706
708
|
//
|
|
707
709
|
// Put a record in the table, replacing any existing record with the same key.
|
|
708
710
|
|
|
709
|
-
table.putRecord = closure putRecord(record, local
|
|
711
|
+
table.putRecord = closure putRecord(record, local params, pending) {
|
|
710
712
|
if preflightError(this)
|
|
711
713
|
return
|
|
712
714
|
params = {
|
|
@@ -735,13 +737,15 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
735
737
|
// set: [`(attribute, value)] // set attributes to values
|
|
736
738
|
// sum: [`(attribute, value)] // attributes += values
|
|
737
739
|
// diff: [`(attribute, value)] // attributes -= values
|
|
740
|
+
// add: [`(attribute, value)] // ADD(attributes, values) -- attrib need not exist
|
|
738
741
|
// remove: [attribute] // remove attributes from the record
|
|
739
742
|
// return: "all_old" | "all_new" | "updated_old" | "updated_new"
|
|
740
743
|
// // return the record as chosen, otherwise { }
|
|
741
744
|
// }
|
|
742
745
|
// The result is a standard result tuple `(error, record).
|
|
743
746
|
|
|
744
|
-
table.updateRecord = closure updateRecord(hashValue, rangeValue, options,
|
|
747
|
+
table.updateRecord = closure updateRecord(hashValue, rangeValue, options,
|
|
748
|
+
local error, params, actions, pending) {
|
|
745
749
|
if preflightError(this)
|
|
746
750
|
return
|
|
747
751
|
params = {
|
|
@@ -750,13 +754,10 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
750
754
|
params.Key = makeDynKey(list(hashValue, rangeValue))
|
|
751
755
|
if options.condition {
|
|
752
756
|
`(error) = dyna.conv.createKeyExpression(params, {
|
|
753
|
-
|
|
754
|
-
key: table.hashKey
|
|
755
|
-
"=": hashValue
|
|
756
|
-
}
|
|
757
|
+
ConditionExpression: options.condition
|
|
757
758
|
})
|
|
758
759
|
if error
|
|
759
|
-
return (list(Error("table.updateRecord:", error)))
|
|
760
|
+
return (list(Error("table.updateRecord condition:", error)))
|
|
760
761
|
}
|
|
761
762
|
dyna.conv.createUpdateExpression(params, options)
|
|
762
763
|
if options.return {
|
|
@@ -793,7 +794,8 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
793
794
|
// }
|
|
794
795
|
|
|
795
796
|
|
|
796
|
-
table.deleteRecord = closure deleteRecord(hashValue, rangeValue, options,
|
|
797
|
+
table.deleteRecord = closure deleteRecord(hashValue, rangeValue, options,
|
|
798
|
+
local params, pending) {
|
|
797
799
|
if preflightError(this)
|
|
798
800
|
return
|
|
799
801
|
params = {
|
|
@@ -802,13 +804,10 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
802
804
|
params.Key = makeDynKey(list(hashValue, rangeValue))
|
|
803
805
|
if options.condition {
|
|
804
806
|
`(error) = dyna.conv.createKeyExpression(params, {
|
|
805
|
-
|
|
806
|
-
key: table.hashKey
|
|
807
|
-
"=": hashValue
|
|
808
|
-
}
|
|
807
|
+
ConditionExpression: options.condition
|
|
809
808
|
})
|
|
810
809
|
if error
|
|
811
|
-
return (list(Error("table.deleteRecord:", error)))
|
|
810
|
+
return (list(Error("table.deleteRecord condition:", error)))
|
|
812
811
|
}
|
|
813
812
|
if options.return {
|
|
814
813
|
params.ReturnValues = {
|
|
@@ -869,7 +868,7 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
869
868
|
//
|
|
870
869
|
|
|
871
870
|
table.queryRecords = closure queryRecords(hashValue, options
|
|
872
|
-
local error,
|
|
871
|
+
local error, params, hashKey, op, expr, output, error)
|
|
873
872
|
{
|
|
874
873
|
if preflightError(this)
|
|
875
874
|
return
|
|
@@ -938,7 +937,7 @@ closure DynaTable(dyna, tablename, local table) {
|
|
|
938
937
|
//
|
|
939
938
|
|
|
940
939
|
table.scanRecords = closure scanRecords(options
|
|
941
|
-
local
|
|
940
|
+
local params, op, expr, output, error)
|
|
942
941
|
{
|
|
943
942
|
if preflightError(this)
|
|
944
943
|
return
|
|
@@ -994,14 +993,22 @@ closure DynamoDB(local dyna) {
|
|
|
994
993
|
|
|
995
994
|
// login
|
|
996
995
|
//
|
|
997
|
-
dyna.login = function login(creds) {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
996
|
+
dyna.login = function login(creds, local params) {
|
|
997
|
+
if !awsSDK
|
|
998
|
+
return (list(Error("DynamoDB.login: no AWS SDK available")))
|
|
999
|
+
params = { }
|
|
1000
|
+
if creds {
|
|
1001
|
+
params.region = creds.region
|
|
1002
|
+
params.credentials = {
|
|
1001
1003
|
accessKeyId: creds.keyID
|
|
1002
1004
|
secretAccessKey: creds.keySecret
|
|
1003
1005
|
}
|
|
1004
|
-
|
|
1006
|
+
if creds.dyna_endpoint {
|
|
1007
|
+
params.endpoint = creds.dyna_endpoint
|
|
1008
|
+
dyna.ycdb = true
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
dyna.aws = xnew(awsSDK.DynamoDB, params)
|
|
1005
1012
|
list(false, { ok: true })
|
|
1006
1013
|
}
|
|
1007
1014
|
|
|
@@ -1011,6 +1018,8 @@ closure DynamoDB(local dyna) {
|
|
|
1011
1018
|
// yet exist; see DynaTable for methods.
|
|
1012
1019
|
//
|
|
1013
1020
|
dyna.table = function table(name) {
|
|
1021
|
+
if !dyna.aws
|
|
1022
|
+
debuglog("DynamoDB.table: database not open:", name)
|
|
1014
1023
|
DynaTable(dyna, name)
|
|
1015
1024
|
}
|
|
1016
1025
|
|
|
@@ -1032,9 +1041,9 @@ closure DynamoDB(local dyna) {
|
|
|
1032
1041
|
dynexBatchGetRecords(dyna, request, options)
|
|
1033
1042
|
}
|
|
1034
1043
|
|
|
1035
|
-
//
|
|
1044
|
+
// batchWriteRecords
|
|
1036
1045
|
//
|
|
1037
|
-
dyna.batchWriteRecords = function
|
|
1046
|
+
dyna.batchWriteRecords = function loadBatchWriteRecords(request, options) {
|
|
1038
1047
|
require("./aws_dynextra.nlg")
|
|
1039
1048
|
dyna.batchWriteRecords = function bwr(request, options) {
|
|
1040
1049
|
dynexBatchWriteRecords(dyna, request, options)
|
|
@@ -1042,7 +1051,7 @@ closure DynamoDB(local dyna) {
|
|
|
1042
1051
|
dynexBatchWriteRecords(dyna, request, options)
|
|
1043
1052
|
}
|
|
1044
1053
|
|
|
1045
|
-
//
|
|
1054
|
+
// transactGetRecords
|
|
1046
1055
|
//
|
|
1047
1056
|
dyna.transactGetRecords = function loadTransactGetRecords(request, options) {
|
|
1048
1057
|
require("./aws_dynextra.nlg")
|
|
@@ -1052,6 +1061,16 @@ closure DynamoDB(local dyna) {
|
|
|
1052
1061
|
dynexTransactGetRecords(dyna, request, options)
|
|
1053
1062
|
}
|
|
1054
1063
|
|
|
1064
|
+
// transactWriteRecords
|
|
1065
|
+
//
|
|
1066
|
+
dyna.transactWriteRecords = function loadTransactWriteRecords(request, options) {
|
|
1067
|
+
require("./aws_dynextra.nlg")
|
|
1068
|
+
dyna.transactWriteRecords = function tgr(request, options) {
|
|
1069
|
+
dynexTransactWriteRecords(dyna, request, options)
|
|
1070
|
+
}
|
|
1071
|
+
dynexTransactWriteRecords(dyna, request, options)
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1055
1074
|
// finis
|
|
1056
1075
|
dyna
|
|
1057
1076
|
}
|
|
@@ -37,7 +37,7 @@ function dynexBatchGetRecords(dyna, request,
|
|
|
37
37
|
request = new(request) // allow local modifications
|
|
38
38
|
index = { }
|
|
39
39
|
for titem in request { // preflight all tables
|
|
40
|
-
tname = titem.table.
|
|
40
|
+
tname = titem.table.name
|
|
41
41
|
if index[tname]
|
|
42
42
|
return (Error("DynaTable.batchGetRecords: duplicate table in request:", tname))
|
|
43
43
|
`(error) = titem.table.info()
|
|
@@ -57,7 +57,7 @@ function dynexBatchGetRecords(dyna, request,
|
|
|
57
57
|
activity = false
|
|
58
58
|
for `(tname, titem) in index {
|
|
59
59
|
if titem.keys.length > 0 {
|
|
60
|
-
primary = titem.table.makeDynKey(titem.keys.
|
|
60
|
+
primary = titem.table.makeDynKey(titem.keys.shift())
|
|
61
61
|
if params.RequestItems[tname].Keys
|
|
62
62
|
params.RequestItems[tname].Keys.push(primary)
|
|
63
63
|
else
|
|
@@ -81,7 +81,7 @@ function dynexBatchGetRecords(dyna, request,
|
|
|
81
81
|
dyna.aws.batchGetItem(params, function(err, data) {
|
|
82
82
|
if err
|
|
83
83
|
debuglog("aws.batchGetItem failed", err)
|
|
84
|
-
pending.signal(err, data)
|
|
84
|
+
pending.signal(list(err, data))
|
|
85
85
|
})
|
|
86
86
|
`(err, response) = pending.wait()
|
|
87
87
|
for `(tname, table) in response.Responses
|
|
@@ -124,7 +124,8 @@ function dynexBatchGetRecords(dyna, request,
|
|
|
124
124
|
*
|
|
125
125
|
*/
|
|
126
126
|
|
|
127
|
-
closure dynexBatchWriteRecords(dyna, request,
|
|
127
|
+
closure dynexBatchWriteRecords(dyna, request,
|
|
128
|
+
local index, group, tname, batches, error, activity) {
|
|
128
129
|
if !dyna.aws
|
|
129
130
|
return (list(Error("DynaTable.batchWriteRecords: not logged into AWS")))
|
|
130
131
|
|
|
@@ -132,19 +133,18 @@ closure dynexBatchWriteRecords(dyna, request, local batches, error, activity) {
|
|
|
132
133
|
// addOp
|
|
133
134
|
// Add a put or delete operation to the parameters
|
|
134
135
|
//
|
|
135
|
-
function addOp(params, table, del, record, local request) {
|
|
136
|
+
function addOp(params, table, del, record, primary, local request) {
|
|
136
137
|
if del { // deleting a record
|
|
137
|
-
if tuple(record)
|
|
138
|
-
record = table.
|
|
139
|
-
|
|
140
|
-
request = { DeleteRequest: { Key: dyna.conv.recordNaanToDyn(record) } }
|
|
138
|
+
if !tuple(record)
|
|
139
|
+
record = list(record[table.hashKey], record[table.rangeKey])
|
|
140
|
+
request = { DeleteRequest: { Key: table.makeDynKey(record) } }
|
|
141
141
|
}
|
|
142
142
|
else // putting a record
|
|
143
143
|
request = { PutRequest: { Item: dyna.conv.recordNaanToDyn(record) } }
|
|
144
|
-
if params.RequestItems[table.
|
|
145
|
-
params.RequestItems[table.
|
|
144
|
+
if params.RequestItems[table.name]
|
|
145
|
+
params.RequestItems[table.name].push(request)
|
|
146
146
|
else
|
|
147
|
-
params.RequestItems[table.
|
|
147
|
+
params.RequestItems[table.name] = [request]
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// transform into batches
|
|
@@ -155,48 +155,68 @@ closure dynexBatchWriteRecords(dyna, request, local batches, error, activity) {
|
|
|
155
155
|
// request have no more entries.
|
|
156
156
|
//
|
|
157
157
|
request = new(request) // allow local modifications
|
|
158
|
+
index = { }
|
|
159
|
+
for group in request { // preflight all tables
|
|
160
|
+
tname = group.table.name
|
|
161
|
+
if index[tname]
|
|
162
|
+
return (Error("DynaTable.dynexBatchWriteRecords: duplicate table in request:", tname))
|
|
163
|
+
`(error) = group.table.info()
|
|
164
|
+
if error
|
|
165
|
+
return (Error("DynaTable.dynexBatchWriteRecords: table", tname, ":", error))
|
|
166
|
+
index[tname] = group
|
|
167
|
+
if group.put // ### in case these are xobjects
|
|
168
|
+
group.put = new(group.put) // new() doesn't deep clone them
|
|
169
|
+
if group.delete
|
|
170
|
+
group.delete = new(group.delete)
|
|
171
|
+
}
|
|
172
|
+
request = new(request) // allow local modifications
|
|
158
173
|
batches = []
|
|
159
174
|
activity = true
|
|
160
175
|
while activity
|
|
161
|
-
let (params, batchsize
|
|
176
|
+
let (params, batchsize) {
|
|
162
177
|
params = {
|
|
163
178
|
RequestItems: { }
|
|
164
179
|
}
|
|
165
180
|
batchsize = 0
|
|
166
181
|
while :fillbatch activity { // loop until no activity or batch full
|
|
167
182
|
activity = false
|
|
168
|
-
for
|
|
169
|
-
if
|
|
170
|
-
addOp(params, table, true,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
for group in request {
|
|
184
|
+
if group.delete.length > 0 {
|
|
185
|
+
addOp(params, group.table, true, group.delete.shift())
|
|
186
|
+
activity = true
|
|
187
|
+
++batchsize
|
|
188
|
+
}
|
|
189
|
+
if group.put.length > 0 {
|
|
190
|
+
addOp(params, group.table, false, group.put.shift())
|
|
191
|
+
activity = true
|
|
192
|
+
++batchsize
|
|
193
|
+
}
|
|
194
|
+
if batchsize >= 25
|
|
177
195
|
break :fillbatch // our batch is full
|
|
178
196
|
}
|
|
179
197
|
}
|
|
180
198
|
if batchsize > 0
|
|
181
199
|
batches.push(params)
|
|
182
200
|
} ()
|
|
183
|
-
asyncArray(batches,
|
|
201
|
+
asyncArray(batches, 1, closure bwr(params, local delayer, pending, err, response) {
|
|
184
202
|
delayer = dyna.conv.genBackoffDelayer()
|
|
185
203
|
loop {
|
|
186
204
|
pending = new(nonce)
|
|
187
|
-
dyna.aws.batchWriteItem(params,
|
|
205
|
+
dyna.aws.batchWriteItem(params, closure(err, data) {
|
|
188
206
|
if err
|
|
189
207
|
debuglog("aws.batchWriteItem failed", err)
|
|
190
|
-
pending.signal(err, data)
|
|
208
|
+
pending.signal(list(err, data))
|
|
191
209
|
})
|
|
192
210
|
`(err, response) = pending.wait()
|
|
193
211
|
if response.UnprocessedKeys
|
|
194
212
|
params.RequestItems = response.UnprocessedKeys // still more to do
|
|
195
213
|
else
|
|
196
214
|
break // total success or failure
|
|
215
|
+
debuglog("dynexBatchWriteRecords unprocessedKeys:", response.UnprocessedKeys)
|
|
197
216
|
if delayer() > dyna.timeout {
|
|
198
217
|
if !error // too slow
|
|
199
218
|
error = err
|
|
219
|
+
debuglog("dynexBatchWriteRecords timeout", error, err)
|
|
200
220
|
break
|
|
201
221
|
}
|
|
202
222
|
}
|
|
@@ -208,7 +228,6 @@ closure dynexBatchWriteRecords(dyna, request, local batches, error, activity) {
|
|
|
208
228
|
};
|
|
209
229
|
|
|
210
230
|
|
|
211
|
-
|
|
212
231
|
/*
|
|
213
232
|
* dynexTransactGetRecords
|
|
214
233
|
*
|
|
@@ -235,12 +254,12 @@ closure dynexTransactGetRecords(dyna, request,
|
|
|
235
254
|
request = new(request) // allow local modifications
|
|
236
255
|
index = { }
|
|
237
256
|
for titem in request { // preflight all tables
|
|
238
|
-
tname = titem.table.
|
|
257
|
+
tname = titem.table.name
|
|
239
258
|
if index[tname]
|
|
240
|
-
return (Error("DynaTable.
|
|
259
|
+
return (Error("DynaTable.transactGetRecords: duplicate table in request:", tname))
|
|
241
260
|
`(error) = titem.table.info()
|
|
242
261
|
if error
|
|
243
|
-
return (Error("DynaTable.
|
|
262
|
+
return (Error("DynaTable.transactGetRecords: table", tname, ":", error))
|
|
244
263
|
titem.data = []
|
|
245
264
|
index[tname] = titem
|
|
246
265
|
}
|
|
@@ -252,7 +271,7 @@ closure dynexTransactGetRecords(dyna, request,
|
|
|
252
271
|
params.TransactItems.push({
|
|
253
272
|
Get: {
|
|
254
273
|
TableName: tname
|
|
255
|
-
Key: makeDynKey(titem.keys.
|
|
274
|
+
Key: titem.table.makeDynKey(titem.keys.shift())
|
|
256
275
|
}
|
|
257
276
|
})
|
|
258
277
|
}
|
|
@@ -262,7 +281,7 @@ closure dynexTransactGetRecords(dyna, request,
|
|
|
262
281
|
dyna.aws.transactGetItems(params, function(err, data) {
|
|
263
282
|
if err
|
|
264
283
|
debuglog("aws.transactGetItems failed", err)
|
|
265
|
-
pending.signal(err, data)
|
|
284
|
+
pending.signal(list(err, data))
|
|
266
285
|
})
|
|
267
286
|
`(error, response) = pending.wait()
|
|
268
287
|
if error
|
|
@@ -277,6 +296,111 @@ closure dynexTransactGetRecords(dyna, request,
|
|
|
277
296
|
};
|
|
278
297
|
|
|
279
298
|
|
|
299
|
+
/*
|
|
300
|
+
* dynexTransactWriteRecords
|
|
301
|
+
*
|
|
302
|
+
* column positioning: // // !
|
|
303
|
+
* Write records to one or more tables using arrays of keys as a single transaction. The result is an
|
|
304
|
+
* error if anything failed or generic success if it worked. The request layout is as follows. Note
|
|
305
|
+
* that unlike the other dynex* calls, each table/key/operation item is separately specified.
|
|
306
|
+
*
|
|
307
|
+
* [
|
|
308
|
+
* {
|
|
309
|
+
* table: <DynaTable object> // table to act upon
|
|
310
|
+
* key: <hash-range tuple>
|
|
311
|
+
* put: {
|
|
312
|
+
* condition: <range-expression> // conditional expression
|
|
313
|
+
* item: <record-to-put>
|
|
314
|
+
* }
|
|
315
|
+
* update: {
|
|
316
|
+
* condition: <range-expression> // conditional expression
|
|
317
|
+
* set: [`(attribute, value)] // set attributes to values
|
|
318
|
+
* sum: [`(attribute, value)] // attributes += values
|
|
319
|
+
* diff: [`(attribute, value)] // attributes -= values
|
|
320
|
+
* add: [`(attribute, value)] // ADD(attributes, values) -- attrib need not exist
|
|
321
|
+
* remove: [attribute] // remove attributes from the record
|
|
322
|
+
* }
|
|
323
|
+
* delete: {
|
|
324
|
+
* condition: <range-expression> // conditional expression
|
|
325
|
+
* }
|
|
326
|
+
* check: {
|
|
327
|
+
* condition: <range-expression> // conditional expression
|
|
328
|
+
* return: "all_old" // optionally return record if condition fails
|
|
329
|
+
* }
|
|
330
|
+
* }
|
|
331
|
+
* { <next-item> }
|
|
332
|
+
* ]
|
|
333
|
+
* This returns a standard result tuple `(error, result). An error is only reported if we are
|
|
334
|
+
* unable to complete all operations.
|
|
335
|
+
*
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
closure dynexTransactWriteRecords(dyna, request,
|
|
339
|
+
local index, titem, tname, error, params, opset, spec, op, pending, response) {
|
|
340
|
+
if !dyna.aws
|
|
341
|
+
return (list(Error("DynaTable.transactWriteRecords: not logged into AWS")))
|
|
342
|
+
request = new(request) // allow local modifications
|
|
343
|
+
index = { }
|
|
344
|
+
for titem in request { // preflight all tables
|
|
345
|
+
tname = titem.table.name
|
|
346
|
+
if !index[tname] {
|
|
347
|
+
`(error) = titem.table.info()
|
|
348
|
+
if error
|
|
349
|
+
return (Error("DynaTable.transactWriteRecords: table", tname, ":", error))
|
|
350
|
+
index[tname] = titem
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
params = {
|
|
354
|
+
TransactItems: []
|
|
355
|
+
}
|
|
356
|
+
for titem in request {
|
|
357
|
+
opset = {
|
|
358
|
+
TableName: titem.table.name
|
|
359
|
+
Key: titem.table.makeDynKey(titem.key)
|
|
360
|
+
}
|
|
361
|
+
if titem.check {
|
|
362
|
+
spec = titem.check
|
|
363
|
+
op = `ConditionCheck
|
|
364
|
+
if spec.return
|
|
365
|
+
opset.ReturnValues = "ALL_OLD"
|
|
366
|
+
} else if titem.put {
|
|
367
|
+
spec = titem.put
|
|
368
|
+
op = `Put
|
|
369
|
+
opset.Item = dyna.conv.recordNaanToDyn(spec.item)
|
|
370
|
+
opset.Key = undefined // key must be in item
|
|
371
|
+
} else if titem.update {
|
|
372
|
+
spec = titem.update
|
|
373
|
+
op = `Update
|
|
374
|
+
dyna.conv.createUpdateExpression(opset, spec)
|
|
375
|
+
} else if titem.delete {
|
|
376
|
+
spec = titem.delete
|
|
377
|
+
op = `Delete
|
|
378
|
+
}
|
|
379
|
+
if spec.condition {
|
|
380
|
+
`(error) = dyna.conv.createKeyExpression(opset, {
|
|
381
|
+
ConditionExpression: spec.condition
|
|
382
|
+
})
|
|
383
|
+
if error
|
|
384
|
+
return (list(Error("DynaTable.transactWriteRecords condition:", error)))
|
|
385
|
+
}
|
|
386
|
+
titem = { }
|
|
387
|
+
titem[op] = opset
|
|
388
|
+
params.TransactItems.push(titem)
|
|
389
|
+
}
|
|
390
|
+
pending = new(nonce)
|
|
391
|
+
dyna.aws.transactWriteItems(params, function(err, data) {
|
|
392
|
+
if err
|
|
393
|
+
debuglog("aws.transactWriteItems failed", err)
|
|
394
|
+
pending.signal(list(err, data))
|
|
395
|
+
})
|
|
396
|
+
`(error, response) = pending.wait()
|
|
397
|
+
if error
|
|
398
|
+
list(error)
|
|
399
|
+
else
|
|
400
|
+
list(false, response)
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
|
|
280
404
|
/*
|
|
281
405
|
* dynexInit
|
|
282
406
|
*
|
|
@@ -285,7 +409,8 @@ closure dynexTransactGetRecords(dyna, request,
|
|
|
285
409
|
*/
|
|
286
410
|
|
|
287
411
|
function dynexInit(local manifest) {
|
|
288
|
-
manifest = `(dynexBatchGetRecords, dynexBatchWriteRecords, dynexTransactGetRecords,
|
|
412
|
+
manifest = `(dynexBatchGetRecords, dynexBatchWriteRecords, dynexTransactGetRecords,
|
|
413
|
+
dynexTransactWriteRecords, dynexInit)
|
|
289
414
|
|
|
290
415
|
Naan.module.build(module.id, "aws_dynextra", function(modobj, compobj) {
|
|
291
416
|
compobj.manifest = manifest
|
|
@@ -46,10 +46,8 @@ closure Lambda(local lamb) {
|
|
|
46
46
|
params.Qualifier = qualifier
|
|
47
47
|
pending = new(nonce)
|
|
48
48
|
lamb.aws.getFunction(params, function(error, data) {
|
|
49
|
-
if error
|
|
50
|
-
|
|
51
|
-
debuglog("aws.getFunction failed", error)
|
|
52
|
-
}
|
|
49
|
+
if error
|
|
50
|
+
ErrorDebuglog("aws.getFunction failed", error)
|
|
53
51
|
pending.signal(list(error, data))
|
|
54
52
|
})
|
|
55
53
|
pending.wait()
|
|
@@ -69,10 +67,8 @@ closure Lambda(local lamb) {
|
|
|
69
67
|
}
|
|
70
68
|
pending = new(nonce)
|
|
71
69
|
lamb.aws.updateFunctionCode(params, function(error, data) {
|
|
72
|
-
if error
|
|
73
|
-
|
|
74
|
-
debuglog("aws.updateFunctionCode failed", error)
|
|
75
|
-
}
|
|
70
|
+
if error
|
|
71
|
+
ErrorDebuglog("aws.updateFunctionCode failed", error)
|
|
76
72
|
pending.signal(list(error, data))
|
|
77
73
|
})
|
|
78
74
|
pending.wait()
|