1 | var Big = require('big.js'),
|
2 | db = require('../db'),
|
3 | conditionParser = require('../db/conditionParser'),
|
4 | projectionParser = require('../db/projectionParser'),
|
5 | updateParser = require('../db/updateParser')
|
6 |
|
7 | exports.checkTypes = checkTypes
|
8 | exports.checkValidations = checkValidations
|
9 | exports.toLowerFirst = toLowerFirst
|
10 | exports.findDuplicate = findDuplicate
|
11 | exports.validateAttributeValue = validateAttributeValue
|
12 | exports.validateConditions = validateConditions
|
13 | exports.validateAttributeConditions = validateAttributeConditions
|
14 | exports.validateExpressionParams = validateExpressionParams
|
15 | exports.validateExpressions = validateExpressions
|
16 | exports.convertKeyCondition = convertKeyCondition
|
17 |
|
18 | function checkTypes(data, types) {
|
19 | var key
|
20 | for (key in data) {
|
21 |
|
22 | if (!types[key] || data[key] == null)
|
23 | delete data[key]
|
24 | }
|
25 |
|
26 | return Object.keys(types).reduce(function(newData, key) {
|
27 | var val = checkType(data[key], types[key])
|
28 | if (val != null) newData[key] = val
|
29 | return newData
|
30 | }, {})
|
31 |
|
32 | function typeError(msg) {
|
33 | var err = new Error(msg)
|
34 | err.statusCode = 400
|
35 | err.body = {
|
36 | __type: 'com.amazon.coral.service#SerializationException',
|
37 | Message: msg,
|
38 | }
|
39 | return err
|
40 | }
|
41 |
|
42 | function checkType(val, type) {
|
43 | if (val == null) return null
|
44 | var children = type.children
|
45 | if (typeof children == 'string') children = {type: children}
|
46 | if (type.type) type = type.type
|
47 | var subtypeMatch = type.match(/(.+?)<(.+)>$/), subtype
|
48 | if (subtypeMatch != null) {
|
49 | type = subtypeMatch[1]
|
50 | subtype = subtypeMatch[2]
|
51 | }
|
52 |
|
53 | if (type == 'AttrStruct') {
|
54 | return checkType(val, {
|
55 | type: subtype + '<AttributeValue>',
|
56 | children: {
|
57 | S: 'String',
|
58 | B: 'Blob',
|
59 | N: 'String',
|
60 | BOOL: 'Boolean',
|
61 | NULL: 'Boolean',
|
62 | BS: {
|
63 | type: 'List',
|
64 | children: 'Blob',
|
65 | },
|
66 | NS: {
|
67 | type: 'List',
|
68 | children: 'String',
|
69 | },
|
70 | SS: {
|
71 | type: 'List',
|
72 | children: 'String',
|
73 | },
|
74 | L: {
|
75 | type: 'List',
|
76 | children: 'AttrStruct<ValueStruct>',
|
77 | },
|
78 | M: {
|
79 | type: 'Map<AttributeValue>',
|
80 | children: 'AttrStruct<ValueStruct>',
|
81 | },
|
82 | },
|
83 | })
|
84 | }
|
85 |
|
86 | switch (type) {
|
87 | case 'Boolean':
|
88 | switch (typeof val) {
|
89 | case 'number':
|
90 | throw typeError((val % 1 === 0 ? 'NUMBER_VALUE' : 'DECIMAL_VALUE') + ' cannot be converted to ' + type)
|
91 | case 'string':
|
92 |
|
93 | val = val.toUpperCase()
|
94 | if (~['TRUE', '1', 'YES'].indexOf(val)) {
|
95 | val = true
|
96 | } else if (~['FALSE', '0', 'NO'].indexOf(val)) {
|
97 | val = false
|
98 | } else {
|
99 | throw typeError('Unexpected token received from parser')
|
100 | }
|
101 | break
|
102 | case 'object':
|
103 | if (Array.isArray(val)) throw typeError('Unrecognized collection type class java.lang.' + type)
|
104 | throw typeError('Start of structure or map found where not expected')
|
105 | }
|
106 | return val
|
107 | case 'Short':
|
108 | case 'Integer':
|
109 | case 'Long':
|
110 | case 'Double':
|
111 | switch (typeof val) {
|
112 | case 'boolean':
|
113 | throw typeError((val ? 'TRUE_VALUE' : 'FALSE_VALUE') + ' cannot be converted to ' + type)
|
114 | case 'number':
|
115 | if (type != 'Double') val = Math.floor(val)
|
116 | break
|
117 | case 'string':
|
118 | throw typeError('STRING_VALUE cannot be converted to ' + type)
|
119 | case 'object':
|
120 | if (Array.isArray(val)) throw typeError('Unrecognized collection type class java.lang.' + type)
|
121 | throw typeError('Start of structure or map found where not expected')
|
122 | }
|
123 | return val
|
124 | case 'String':
|
125 | switch (typeof val) {
|
126 | case 'boolean':
|
127 | throw typeError((val ? 'TRUE_VALUE' : 'FALSE_VALUE') + ' cannot be converted to ' + type)
|
128 | case 'number':
|
129 | throw typeError((val % 1 === 0 ? 'NUMBER_VALUE' : 'DECIMAL_VALUE') + ' cannot be converted to ' + type)
|
130 | case 'object':
|
131 | if (Array.isArray(val)) throw typeError('Unrecognized collection type class java.lang.' + type)
|
132 | throw typeError('Start of structure or map found where not expected')
|
133 | }
|
134 | return val
|
135 | case 'Blob':
|
136 | switch (typeof val) {
|
137 | case 'boolean':
|
138 | case 'number':
|
139 | throw typeError('only base-64-encoded strings are convertible to bytes')
|
140 | case 'object':
|
141 | if (Array.isArray(val)) throw typeError('Unrecognized collection type class java.nio.ByteBuffer')
|
142 | throw typeError('Start of structure or map found where not expected')
|
143 | }
|
144 | if (val.length % 4)
|
145 | throw typeError('Base64 encoded length is expected a multiple of 4 bytes but found: ' + val.length)
|
146 |
|
147 | if (Buffer.from(val, 'base64').toString('base64') != val)
|
148 | throw typeError('Invalid last non-pad Base64 character dectected')
|
149 | return val
|
150 | case 'List':
|
151 | switch (typeof val) {
|
152 | case 'boolean':
|
153 | case 'number':
|
154 | case 'string':
|
155 | throw typeError('Unexpected field type')
|
156 | case 'object':
|
157 | if (!Array.isArray(val)) throw typeError('Start of structure or map found where not expected')
|
158 | }
|
159 | return val.map(function(child) { return checkType(child, children) })
|
160 | case 'ParameterizedList':
|
161 | switch (typeof val) {
|
162 | case 'boolean':
|
163 | case 'number':
|
164 | case 'string':
|
165 | throw typeError('sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class')
|
166 | case 'object':
|
167 | if (!Array.isArray(val)) throw typeError('Start of structure or map found where not expected')
|
168 | }
|
169 | return val.map(function(child) { return checkType(child, children) })
|
170 | case 'ParameterizedMap':
|
171 | switch (typeof val) {
|
172 | case 'boolean':
|
173 | case 'number':
|
174 | case 'string':
|
175 | throw typeError('sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class')
|
176 | case 'object':
|
177 | if (Array.isArray(val)) throw typeError('Unrecognized collection type java.util.Map<java.lang.String, com.amazonaws.dynamodb.v20120810.AttributeValue>')
|
178 | }
|
179 | return Object.keys(val).reduce(function(newVal, key) {
|
180 | newVal[key] = checkType(val[key], children)
|
181 | return newVal
|
182 | }, {})
|
183 | case 'Map':
|
184 | switch (typeof val) {
|
185 | case 'boolean':
|
186 | case 'number':
|
187 | case 'string':
|
188 | throw typeError('Unexpected field type')
|
189 | case 'object':
|
190 | if (Array.isArray(val)) {
|
191 | throw typeError('Unrecognized collection type java.util.Map<java.lang.String, ' +
|
192 | (~subtype.indexOf('.') ? subtype : 'com.amazonaws.dynamodb.v20120810.' + subtype) + '>')
|
193 | }
|
194 | }
|
195 | return Object.keys(val).reduce(function(newVal, key) {
|
196 | newVal[key] = checkType(val[key], children)
|
197 | return newVal
|
198 | }, {})
|
199 | case 'ValueStruct':
|
200 | switch (typeof val) {
|
201 | case 'boolean':
|
202 | case 'number':
|
203 | case 'string':
|
204 | throw typeError('Unexpected value type in payload')
|
205 | case 'object':
|
206 | if (Array.isArray(val)) throw typeError('Unrecognized collection type class com.amazonaws.dynamodb.v20120810.' + subtype)
|
207 | }
|
208 | return checkTypes(val, children)
|
209 | case 'FieldStruct':
|
210 | switch (typeof val) {
|
211 | case 'boolean':
|
212 | case 'number':
|
213 | case 'string':
|
214 | throw typeError('Unexpected field type')
|
215 | case 'object':
|
216 | if (Array.isArray(val)) throw typeError('Unrecognized collection type class com.amazonaws.dynamodb.v20120810.' + subtype)
|
217 | }
|
218 | return checkTypes(val, children)
|
219 | default:
|
220 | throw new Error('Unknown type: ' + type)
|
221 | }
|
222 | }
|
223 | }
|
224 |
|
225 | var validateFns = {}
|
226 |
|
227 | function checkValidations(data, validations, custom, store) {
|
228 | var attr, msg, errors = []
|
229 |
|
230 | for (attr in validations) {
|
231 | if (validations[attr].required && data[attr] == null) {
|
232 | throw db.validationError('The parameter \'' + attr + '\' is required but was not present in the request')
|
233 | }
|
234 | if (validations[attr].tableName) {
|
235 | msg = validateTableName(attr, data[attr])
|
236 | if (msg) throw db.validationError(msg)
|
237 | }
|
238 | }
|
239 |
|
240 | function checkNonRequireds(data, types, parent) {
|
241 | for (attr in types) {
|
242 | checkNonRequired(attr, data[attr], types[attr], parent)
|
243 | }
|
244 | }
|
245 |
|
246 | checkNonRequireds(data, validations)
|
247 |
|
248 | function checkNonRequired(attr, data, validations, parent) {
|
249 | if (validations == null || typeof validations != 'object') return
|
250 | for (var validation in validations) {
|
251 | if (errors.length >= 10) return
|
252 | if (~['type', 'required', 'tableName'].indexOf(validation)) continue
|
253 | if (validation != 'notNull' && data == null) continue
|
254 | if (validation == 'children') {
|
255 | if (/List$/.test(validations.type)) {
|
256 | for (var i = 0; i < data.length; i++) {
|
257 | checkNonRequired('member', data[i], validations.children,
|
258 | (parent ? parent + '.' : '') + toLowerFirst(attr) + '.' + (i + 1))
|
259 | }
|
260 | continue
|
261 | } else if (/Map/.test(validations.type)) {
|
262 | Object.keys(data).forEach(function(key) {
|
263 | checkNonRequired('member', data[key], validations.children,
|
264 | (parent ? parent + '.' : '') + toLowerFirst(attr) + '.' + key)
|
265 | })
|
266 | continue
|
267 | }
|
268 | checkNonRequireds(data, validations.children, (parent ? parent + '.' : '') + toLowerFirst(attr))
|
269 | continue
|
270 | }
|
271 | validateFns[validation](parent, attr, validations[validation], data, errors)
|
272 | }
|
273 | }
|
274 |
|
275 | if (errors.length)
|
276 | throw db.validationError(errors.length + ' validation error' + (errors.length > 1 ? 's' : '') + ' detected: ' + errors.join('; '))
|
277 |
|
278 | if (custom) {
|
279 | msg = custom(data, store)
|
280 | if (msg) throw db.validationError(msg)
|
281 | }
|
282 | }
|
283 |
|
284 | validateFns.notNull = function(parent, key, val, data, errors) {
|
285 | validate(data != null, 'Member must not be null', data, parent, key, errors)
|
286 | }
|
287 | validateFns.greaterThanOrEqual = function(parent, key, val, data, errors) {
|
288 | validate(data >= val, 'Member must have value greater than or equal to ' + val, data, parent, key, errors)
|
289 | }
|
290 | validateFns.lessThanOrEqual = function(parent, key, val, data, errors) {
|
291 | validate(data <= val, 'Member must have value less than or equal to ' + val, data, parent, key, errors)
|
292 | }
|
293 | validateFns.regex = function(parent, key, pattern, data, errors) {
|
294 | validate(RegExp('^' + pattern + '$').test(data), 'Member must satisfy regular expression pattern: ' + pattern, data, parent, key, errors)
|
295 | }
|
296 | validateFns.lengthGreaterThanOrEqual = function(parent, key, val, data, errors) {
|
297 | var length = (typeof data == 'object' && !Array.isArray(data)) ? Object.keys(data).length : data.length
|
298 | validate(length >= val, 'Member must have length greater than or equal to ' + val, data, parent, key, errors)
|
299 | }
|
300 | validateFns.lengthLessThanOrEqual = function(parent, key, val, data, errors) {
|
301 | var length = (typeof data == 'object' && !Array.isArray(data)) ? Object.keys(data).length : data.length
|
302 | validate(length <= val, 'Member must have length less than or equal to ' + val, data, parent, key, errors)
|
303 | }
|
304 | validateFns.enum = function(parent, key, val, data, errors) {
|
305 | validate(~val.indexOf(data), 'Member must satisfy enum value set: [' + val.join(', ') + ']', data, parent, key, errors)
|
306 | }
|
307 | validateFns.keys = function(parent, key, val, data, errors) {
|
308 | Object.keys(data).forEach(function(mapKey) {
|
309 | try {
|
310 | Object.keys(val).forEach(function(validation) {
|
311 | validateFns[validation]('', '', val[validation], mapKey, [])
|
312 | })
|
313 | } catch (e) {
|
314 | var msgs = Object.keys(val).map(function(validation) {
|
315 | if (validation == 'lengthGreaterThanOrEqual')
|
316 | return 'Member must have length greater than or equal to ' + val[validation]
|
317 | if (validation == 'lengthLessThanOrEqual')
|
318 | return 'Member must have length less than or equal to ' + val[validation]
|
319 | if (validation == 'regex')
|
320 | return 'Member must satisfy regular expression pattern: ' + val[validation]
|
321 | })
|
322 | validate(false, 'Map keys must satisfy constraint: [' + msgs.join(', ') + ']', data, parent, key, errors)
|
323 | }
|
324 | })
|
325 | }
|
326 | validateFns.values = function(parent, key, val, data, errors) {
|
327 | Object.keys(data).forEach(function(mapKey) {
|
328 | try {
|
329 | Object.keys(val).forEach(function(validation) {
|
330 | validateFns[validation]('', '', val[validation], data[mapKey], [])
|
331 | })
|
332 | } catch (e) {
|
333 | var msgs = Object.keys(val).map(function(validation) {
|
334 | if (validation == 'lengthGreaterThanOrEqual')
|
335 | return 'Member must have length greater than or equal to ' + val[validation]
|
336 | if (validation == 'lengthLessThanOrEqual')
|
337 | return 'Member must have length less than or equal to ' + val[validation]
|
338 | })
|
339 | validate(false, 'Map value must satisfy constraint: [' + msgs.join(', ') + ']', data, parent, key, errors)
|
340 | }
|
341 | })
|
342 | }
|
343 |
|
344 | function validate(predicate, msg, data, parent, key, errors) {
|
345 | if (predicate) return
|
346 | var value = valueStr(data)
|
347 | if (value != 'null') value = '\'' + value + '\''
|
348 | parent = parent ? parent + '.' : ''
|
349 | errors.push('Value ' + value + ' at \'' + parent + toLowerFirst(key) + '\' failed to satisfy constraint: ' + msg)
|
350 | }
|
351 |
|
352 | function validateTableName(key, val) {
|
353 | if (val == null) return null
|
354 | if (val.length < 3 || val.length > 255)
|
355 | return key + ' must be at least 3 characters long and at most 255 characters long'
|
356 | }
|
357 |
|
358 | function toLowerFirst(str) {
|
359 | return str[0].toLowerCase() + str.slice(1)
|
360 | }
|
361 |
|
362 | function validateAttributeValue(value) {
|
363 | var types = Object.keys(value), msg, i, attr
|
364 | if (!types.length)
|
365 | return 'Supplied AttributeValue is empty, must contain exactly one of the supported datatypes'
|
366 |
|
367 | for (var type in value) {
|
368 | if (type == 'N') {
|
369 | msg = checkNum(type, value)
|
370 | if (msg) return msg
|
371 | }
|
372 |
|
373 | if (type == 'B' && !value[type])
|
374 | return 'One or more parameter values were invalid: An AttributeValue may not contain a null or empty binary type.'
|
375 |
|
376 | if (type == 'S' && !value[type])
|
377 | return 'One or more parameter values were invalid: An AttributeValue may not contain an empty string'
|
378 |
|
379 | if (type == 'NULL' && !value[type])
|
380 | return 'One or more parameter values were invalid: Null attribute value types must have the value of true'
|
381 |
|
382 | if (type == 'SS' && !value[type].length)
|
383 | return 'One or more parameter values were invalid: An string set may not be empty'
|
384 |
|
385 | if (type == 'NS' && !value[type].length)
|
386 | return 'One or more parameter values were invalid: An number set may not be empty'
|
387 |
|
388 | if (type == 'BS' && !value[type].length)
|
389 | return 'One or more parameter values were invalid: Binary sets should not be empty'
|
390 |
|
391 | if (type == 'SS' && value[type].some(function(x) { return !x }))
|
392 | return 'One or more parameter values were invalid: An string set may not have a empty string as a member'
|
393 |
|
394 | if (type == 'BS' && value[type].some(function(x) { return !x }))
|
395 | return 'One or more parameter values were invalid: Binary sets may not contain null or empty values'
|
396 |
|
397 | if (type == 'NS') {
|
398 | for (i = 0; i < value[type].length; i++) {
|
399 | msg = checkNum(i, value[type])
|
400 | if (msg) return msg
|
401 | }
|
402 | }
|
403 |
|
404 | if (type == 'SS' && findDuplicate(value[type]))
|
405 | return 'One or more parameter values were invalid: Input collection ' + valueStr(value[type]) + ' contains duplicates.'
|
406 |
|
407 | if (type == 'NS' && findDuplicate(value[type]))
|
408 | return 'Input collection contains duplicates'
|
409 |
|
410 | if (type == 'BS' && findDuplicate(value[type]))
|
411 | return 'One or more parameter values were invalid: Input collection ' + valueStr(value[type]) + 'of type BS contains duplicates.'
|
412 |
|
413 | if (type == 'M') {
|
414 | for (attr in value[type]) {
|
415 | msg = validateAttributeValue(value[type][attr])
|
416 | if (msg) return msg
|
417 | }
|
418 | }
|
419 |
|
420 | if (type == 'L') {
|
421 | for (i = 0; i < value[type].length; i++) {
|
422 | msg = validateAttributeValue(value[type][i])
|
423 | if (msg) return msg
|
424 | }
|
425 | }
|
426 | }
|
427 |
|
428 | if (types.length > 1)
|
429 | return 'Supplied AttributeValue has more than one datatypes set, must contain exactly one of the supported datatypes'
|
430 | }
|
431 |
|
432 | function checkNum(attr, obj) {
|
433 | if (!obj[attr])
|
434 | return 'The parameter cannot be converted to a numeric value'
|
435 |
|
436 | var bigNum
|
437 | try {
|
438 | bigNum = new Big(obj[attr])
|
439 | } catch (e) {
|
440 | return 'The parameter cannot be converted to a numeric value: ' + obj[attr]
|
441 | }
|
442 | if (bigNum.e > 125)
|
443 | return 'Number overflow. Attempting to store a number with magnitude larger than supported range'
|
444 | else if (bigNum.e < -130)
|
445 | return 'Number underflow. Attempting to store a number with magnitude smaller than supported range'
|
446 | else if (bigNum.c.length > 38)
|
447 | return 'Attempting to store more than 38 significant digits in a Number'
|
448 |
|
449 | obj[attr] = bigNum.toFixed()
|
450 | }
|
451 |
|
452 | function valueStr(data) {
|
453 | return data == null ? 'null' : Array.isArray(data) ? '[' + data.map(valueStr).join(', ') + ']' :
|
454 | typeof data == 'object' ? JSON.stringify(data) : data
|
455 | }
|
456 |
|
457 | function findDuplicate(arr) {
|
458 | if (!arr) return null
|
459 | var vals = Object.create(null)
|
460 | for (var i = 0; i < arr.length; i++) {
|
461 | if (vals[arr[i]]) return arr[i]
|
462 | vals[arr[i]] = true
|
463 | }
|
464 | }
|
465 |
|
466 | function validateAttributeConditions(data) {
|
467 | for (var key in data.Expected) {
|
468 | var condition = data.Expected[key]
|
469 |
|
470 | if ('AttributeValueList' in condition && 'Value' in condition)
|
471 | return 'One or more parameter values were invalid: ' +
|
472 | 'Value and AttributeValueList cannot be used together for Attribute: ' + key
|
473 |
|
474 | if ('ComparisonOperator' in condition) {
|
475 | if ('Exists' in condition)
|
476 | return 'One or more parameter values were invalid: ' +
|
477 | 'Exists and ComparisonOperator cannot be used together for Attribute: ' + key
|
478 |
|
479 | if (condition.ComparisonOperator != 'NULL' && condition.ComparisonOperator != 'NOT_NULL' &&
|
480 | !('AttributeValueList' in condition) && !('Value' in condition))
|
481 | return 'One or more parameter values were invalid: ' +
|
482 | 'Value or AttributeValueList must be used with ComparisonOperator: ' + condition.ComparisonOperator +
|
483 | ' for Attribute: ' + key
|
484 |
|
485 | var values = condition.AttributeValueList ?
|
486 | condition.AttributeValueList.length : condition.Value ? 1 : 0
|
487 | var validAttrCount = false
|
488 |
|
489 | switch (condition.ComparisonOperator) {
|
490 | case 'EQ':
|
491 | case 'NE':
|
492 | case 'LE':
|
493 | case 'LT':
|
494 | case 'GE':
|
495 | case 'GT':
|
496 | case 'CONTAINS':
|
497 | case 'NOT_CONTAINS':
|
498 | case 'BEGINS_WITH':
|
499 | if (values === 1) validAttrCount = true
|
500 | break
|
501 | case 'NOT_NULL':
|
502 | case 'NULL':
|
503 | if (values === 0) validAttrCount = true
|
504 | break
|
505 | case 'IN':
|
506 | if (values > 0) validAttrCount = true
|
507 | break
|
508 | case 'BETWEEN':
|
509 | if (values === 2) validAttrCount = true
|
510 | break
|
511 | }
|
512 | if (!validAttrCount)
|
513 | return 'One or more parameter values were invalid: ' +
|
514 | 'Invalid number of argument(s) for the ' + condition.ComparisonOperator + ' ComparisonOperator'
|
515 |
|
516 | if (condition.AttributeValueList && condition.AttributeValueList.length) {
|
517 | var type = Object.keys(condition.AttributeValueList[0])[0]
|
518 | if (condition.AttributeValueList.some(function(attr) { return Object.keys(attr)[0] != type })) {
|
519 | return 'One or more parameter values were invalid: AttributeValues inside AttributeValueList must be of same type'
|
520 | }
|
521 | if (condition.ComparisonOperator == 'BETWEEN' && db.compare('GT', condition.AttributeValueList[0], condition.AttributeValueList[1])) {
|
522 | return 'The BETWEEN condition was provided a range where the lower bound is greater than the upper bound'
|
523 | }
|
524 | }
|
525 | } else if ('AttributeValueList' in condition) {
|
526 | return 'One or more parameter values were invalid: ' +
|
527 | 'AttributeValueList can only be used with a ComparisonOperator for Attribute: ' + key
|
528 | } else {
|
529 | var exists = condition.Exists == null || condition.Exists
|
530 | if (exists && condition.Value == null)
|
531 | return 'One or more parameter values were invalid: ' +
|
532 | 'Value must be provided when Exists is ' +
|
533 | (condition.Exists == null ? 'null' : condition.Exists) +
|
534 | ' for Attribute: ' + key
|
535 | else if (!exists && condition.Value != null)
|
536 | return 'One or more parameter values were invalid: ' +
|
537 | 'Value cannot be used when Exists is false for Attribute: ' + key
|
538 | if (condition.Value != null) {
|
539 | var msg = validateAttributeValue(condition.Value)
|
540 | if (msg) return msg
|
541 | }
|
542 | }
|
543 | }
|
544 | }
|
545 |
|
546 | function validateConditions(conditions) {
|
547 | var lengths = {
|
548 | NULL: 0,
|
549 | NOT_NULL: 0,
|
550 | EQ: 1,
|
551 | NE: 1,
|
552 | LE: 1,
|
553 | LT: 1,
|
554 | GE: 1,
|
555 | GT: 1,
|
556 | CONTAINS: 1,
|
557 | NOT_CONTAINS: 1,
|
558 | BEGINS_WITH: 1,
|
559 | IN: [1],
|
560 | BETWEEN: 2,
|
561 | }
|
562 | var types = {
|
563 | EQ: ['S', 'N', 'B', 'SS', 'NS', 'BS'],
|
564 | NE: ['S', 'N', 'B', 'SS', 'NS', 'BS'],
|
565 | LE: ['S', 'N', 'B'],
|
566 | LT: ['S', 'N', 'B'],
|
567 | GE: ['S', 'N', 'B'],
|
568 | GT: ['S', 'N', 'B'],
|
569 | CONTAINS: ['S', 'N', 'B'],
|
570 | NOT_CONTAINS: ['S', 'N', 'B'],
|
571 | BEGINS_WITH: ['S', 'B'],
|
572 | IN: ['S', 'N', 'B'],
|
573 | BETWEEN: ['S', 'N', 'B'],
|
574 | }
|
575 | for (var key in conditions) {
|
576 | var comparisonOperator = conditions[key].ComparisonOperator
|
577 | var attrValList = conditions[key].AttributeValueList || []
|
578 | for (var i = 0; i < attrValList.length; i++) {
|
579 | var msg = validateAttributeValue(attrValList[i])
|
580 | if (msg) return msg
|
581 | }
|
582 |
|
583 | if ((typeof lengths[comparisonOperator] == 'number' && attrValList.length != lengths[comparisonOperator]) ||
|
584 | (attrValList.length < lengths[comparisonOperator][0] || attrValList.length > lengths[comparisonOperator][1]))
|
585 | return 'One or more parameter values were invalid: Invalid number of argument(s) for the ' +
|
586 | comparisonOperator + ' ComparisonOperator'
|
587 |
|
588 | if (attrValList.length) {
|
589 | var type = Object.keys(attrValList[0])[0]
|
590 | if (attrValList.some(function(attr) { return Object.keys(attr)[0] != type })) {
|
591 | return 'One or more parameter values were invalid: AttributeValues inside AttributeValueList must be of same type'
|
592 | }
|
593 | }
|
594 |
|
595 | if (types[comparisonOperator]) {
|
596 | for (i = 0; i < attrValList.length; i++) {
|
597 | if (!~types[comparisonOperator].indexOf(Object.keys(attrValList[i])[0]))
|
598 | return 'One or more parameter values were invalid: ComparisonOperator ' + comparisonOperator +
|
599 | ' is not valid for ' + Object.keys(attrValList[i])[0] + ' AttributeValue type'
|
600 | }
|
601 | }
|
602 |
|
603 | if (comparisonOperator == 'BETWEEN' && db.compare('GT', attrValList[0], attrValList[1])) {
|
604 | return 'The BETWEEN condition was provided a range where the lower bound is greater than the upper bound'
|
605 | }
|
606 | }
|
607 | }
|
608 |
|
609 | function validateExpressionParams(data, expressions, nonExpressions) {
|
610 | var exprParams = expressions.filter(function(expr) { return data[expr] != null })
|
611 |
|
612 | if (exprParams.length) {
|
613 |
|
614 | if (data.KeyConditions != null && data.KeyConditionExpression == null) {
|
615 | nonExpressions.splice(nonExpressions.indexOf('KeyConditions'), 1)
|
616 | }
|
617 | var nonExprParams = nonExpressions.filter(function(expr) { return data[expr] != null })
|
618 | if (nonExprParams.length) {
|
619 | return 'Can not use both expression and non-expression parameters in the same request: ' +
|
620 | 'Non-expression parameters: {' + nonExprParams.join(', ') + '} ' +
|
621 | 'Expression parameters: {' + exprParams.join(', ') + '}'
|
622 | }
|
623 | }
|
624 |
|
625 | if (data.ExpressionAttributeNames != null && !exprParams.length) {
|
626 | return 'ExpressionAttributeNames can only be specified when using expressions'
|
627 | }
|
628 |
|
629 | var valExprs = expressions.filter(function(expr) { return expr != 'ProjectionExpression' })
|
630 | if (valExprs.length && data.ExpressionAttributeValues != null &&
|
631 | valExprs.every(function(expr) { return data[expr] == null })) {
|
632 | return 'ExpressionAttributeValues can only be specified when using expressions: ' +
|
633 | valExprs.join(' and ') + ' ' + (valExprs.length > 1 ? 'are' : 'is') + ' null'
|
634 | }
|
635 | }
|
636 |
|
637 | function validateExpressions(data) {
|
638 | var key, msg, result, context = {
|
639 | attrNames: data.ExpressionAttributeNames,
|
640 | attrVals: data.ExpressionAttributeValues,
|
641 | unusedAttrNames: {},
|
642 | unusedAttrVals: {},
|
643 | }
|
644 |
|
645 | if (data.ExpressionAttributeNames != null) {
|
646 | if (!Object.keys(data.ExpressionAttributeNames).length)
|
647 | return 'ExpressionAttributeNames must not be empty'
|
648 | for (key in data.ExpressionAttributeNames) {
|
649 | if (!/^#[0-9a-zA-Z_]+$/.test(key)) {
|
650 | return 'ExpressionAttributeNames contains invalid key: Syntax error; key: "' + key + '"'
|
651 | }
|
652 | context.unusedAttrNames[key] = true
|
653 | }
|
654 | }
|
655 |
|
656 | if (data.ExpressionAttributeValues != null) {
|
657 | if (!Object.keys(data.ExpressionAttributeValues).length)
|
658 | return 'ExpressionAttributeValues must not be empty'
|
659 | for (key in data.ExpressionAttributeValues) {
|
660 | if (!/^:[0-9a-zA-Z_]+$/.test(key)) {
|
661 | return 'ExpressionAttributeValues contains invalid key: Syntax error; key: "' + key + '"'
|
662 | }
|
663 | context.unusedAttrVals[key] = true
|
664 | }
|
665 | for (key in data.ExpressionAttributeValues) {
|
666 | msg = validateAttributeValue(data.ExpressionAttributeValues[key])
|
667 | if (msg) {
|
668 | msg = 'ExpressionAttributeValues contains invalid value: ' + msg + ' for key ' + key
|
669 | return msg
|
670 | }
|
671 | }
|
672 | }
|
673 |
|
674 | if (data.UpdateExpression != null) {
|
675 | result = parse(data.UpdateExpression, updateParser, context)
|
676 | if (typeof result == 'string') {
|
677 | return 'Invalid UpdateExpression: ' + result
|
678 | }
|
679 | data._updates = result
|
680 | }
|
681 |
|
682 | if (data.ConditionExpression != null) {
|
683 | result = parse(data.ConditionExpression, conditionParser, context)
|
684 | if (typeof result == 'string') {
|
685 | return 'Invalid ConditionExpression: ' + result
|
686 | }
|
687 | data._condition = result
|
688 | }
|
689 |
|
690 | if (data.KeyConditionExpression != null) {
|
691 | context.isKeyCondition = true
|
692 | result = parse(data.KeyConditionExpression, conditionParser, context)
|
693 | if (typeof result == 'string') {
|
694 | return 'Invalid KeyConditionExpression: ' + result
|
695 | }
|
696 | data._keyCondition = result
|
697 | }
|
698 |
|
699 | if (data.FilterExpression != null) {
|
700 | result = parse(data.FilterExpression, conditionParser, context)
|
701 | if (typeof result == 'string') {
|
702 | return 'Invalid FilterExpression: ' + result
|
703 | }
|
704 | data._filter = result
|
705 | }
|
706 |
|
707 | if (data.ProjectionExpression != null) {
|
708 | result = parse(data.ProjectionExpression, projectionParser, context)
|
709 | if (typeof result == 'string') {
|
710 | return 'Invalid ProjectionExpression: ' + result
|
711 | }
|
712 | data._projection = result
|
713 | }
|
714 |
|
715 | if (Object.keys(context.unusedAttrNames).length) {
|
716 | return 'Value provided in ExpressionAttributeNames unused in expressions: ' +
|
717 | 'keys: {' + Object.keys(context.unusedAttrNames).join(', ') + '}'
|
718 | }
|
719 |
|
720 | if (Object.keys(context.unusedAttrVals).length) {
|
721 | return 'Value provided in ExpressionAttributeValues unused in expressions: ' +
|
722 | 'keys: {' + Object.keys(context.unusedAttrVals).join(', ') + '}'
|
723 | }
|
724 | }
|
725 |
|
726 | function parse(str, parser, context) {
|
727 | if (str == '') return 'The expression can not be empty;'
|
728 | context.isReserved = isReserved
|
729 | context.compare = db.compare
|
730 | try {
|
731 | return parser.parse(str, {context: context})
|
732 | } catch (e) {
|
733 | return e.name == 'SyntaxError' ? 'Syntax error; ' + e.message : e.message
|
734 | }
|
735 | }
|
736 |
|
737 | function convertKeyCondition(expression) {
|
738 | var keyConds = Object.create(null)
|
739 | return checkExpr(expression, keyConds) || keyConds
|
740 | }
|
741 |
|
742 | function checkExpr(expr, keyConds) {
|
743 | if (!expr || !expr.type) return
|
744 | if (~['or', 'not', 'in', '<>'].indexOf(expr.type)) {
|
745 | return 'Invalid operator used in KeyConditionExpression: ' + expr.type.toUpperCase()
|
746 | }
|
747 | if (expr.type == 'function' && ~['attribute_exists', 'attribute_not_exists', 'attribute_type', 'contains'].indexOf(expr.name)) {
|
748 | return 'Invalid operator used in KeyConditionExpression: ' + expr.name
|
749 | }
|
750 | if (expr.type == 'function' && expr.name == 'size') {
|
751 | return 'KeyConditionExpressions cannot contain nested operations'
|
752 | }
|
753 | if (expr.type == 'between' && !Array.isArray(expr.args[0])) {
|
754 | return 'Invalid condition in KeyConditionExpression: ' + expr.type.toUpperCase() + ' operator must have the key attribute as its first operand'
|
755 | }
|
756 | if (expr.type == 'function' && expr.name == 'begins_with' && !Array.isArray(expr.args[0])) {
|
757 | return 'Invalid condition in KeyConditionExpression: ' + expr.name + ' operator must have the key attribute as its first operand'
|
758 | }
|
759 | if (expr.args) {
|
760 | var attrName = '', attrIx = 0
|
761 | for (var i = 0; i < expr.args.length; i++) {
|
762 | if (Array.isArray(expr.args[i])) {
|
763 | if (attrName) {
|
764 | return 'Invalid condition in KeyConditionExpression: Multiple attribute names used in one condition'
|
765 | }
|
766 | if (expr.args[i].length > 1) {
|
767 | return 'KeyConditionExpressions cannot have conditions on nested attributes'
|
768 | }
|
769 | attrName = expr.args[i][0]
|
770 | attrIx = i
|
771 | } else if (expr.args[i].type) {
|
772 | var result = checkExpr(expr.args[i], keyConds)
|
773 | if (result) return result
|
774 | }
|
775 | }
|
776 | if (expr.type != 'and') {
|
777 | if (!attrName) {
|
778 | return 'Invalid condition in KeyConditionExpression: No key attribute specified'
|
779 | }
|
780 | if (keyConds[attrName]) {
|
781 | return 'KeyConditionExpressions must only contain one condition per key'
|
782 | }
|
783 | if (attrIx != 0) {
|
784 | expr.type = {
|
785 | '=': '=',
|
786 | '<': '>',
|
787 | '<=': '>=',
|
788 | '>': '<',
|
789 | '>=': '<=',
|
790 | }[expr.type]
|
791 | expr.args[1] = expr.args[0]
|
792 | }
|
793 | keyConds[attrName] = {
|
794 | ComparisonOperator: {
|
795 | '=': 'EQ',
|
796 | '<': 'LT',
|
797 | '<=': 'LE',
|
798 | '>': 'GT',
|
799 | '>=': 'GE',
|
800 | 'between': 'BETWEEN',
|
801 | 'function': 'BEGINS_WITH',
|
802 | }[expr.type],
|
803 | AttributeValueList: expr.args.slice(1),
|
804 | }
|
805 | }
|
806 | }
|
807 | }
|
808 |
|
809 |
|
810 | var RESERVED_WORDS = {
|
811 | ABORT: true,
|
812 | ABSOLUTE: true,
|
813 | ACTION: true,
|
814 | ADD: true,
|
815 | AFTER: true,
|
816 | AGENT: true,
|
817 | AGGREGATE: true,
|
818 | ALL: true,
|
819 | ALLOCATE: true,
|
820 | ALTER: true,
|
821 | ANALYZE: true,
|
822 | AND: true,
|
823 | ANY: true,
|
824 | ARCHIVE: true,
|
825 | ARE: true,
|
826 | ARRAY: true,
|
827 | AS: true,
|
828 | ASC: true,
|
829 | ASCII: true,
|
830 | ASENSITIVE: true,
|
831 | ASSERTION: true,
|
832 | ASYMMETRIC: true,
|
833 | AT: true,
|
834 | ATOMIC: true,
|
835 | ATTACH: true,
|
836 | ATTRIBUTE: true,
|
837 | AUTH: true,
|
838 | AUTHORIZATION: true,
|
839 | AUTHORIZE: true,
|
840 | AUTO: true,
|
841 | AVG: true,
|
842 | BACK: true,
|
843 | BACKUP: true,
|
844 | BASE: true,
|
845 | BATCH: true,
|
846 | BEFORE: true,
|
847 | BEGIN: true,
|
848 | BETWEEN: true,
|
849 | BIGINT: true,
|
850 | BINARY: true,
|
851 | BIT: true,
|
852 | BLOB: true,
|
853 | BLOCK: true,
|
854 | BOOLEAN: true,
|
855 | BOTH: true,
|
856 | BREADTH: true,
|
857 | BUCKET: true,
|
858 | BULK: true,
|
859 | BY: true,
|
860 | BYTE: true,
|
861 | CALL: true,
|
862 | CALLED: true,
|
863 | CALLING: true,
|
864 | CAPACITY: true,
|
865 | CASCADE: true,
|
866 | CASCADED: true,
|
867 | CASE: true,
|
868 | CAST: true,
|
869 | CATALOG: true,
|
870 | CHAR: true,
|
871 | CHARACTER: true,
|
872 | CHECK: true,
|
873 | CLASS: true,
|
874 | CLOB: true,
|
875 | CLOSE: true,
|
876 | CLUSTER: true,
|
877 | CLUSTERED: true,
|
878 | CLUSTERING: true,
|
879 | CLUSTERS: true,
|
880 | COALESCE: true,
|
881 | COLLATE: true,
|
882 | COLLATION: true,
|
883 | COLLECTION: true,
|
884 | COLUMN: true,
|
885 | COLUMNS: true,
|
886 | COMBINE: true,
|
887 | COMMENT: true,
|
888 | COMMIT: true,
|
889 | COMPACT: true,
|
890 | COMPILE: true,
|
891 | COMPRESS: true,
|
892 | CONDITION: true,
|
893 | CONFLICT: true,
|
894 | CONNECT: true,
|
895 | CONNECTION: true,
|
896 | CONSISTENCY: true,
|
897 | CONSISTENT: true,
|
898 | CONSTRAINT: true,
|
899 | CONSTRAINTS: true,
|
900 | CONSTRUCTOR: true,
|
901 | CONSUMED: true,
|
902 | CONTINUE: true,
|
903 | CONVERT: true,
|
904 | COPY: true,
|
905 | CORRESPONDING: true,
|
906 | COUNT: true,
|
907 | COUNTER: true,
|
908 | CREATE: true,
|
909 | CROSS: true,
|
910 | CUBE: true,
|
911 | CURRENT: true,
|
912 | CURSOR: true,
|
913 | CYCLE: true,
|
914 | DATA: true,
|
915 | DATABASE: true,
|
916 | DATE: true,
|
917 | DATETIME: true,
|
918 | DAY: true,
|
919 | DEALLOCATE: true,
|
920 | DEC: true,
|
921 | DECIMAL: true,
|
922 | DECLARE: true,
|
923 | DEFAULT: true,
|
924 | DEFERRABLE: true,
|
925 | DEFERRED: true,
|
926 | DEFINE: true,
|
927 | DEFINED: true,
|
928 | DEFINITION: true,
|
929 | DELETE: true,
|
930 | DELIMITED: true,
|
931 | DEPTH: true,
|
932 | DEREF: true,
|
933 | DESC: true,
|
934 | DESCRIBE: true,
|
935 | DESCRIPTOR: true,
|
936 | DETACH: true,
|
937 | DETERMINISTIC: true,
|
938 | DIAGNOSTICS: true,
|
939 | DIRECTORIES: true,
|
940 | DISABLE: true,
|
941 | DISCONNECT: true,
|
942 | DISTINCT: true,
|
943 | DISTRIBUTE: true,
|
944 | DO: true,
|
945 | DOMAIN: true,
|
946 | DOUBLE: true,
|
947 | DROP: true,
|
948 | DUMP: true,
|
949 | DURATION: true,
|
950 | DYNAMIC: true,
|
951 | EACH: true,
|
952 | ELEMENT: true,
|
953 | ELSE: true,
|
954 | ELSEIF: true,
|
955 | EMPTY: true,
|
956 | ENABLE: true,
|
957 | END: true,
|
958 | EQUAL: true,
|
959 | EQUALS: true,
|
960 | ERROR: true,
|
961 | ESCAPE: true,
|
962 | ESCAPED: true,
|
963 | EVAL: true,
|
964 | EVALUATE: true,
|
965 | EXCEEDED: true,
|
966 | EXCEPT: true,
|
967 | EXCEPTION: true,
|
968 | EXCEPTIONS: true,
|
969 | EXCLUSIVE: true,
|
970 | EXEC: true,
|
971 | EXECUTE: true,
|
972 | EXISTS: true,
|
973 | EXIT: true,
|
974 | EXPLAIN: true,
|
975 | EXPLODE: true,
|
976 | EXPORT: true,
|
977 | EXPRESSION: true,
|
978 | EXTENDED: true,
|
979 | EXTERNAL: true,
|
980 | EXTRACT: true,
|
981 | FAIL: true,
|
982 | FALSE: true,
|
983 | FAMILY: true,
|
984 | FETCH: true,
|
985 | FIELDS: true,
|
986 | FILE: true,
|
987 | FILTER: true,
|
988 | FILTERING: true,
|
989 | FINAL: true,
|
990 | FINISH: true,
|
991 | FIRST: true,
|
992 | FIXED: true,
|
993 | FLATTERN: true,
|
994 | FLOAT: true,
|
995 | FOR: true,
|
996 | FORCE: true,
|
997 | FOREIGN: true,
|
998 | FORMAT: true,
|
999 | FORWARD: true,
|
1000 | FOUND: true,
|
1001 | FREE: true,
|
1002 | FROM: true,
|
1003 | FULL: true,
|
1004 | FUNCTION: true,
|
1005 | FUNCTIONS: true,
|
1006 | GENERAL: true,
|
1007 | GENERATE: true,
|
1008 | GET: true,
|
1009 | GLOB: true,
|
1010 | GLOBAL: true,
|
1011 | GO: true,
|
1012 | GOTO: true,
|
1013 | GRANT: true,
|
1014 | GREATER: true,
|
1015 | GROUP: true,
|
1016 | GROUPING: true,
|
1017 | HANDLER: true,
|
1018 | HASH: true,
|
1019 | HAVE: true,
|
1020 | HAVING: true,
|
1021 | HEAP: true,
|
1022 | HIDDEN: true,
|
1023 | HOLD: true,
|
1024 | HOUR: true,
|
1025 | IDENTIFIED: true,
|
1026 | IDENTITY: true,
|
1027 | IF: true,
|
1028 | IGNORE: true,
|
1029 | IMMEDIATE: true,
|
1030 | IMPORT: true,
|
1031 | IN: true,
|
1032 | INCLUDING: true,
|
1033 | INCLUSIVE: true,
|
1034 | INCREMENT: true,
|
1035 | INCREMENTAL: true,
|
1036 | INDEX: true,
|
1037 | INDEXED: true,
|
1038 | INDEXES: true,
|
1039 | INDICATOR: true,
|
1040 | INFINITE: true,
|
1041 | INITIALLY: true,
|
1042 | INLINE: true,
|
1043 | INNER: true,
|
1044 | INNTER: true,
|
1045 | INOUT: true,
|
1046 | INPUT: true,
|
1047 | INSENSITIVE: true,
|
1048 | INSERT: true,
|
1049 | INSTEAD: true,
|
1050 | INT: true,
|
1051 | INTEGER: true,
|
1052 | INTERSECT: true,
|
1053 | INTERVAL: true,
|
1054 | INTO: true,
|
1055 | INVALIDATE: true,
|
1056 | IS: true,
|
1057 | ISOLATION: true,
|
1058 | ITEM: true,
|
1059 | ITEMS: true,
|
1060 | ITERATE: true,
|
1061 | JOIN: true,
|
1062 | KEY: true,
|
1063 | KEYS: true,
|
1064 | LAG: true,
|
1065 | LANGUAGE: true,
|
1066 | LARGE: true,
|
1067 | LAST: true,
|
1068 | LATERAL: true,
|
1069 | LEAD: true,
|
1070 | LEADING: true,
|
1071 | LEAVE: true,
|
1072 | LEFT: true,
|
1073 | LENGTH: true,
|
1074 | LESS: true,
|
1075 | LEVEL: true,
|
1076 | LIKE: true,
|
1077 | LIMIT: true,
|
1078 | LIMITED: true,
|
1079 | LINES: true,
|
1080 | LIST: true,
|
1081 | LOAD: true,
|
1082 | LOCAL: true,
|
1083 | LOCALTIME: true,
|
1084 | LOCALTIMESTAMP: true,
|
1085 | LOCATION: true,
|
1086 | LOCATOR: true,
|
1087 | LOCK: true,
|
1088 | LOCKS: true,
|
1089 | LOG: true,
|
1090 | LOGED: true,
|
1091 | LONG: true,
|
1092 | LOOP: true,
|
1093 | LOWER: true,
|
1094 | MAP: true,
|
1095 | MATCH: true,
|
1096 | MATERIALIZED: true,
|
1097 | MAX: true,
|
1098 | MAXLEN: true,
|
1099 | MEMBER: true,
|
1100 | MERGE: true,
|
1101 | METHOD: true,
|
1102 | METRICS: true,
|
1103 | MIN: true,
|
1104 | MINUS: true,
|
1105 | MINUTE: true,
|
1106 | MISSING: true,
|
1107 | MOD: true,
|
1108 | MODE: true,
|
1109 | MODIFIES: true,
|
1110 | MODIFY: true,
|
1111 | MODULE: true,
|
1112 | MONTH: true,
|
1113 | MULTI: true,
|
1114 | MULTISET: true,
|
1115 | NAME: true,
|
1116 | NAMES: true,
|
1117 | NATIONAL: true,
|
1118 | NATURAL: true,
|
1119 | NCHAR: true,
|
1120 | NCLOB: true,
|
1121 | NEW: true,
|
1122 | NEXT: true,
|
1123 | NO: true,
|
1124 | NONE: true,
|
1125 | NOT: true,
|
1126 | NULL: true,
|
1127 | NULLIF: true,
|
1128 | NUMBER: true,
|
1129 | NUMERIC: true,
|
1130 | OBJECT: true,
|
1131 | OF: true,
|
1132 | OFFLINE: true,
|
1133 | OFFSET: true,
|
1134 | OLD: true,
|
1135 | ON: true,
|
1136 | ONLINE: true,
|
1137 | ONLY: true,
|
1138 | OPAQUE: true,
|
1139 | OPEN: true,
|
1140 | OPERATOR: true,
|
1141 | OPTION: true,
|
1142 | OR: true,
|
1143 | ORDER: true,
|
1144 | ORDINALITY: true,
|
1145 | OTHER: true,
|
1146 | OTHERS: true,
|
1147 | OUT: true,
|
1148 | OUTER: true,
|
1149 | OUTPUT: true,
|
1150 | OVER: true,
|
1151 | OVERLAPS: true,
|
1152 | OVERRIDE: true,
|
1153 | OWNER: true,
|
1154 | PAD: true,
|
1155 | PARALLEL: true,
|
1156 | PARAMETER: true,
|
1157 | PARAMETERS: true,
|
1158 | PARTIAL: true,
|
1159 | PARTITION: true,
|
1160 | PARTITIONED: true,
|
1161 | PARTITIONS: true,
|
1162 | PATH: true,
|
1163 | PERCENT: true,
|
1164 | PERCENTILE: true,
|
1165 | PERMISSION: true,
|
1166 | PERMISSIONS: true,
|
1167 | PIPE: true,
|
1168 | PIPELINED: true,
|
1169 | PLAN: true,
|
1170 | POOL: true,
|
1171 | POSITION: true,
|
1172 | PRECISION: true,
|
1173 | PREPARE: true,
|
1174 | PRESERVE: true,
|
1175 | PRIMARY: true,
|
1176 | PRIOR: true,
|
1177 | PRIVATE: true,
|
1178 | PRIVILEGES: true,
|
1179 | PROCEDURE: true,
|
1180 | PROCESSED: true,
|
1181 | PROJECT: true,
|
1182 | PROJECTION: true,
|
1183 | PROPERTY: true,
|
1184 | PROVISIONING: true,
|
1185 | PUBLIC: true,
|
1186 | PUT: true,
|
1187 | QUERY: true,
|
1188 | QUIT: true,
|
1189 | QUORUM: true,
|
1190 | RAISE: true,
|
1191 | RANDOM: true,
|
1192 | RANGE: true,
|
1193 | RANK: true,
|
1194 | RAW: true,
|
1195 | READ: true,
|
1196 | READS: true,
|
1197 | REAL: true,
|
1198 | REBUILD: true,
|
1199 | RECORD: true,
|
1200 | RECURSIVE: true,
|
1201 | REDUCE: true,
|
1202 | REF: true,
|
1203 | REFERENCE: true,
|
1204 | REFERENCES: true,
|
1205 | REFERENCING: true,
|
1206 | REGEXP: true,
|
1207 | REGION: true,
|
1208 | REINDEX: true,
|
1209 | RELATIVE: true,
|
1210 | RELEASE: true,
|
1211 | REMAINDER: true,
|
1212 | RENAME: true,
|
1213 | REPEAT: true,
|
1214 | REPLACE: true,
|
1215 | REQUEST: true,
|
1216 | RESET: true,
|
1217 | RESIGNAL: true,
|
1218 | RESOURCE: true,
|
1219 | RESPONSE: true,
|
1220 | RESTORE: true,
|
1221 | RESTRICT: true,
|
1222 | RESULT: true,
|
1223 | RETURN: true,
|
1224 | RETURNING: true,
|
1225 | RETURNS: true,
|
1226 | REVERSE: true,
|
1227 | REVOKE: true,
|
1228 | RIGHT: true,
|
1229 | ROLE: true,
|
1230 | ROLES: true,
|
1231 | ROLLBACK: true,
|
1232 | ROLLUP: true,
|
1233 | ROUTINE: true,
|
1234 | ROW: true,
|
1235 | ROWS: true,
|
1236 | RULE: true,
|
1237 | RULES: true,
|
1238 | SAMPLE: true,
|
1239 | SATISFIES: true,
|
1240 | SAVE: true,
|
1241 | SAVEPOINT: true,
|
1242 | SCAN: true,
|
1243 | SCHEMA: true,
|
1244 | SCOPE: true,
|
1245 | SCROLL: true,
|
1246 | SEARCH: true,
|
1247 | SECOND: true,
|
1248 | SECTION: true,
|
1249 | SEGMENT: true,
|
1250 | SEGMENTS: true,
|
1251 | SELECT: true,
|
1252 | SELF: true,
|
1253 | SEMI: true,
|
1254 | SENSITIVE: true,
|
1255 | SEPARATE: true,
|
1256 | SEQUENCE: true,
|
1257 | SERIALIZABLE: true,
|
1258 | SESSION: true,
|
1259 | SET: true,
|
1260 | SETS: true,
|
1261 | SHARD: true,
|
1262 | SHARE: true,
|
1263 | SHARED: true,
|
1264 | SHORT: true,
|
1265 | SHOW: true,
|
1266 | SIGNAL: true,
|
1267 | SIMILAR: true,
|
1268 | SIZE: true,
|
1269 | SKEWED: true,
|
1270 | SMALLINT: true,
|
1271 | SNAPSHOT: true,
|
1272 | SOME: true,
|
1273 | SOURCE: true,
|
1274 | SPACE: true,
|
1275 | SPACES: true,
|
1276 | SPARSE: true,
|
1277 | SPECIFIC: true,
|
1278 | SPECIFICTYPE: true,
|
1279 | SPLIT: true,
|
1280 | SQL: true,
|
1281 | SQLCODE: true,
|
1282 | SQLERROR: true,
|
1283 | SQLEXCEPTION: true,
|
1284 | SQLSTATE: true,
|
1285 | SQLWARNING: true,
|
1286 | START: true,
|
1287 | STATE: true,
|
1288 | STATIC: true,
|
1289 | STATUS: true,
|
1290 | STORAGE: true,
|
1291 | STORE: true,
|
1292 | STORED: true,
|
1293 | STREAM: true,
|
1294 | STRING: true,
|
1295 | STRUCT: true,
|
1296 | STYLE: true,
|
1297 | SUB: true,
|
1298 | SUBMULTISET: true,
|
1299 | SUBPARTITION: true,
|
1300 | SUBSTRING: true,
|
1301 | SUBTYPE: true,
|
1302 | SUM: true,
|
1303 | SUPER: true,
|
1304 | SYMMETRIC: true,
|
1305 | SYNONYM: true,
|
1306 | SYSTEM: true,
|
1307 | TABLE: true,
|
1308 | TABLESAMPLE: true,
|
1309 | TEMP: true,
|
1310 | TEMPORARY: true,
|
1311 | TERMINATED: true,
|
1312 | TEXT: true,
|
1313 | THAN: true,
|
1314 | THEN: true,
|
1315 | THROUGHPUT: true,
|
1316 | TIME: true,
|
1317 | TIMESTAMP: true,
|
1318 | TIMEZONE: true,
|
1319 | TINYINT: true,
|
1320 | TO: true,
|
1321 | TOKEN: true,
|
1322 | TOTAL: true,
|
1323 | TOUCH: true,
|
1324 | TRAILING: true,
|
1325 | TRANSACTION: true,
|
1326 | TRANSFORM: true,
|
1327 | TRANSLATE: true,
|
1328 | TRANSLATION: true,
|
1329 | TREAT: true,
|
1330 | TRIGGER: true,
|
1331 | TRIM: true,
|
1332 | TRUE: true,
|
1333 | TRUNCATE: true,
|
1334 | TTL: true,
|
1335 | TUPLE: true,
|
1336 | TYPE: true,
|
1337 | UNDER: true,
|
1338 | UNDO: true,
|
1339 | UNION: true,
|
1340 | UNIQUE: true,
|
1341 | UNIT: true,
|
1342 | UNKNOWN: true,
|
1343 | UNLOGGED: true,
|
1344 | UNNEST: true,
|
1345 | UNPROCESSED: true,
|
1346 | UNSIGNED: true,
|
1347 | UNTIL: true,
|
1348 | UPDATE: true,
|
1349 | UPPER: true,
|
1350 | URL: true,
|
1351 | USAGE: true,
|
1352 | USE: true,
|
1353 | USER: true,
|
1354 | USERS: true,
|
1355 | USING: true,
|
1356 | UUID: true,
|
1357 | VACUUM: true,
|
1358 | VALUE: true,
|
1359 | VALUED: true,
|
1360 | VALUES: true,
|
1361 | VARCHAR: true,
|
1362 | VARIABLE: true,
|
1363 | VARIANCE: true,
|
1364 | VARINT: true,
|
1365 | VARYING: true,
|
1366 | VIEW: true,
|
1367 | VIEWS: true,
|
1368 | VIRTUAL: true,
|
1369 | VOID: true,
|
1370 | WAIT: true,
|
1371 | WHEN: true,
|
1372 | WHENEVER: true,
|
1373 | WHERE: true,
|
1374 | WHILE: true,
|
1375 | WINDOW: true,
|
1376 | WITH: true,
|
1377 | WITHIN: true,
|
1378 | WITHOUT: true,
|
1379 | WORK: true,
|
1380 | WRAPPED: true,
|
1381 | WRITE: true,
|
1382 | YEAR: true,
|
1383 | ZONE: true,
|
1384 | }
|
1385 |
|
1386 | function isReserved(name) {
|
1387 | return RESERVED_WORDS[name.toUpperCase()] != null
|
1388 | }
|