Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dynamite

Package Overview
Dependencies
Maintainers
17
Versions
54
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dynamite - npm Package Compare versions

Comparing version 0.8.2 to 0.9.0

lib/UpdateExpressionBuilder.js

613

lib/ConditionBuilder.js
var assert = require('assert')
var typ = require('typ')
var typeUtil = require('./typeUtil')
var ConditionJunction = require('./ConditionJunction')
var util = require('util')
/**
* @param {Object=} opt_conditions
* @constructor
*/
function ConditionBuilder(opt_conditions) {
this._conditions = opt_conditions || {}
this._uniqueName = ''
function ConditionBuilder() {
this._exprs = []
}
/**
* @param {Array.<ConditionBuilder|ConditionJunction>} conditions
* @return {ConditionJunction}
* Creates a new Conditional expression with an operator (AND, EQ, etc)
* @param {Op} op One of the ops defined in the Op enum.
* @param {Array<ConditionExpr>} args The arguments to the op.
* @return {ConditionExpr}
*/
ConditionBuilder.prototype._op = function (op, args) {
if (!op) throw new Error('Missing op')
return new ConditionExprOp(op, args)
}
/**
* Creates a new Conditional expression that evaluates to an attribute name
* @param {string} name An attribute name
* @return {ConditionExpr}
*/
ConditionBuilder.prototype._attr = function (name) {
return new ConditionExprAttr(name)
}
/**
* Creates a new Conditional expression that evaluates to a value
* @param {*} val Any literal value representable in a dynamodb expression
* @return {ConditionExpr}
*/
ConditionBuilder.prototype._val = function (val) {
return new ConditionExprVal(val)
}
/**
* Returns this condition builder as a ConditionExpr, the internal representation
* of a condition.
* @return {ConditionExpr}
*/
ConditionBuilder.prototype._asExpr = function () {
return this._op(Op.AND, this._exprs)
}
/**
* @param {Array.<ConditionBuilder>} conditions
* @return {ConditionBuilder}
*/
ConditionBuilder.andConditions = function (conditions) {
ConditionBuilder.validateConditions(conditions)
return new ConditionJunction('AND', conditions)
var builder = new ConditionBuilder()
builder._exprs.push(builder._op(Op.AND, conditions.map(function (c) {
return c._asExpr()
})))
return builder
}
/**
* @param {Array.<ConditionBuilder|ConditionJunction>} conditions
* @return {ConditionJunction}
* @param {Array.<ConditionBuilder>} conditions
* @return {ConditionBuilder}
*/
ConditionBuilder.orConditions = function (conditions) {
ConditionBuilder.validateConditions(conditions)
return new ConditionJunction('OR', conditions)
var builder = new ConditionBuilder()
builder._exprs.push(builder._op('OR', conditions.map(function (c) {
return c._asExpr()
})))
return builder
}
/**
* @param {ConditionBuilder|ConditionJunction} condition
* @return {ConditionJunction}
* @param {ConditionBuilder} condition
* @return {ConditionBuilder}
*/

@@ -40,3 +84,5 @@ ConditionBuilder.notCondition = function (condition) {

ConditionBuilder.validateConditions(conditions)
return new ConditionJunction('NOT', conditions)
var builder = new ConditionBuilder()
builder._exprs.push(builder._op('NOT', [condition._asExpr()]))
return builder
}

@@ -48,5 +94,4 @@

var condition = conditions[i]
assert.ok(condition instanceof ConditionBuilder ||
condition instanceof ConditionJunction,
'Expected ConditionBuilder or ConditionJunction')
assert.ok(condition instanceof ConditionBuilder,
'Expected ConditionBuilder')
}

@@ -56,19 +101,2 @@ }

/**
* @param {!Object} field
* @param {Array.<ConditionBuilder>} conditions
*/
ConditionBuilder.populateFieldFromConditionBuilderList = function (field, conditions) {
if (conditions) {
assert.ok(Array.isArray(conditions), 'Expected array')
for (var i = 0; i < conditions.length; i++) {
var condition = conditions[i]
assert.ok(condition instanceof ConditionBuilder, 'Expected ConditionBuilder')
for (var attr in condition._conditions) {
field[attr] = condition._conditions[attr]
}
}
}
}
/**
* @param {Object} data

@@ -78,3 +106,3 @@ * @param {string} fieldName The fieldName on `data`

* @param {{count: number}} nameMutex
* @return {ConditionBuilder|ConditionJunction}
* @return {ConditionBuilder}
*/

@@ -84,3 +112,3 @@ ConditionBuilder.populateExpressionField = function (data, fieldName, conditions, nameMutex) {

var junction = new ConditionJunction('AND', conditions)
var junction = ConditionBuilder.andConditions(conditions)
junction.assignUniqueNames(nameMutex)

@@ -106,6 +134,3 @@

ConditionBuilder.prototype.assignUniqueNames = function (nameMutex) {
if (!nameMutex.count) {
nameMutex.count = 1
}
this._uniqueName = 'C' + nameMutex.count++
this._asExpr().assignUniqueNames(nameMutex)
}

@@ -115,3 +140,5 @@

ConditionBuilder.prototype.buildAttributeNames = function () {
return typeUtil.buildAttributeNames(Object.keys(this._conditions))
var result = []
this._asExpr().appendAttributeNames(result)
return typeUtil.buildAttributeNames(result)
}

@@ -122,10 +149,3 @@

var result = {}
Object.keys(this._conditions).map(function (key) {
var list = this._conditions[key].AttributeValueList
if (!list) return
list.map(function (value, index) {
result[this._getValueAlias(key, index)] = value
}, this)
}, this)
this._asExpr().appendAttributeValues(result)
return result

@@ -135,10 +155,2 @@ }

/**
* @see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ExpressionPlaceholders.html#ExpressionAttributeValues
*/
ConditionBuilder.prototype._getValueAlias = function (key, index) {
if (!this._uniqueName) throw new Error('Names have not been assigned yet')
return ':V' + this._uniqueName + 'X' + key + 'X' + index
}
/**
* @return {string} String suitable for FilterExpression and KeyExpression

@@ -148,56 +160,13 @@ * @see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html#ConditionExpressionReference.Syntax

ConditionBuilder.prototype.buildExpression = function () {
var filters = Object.keys(this._conditions).map(function (key) {
var operator = this._conditions[key].ComparisonOperator
var attrAlias = typeUtil.getAttributeAlias(key)
var valueAliases = []
if (this._conditions[key].AttributeValueList) {
valueAliases = this._conditions[key].AttributeValueList.map(function (val, index) {
return this._getValueAlias(key, index)
}, this)
}
switch (operator) {
case 'BEGINS_WITH':
return 'begins_with(' + attrAlias + ', ' + valueAliases[0] + ')'
case 'EQ':
return '(' + attrAlias + ' = ' + valueAliases[0] + ')'
case 'NE':
return '(' + attrAlias + ' <> ' + valueAliases[0] + ')'
case 'LE':
return '(' + attrAlias + ' <= ' + valueAliases[0] + ')'
case 'LT':
return '(' + attrAlias + ' < ' + valueAliases[0] + ')'
case 'GE':
return '(' + attrAlias + ' >= ' + valueAliases[0] + ')'
case 'GT':
return '(' + attrAlias + ' > ' + valueAliases[0] + ')'
case 'BETWEEN':
return '(' + attrAlias + ' BETWEEN ' + valueAliases[0] + ' AND ' + valueAliases[1] + ')'
case 'IN':
return '(' + attrAlias + ' IN (' + valueAliases.join(', ') + '))'
case 'NOT_CONTAINS':
return '(attribute_exists(' + attrAlias + ') AND NOT contains(' + attrAlias + ', ' + valueAliases[0] + '))'
case 'CONTAINS':
return 'contains(' + attrAlias + ', ' + valueAliases[0] + ')'
case 'NULL':
return 'attribute_not_exists(' + attrAlias + ')'
case 'NOT_NULL':
return 'attribute_exists(' + attrAlias + ')'
default:
throw new Error('Invalid comparison operator \'' + operator + '\'')
}
}, this)
return filters.join(' AND ')
return this._asExpr().buildExpression()
}
/**
* Iterate through all the conditions
* @param {function(Object, string)} callback
* Iterate through all the expressions. Intended for FakeDynamo
* @param {function(Object)} callback
*/
ConditionBuilder.prototype.forEachCondition = function (callback) {
Object.keys(this._conditions).map(function (key) {
callback(this._conditions[key], key)
}, this)
ConditionBuilder.prototype.visitExpressionsPostOrder = function (callback) {
this._exprs.forEach(function (expr) {
expr.visitPostOrder(callback)
})
}

@@ -210,44 +179,5 @@

ConditionBuilder.prototype.buildFilterFn = function () {
var filters = Object.keys(this._conditions).map(function (key) {
var operator = this._conditions[key].ComparisonOperator
var values = []
if (this._conditions[key].AttributeValueList) {
values = this._conditions[key].AttributeValueList.map(typeUtil.objectToValue)
}
switch (operator) {
case 'BEGINS_WITH':
return function(item) { return item[key].indexOf(values[0]) === 0 }
case 'EQ':
return function(item) { return item[key] == values[0] }
case 'NE':
return function(item) { return item[key] != values[0] }
case 'LE':
return function(item) { return item[key] <= values[0] }
case 'LT':
return function(item) { return item[key] < values[0] }
case 'GE':
return function(item) { return item[key] >= values[0] }
case 'GT':
return function(item) { return item[key] > values[0] }
case 'BETWEEN':
return function(item) { return item[key] >= values[0] && item[key] <= values[1] }
case 'IN':
return function(item) { return values.indexOf(item[key]) != -1 }
case 'NOT_CONTAINS':
return function(item) { return item[key].indexOf(values[0]) == -1 }
case 'CONTAINS':
return function(item) { return item[key].indexOf(values[0]) != -1 }
case 'NULL':
return function(item) { return !item.hasOwnProperty(key) }
case 'NOT_NULL':
return function(item) { return item.hasOwnProperty(key) }
default:
throw new Error('Invalid comparison operator \'' + operator + '\'')
}
}, this)
var builder = this
return function (item) {
return filters.every(function (filter) { return filter(item) })
return !!builder._asExpr().evaluate(item)
}

@@ -261,64 +191,86 @@ }

if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'EQ',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('EQ', [this._attr(key), this._val(val)]))
return this
}
ConditionBuilder.prototype.filterAttributeEqualsAttribute = function (key1, key2) {
if (typ.isNullish(key1)) throw new Error("Key1 must be defined")
if (typ.isNullish(key2)) throw new Error("Key2 must be defined")
this._exprs.push(this._op('EQ', [this._attr(key1), this._attr(key2)]))
return this
}
ConditionBuilder.prototype.filterAttributeNotEquals = function (key, val) {
if (typ.isNullish(key)) throw new Error("Key must be defined")
if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'NE',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('NE', [this._attr(key), this._val(val)]))
return this
}
ConditionBuilder.prototype.filterAttributeNotEqualsAttribute = function (key1, key2) {
if (typ.isNullish(key1)) throw new Error("Key1 must be defined")
if (typ.isNullish(key2)) throw new Error("Key2 must be defined")
this._exprs.push(this._op('NE', [this._attr(key1), this._attr(key2)]))
return this
}
ConditionBuilder.prototype.filterAttributeLessThanEqual = function (key, val) {
if (typ.isNullish(key)) throw new Error("Key must be defined")
if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'LE',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('LE', [this._attr(key), this._val(val)]))
return this
}
ConditionBuilder.prototype.filterAttributeLessThanEqualAttribute = function (key1, key2) {
if (typ.isNullish(key1)) throw new Error("Key1 must be defined")
if (typ.isNullish(key2)) throw new Error("Key2 must be defined")
this._exprs.push(this._op('LE', [this._attr(key1), this._attr(key2)]))
return this
}
ConditionBuilder.prototype.filterAttributeLessThan = function (key, val) {
if (typ.isNullish(key)) throw new Error("Key must be defined")
if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'LT',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('LT', [this._attr(key), this._val(val)]))
return this
}
ConditionBuilder.prototype.filterAttributeLessThanAttribute = function (key1, key2) {
if (typ.isNullish(key1)) throw new Error("Key1 must be defined")
if (typ.isNullish(key2)) throw new Error("Key2 must be defined")
this._exprs.push(this._op('LT', [this._attr(key1), this._attr(key2)]))
return this
}
ConditionBuilder.prototype.filterAttributeGreaterThanEqual = function (key, val) {
if (typ.isNullish(key)) throw new Error("Key must be defined")
if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'GE',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('GE', [this._attr(key), this._val(val)]))
return this
}
ConditionBuilder.prototype.filterAttributeGreaterThanEqualAttribute = function (key1, key2) {
if (typ.isNullish(key1)) throw new Error("Key1 must be defined")
if (typ.isNullish(key2)) throw new Error("Key2 must be defined")
this._exprs.push(this._op('GE', [this._attr(key1), this._attr(key2)]))
return this
}
ConditionBuilder.prototype.filterAttributeGreaterThan = function (key, val) {
if (typ.isNullish(key)) throw new Error("Key must be defined")
if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'GT',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('GT', [this._attr(key), this._val(val)]))
return this
}
ConditionBuilder.prototype.filterAttributeGreaterThanAttribute = function (key1, key2) {
if (typ.isNullish(key1)) throw new Error("Key1 must be defined")
if (typ.isNullish(key2)) throw new Error("Key2 must be defined")
this._exprs.push(this._op('GT', [this._attr(key1), this._attr(key2)]))
return this
}
ConditionBuilder.prototype.filterAttributeNotNull = function (key) {
if (typ.isNullish(key)) throw new Error("Key must be defined")
this._conditions[key] = {
ComparisonOperator: 'NOT_NULL'
}
this._exprs.push(this._op('NOT_NULL', [this._attr(key)]))
return this

@@ -330,5 +282,3 @@ }

if (typ.isNullish(key)) throw new Error("Key must be defined")
this._conditions[key] = {
ComparisonOperator: 'NULL'
}
this._exprs.push(this._op('NULL', [this._attr(key)]))
return this

@@ -340,6 +290,3 @@ }

if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'CONTAINS',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('CONTAINS', [this._attr(key), this._val(val)]))
return this

@@ -351,6 +298,3 @@ }

if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'NOT_CONTAINS',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('NOT_CONTAINS', [this._attr(key), this._val(val)]))
return this

@@ -362,6 +306,3 @@ }

if (typ.isNullish(val)) throw new Error("Val must be defined")
this._conditions[key] = {
ComparisonOperator: 'BEGINS_WITH',
AttributeValueList: [typeUtil.valueToObject(val)]
}
this._exprs.push(this._op('BEGINS_WITH', [this._attr(key), this._val(val)]))
return this

@@ -374,6 +315,3 @@ }

if (typ.isNullish(val2)) throw new Error("Val 2 must be defined")
this._conditions[key] = {
ComparisonOperator: 'BETWEEN',
AttributeValueList: [typeUtil.valueToObject(val1), typeUtil.valueToObject(val2)]
}
this._exprs.push(this._op('BETWEEN', [this._attr(key), this._val(val1), this._val(val2)]))
return this

@@ -385,9 +323,288 @@ }

if (typ.isNullish(vals)) throw new Error("Vals must be defined")
this._conditions[key] = {
ComparisonOperator: 'IN',
AttributeValueList: vals.map(typeUtil.valueToObject)
}
this._exprs.push(this._op('IN', [this._attr(key)].concat(vals.map(this._val.bind(this)))))
return this
}
/**
* Represents an abstract conditional expression internally.
*
* May contain zero or more arguments, which are also ConditionExprs.
*
* @param {Array<ConditionExpr>} args
* @constructor
*/
function ConditionExpr(args) {
this.args = args || []
this.uniqueName = ''
}
/**
* Iterate through all the expressions
* @param {function(Object)} callback
*/
ConditionExpr.prototype.visitPostOrder = function (callback) {
this.args.forEach(function (arg) {
arg.visitPostOrder(callback)
})
callback(this)
}
/**
* @param {Object} nameMutex
*/
ConditionExpr.prototype.assignUniqueNames = function (nameMutex) {
if (!nameMutex.count) {
nameMutex.count = 1
}
this.visitPostOrder(function (expr) {
expr.uniqueName = 'C' + nameMutex.count++
})
}
/**
* Appends the attribute names to the given array.
*/
ConditionExpr.prototype.appendAttributeNames = function (result) {
this.args.forEach(function (arg) {
arg.appendAttributeNames(result)
})
}
/**
* Appends the attribute values to the given object.
*/
ConditionExpr.prototype.appendAttributeValues = function (result) {
this.args.forEach(function (arg) {
arg.appendAttributeValues(result)
})
}
/**
* Builds an expression for consumption by the AWS expression API
*/
ConditionExpr.prototype.buildExpression = function () {
throw new Error('Expected buildExpression impl')
}
/**
* Client-side evaluation.
*/
ConditionExpr.prototype.evaluate = function () {
throw new Error('Expected evaluate impl')
}
/**
* Represents a conditional expression with 1 or more arguments.
* @param {Op} op One of the ops defined in the Op enum.
* @param {Array<ConditionExpr>} args The arguments to the op.
* @constructor
*/
function ConditionExprOp(op, args) {
ConditionExpr.call(this, args)
this.op = op
}
util.inherits(ConditionExprOp, ConditionExpr)
/**
* Builds an expression for arg i, asserting that the arg exists
*/
ConditionExprOp.prototype.buildArgExpr = function (i) {
if (i >= this.args.length) throw new Error('Operator ' + this.op + ' expected arg at position ' + i)
return this.args[i].buildExpression()
}
/** @override */
ConditionExprOp.prototype.buildExpression = function () {
var operator = this.op
switch (operator) {
case Op.NOT:
return '(NOT ' + this.buildArgExpr(0) + ')'
case Op.AND:
if (this.args.length == 0) return ''
if (this.args.length == 1) return this.buildArgExpr(0)
var andExprs = this.args.map(function (arg) {
return arg.buildExpression()
}, this)
return '(' + andExprs.join(' AND ') + ')'
case Op.OR:
if (this.args.length == 0) return ''
if (this.args.length == 1) return this.buildArgExpr(0)
var orExprs = this.args.map(function (arg) {
return arg.buildExpression()
}, this)
return '(' + orExprs.join(' OR ') + ')'
case Op.BEGINS_WITH:
return 'begins_with(' + this.buildArgExpr(0) + ', ' + this.buildArgExpr(1) + ')'
case Op.EQ:
return '(' + this.buildArgExpr(0) + ' = ' + this.buildArgExpr(1) + ')'
case Op.NE:
return '(' + this.buildArgExpr(0) + ' <> ' + this.buildArgExpr(1) + ')'
case Op.LE:
return '(' + this.buildArgExpr(0) + ' <= ' + this.buildArgExpr(1) + ')'
case Op.LT:
return '(' + this.buildArgExpr(0) + ' < ' + this.buildArgExpr(1) + ')'
case Op.GE:
return '(' + this.buildArgExpr(0) + ' >= ' + this.buildArgExpr(1) + ')'
case Op.GT:
return '(' + this.buildArgExpr(0) + ' > ' + this.buildArgExpr(1) + ')'
case Op.BETWEEN:
return '(' + this.buildArgExpr(0) + ' BETWEEN ' + this.buildArgExpr(1) + ' AND ' + this.buildArgExpr(2) + ')'
case Op.IN:
var values = this.args.slice(1).map(function (arg) {
return arg.buildExpression()
}, this)
return '(' + this.buildArgExpr(0) + ' IN (' + values + '))'
case Op.NOT_CONTAINS:
return '(attribute_exists(' + this.buildArgExpr(0) + ') AND NOT contains(' + this.buildArgExpr(0) + ', ' + this.buildArgExpr(1) + '))'
case Op.CONTAINS:
return 'contains(' + this.buildArgExpr(0) + ', ' + this.buildArgExpr(1) + ')'
case Op.NULL:
return 'attribute_not_exists(' + this.buildArgExpr(0) + ')'
case Op.NOT_NULL:
return 'attribute_exists(' + this.buildArgExpr(0) + ')'
default:
throw new Error('Invalid comparison operator \'' + operator + '\'')
}
}
/**
* Evaluate the value for arg i, asserting that the arg exists
*/
ConditionExprOp.prototype.evalArg = function (i, item) {
if (i >= this.args.length) throw new Error('Operator ' + this.op + ' expected arg at position ' + i)
return this.args[i].evaluate(item)
}
/**
* Evaluate the value for arg i, asserting that the arg exists
*/
ConditionExprOp.prototype.evalArgs = function (item) {
return this.args.map(function (arg) {
return arg.evaluate(item)
})
}
/** @override */
ConditionExprOp.prototype.evaluate = function (item) {
var argExprs = this.args
var operator = this.op
switch (operator) {
case Op.NOT:
return !this.evalArg(0, item)
case Op.AND:
return this.evalArgs(item).every(function (val) {
return val
})
case Op.OR:
return this.evalArgs(item).some(function (val) {
return val
})
case Op.BEGINS_WITH:
return item && this.evalArg(0, item).indexOf(this.evalArg(1, item)) === 0
case Op.EQ:
return item && this.evalArg(0, item) == this.evalArg(1, item)
case Op.NE:
return item && this.evalArg(0, item) != this.evalArg(1, item)
case Op.LE:
return item && this.evalArg(0, item) <= this.evalArg(1, item)
case Op.LT:
return item && this.evalArg(0, item) < this.evalArg(1, item)
case Op.GE:
return item && this.evalArg(0, item) >= this.evalArg(1, item)
case Op.GT:
return this.evalArg(0, item) > this.evalArg(1, item)
case Op.BETWEEN:
return item && this.evalArg(0, item) >= this.evalArg(1, item) && this.evalArg(0, item) <= this.evalArg(2, item)
case Op.IN:
return item && this.evalArgs(item).slice(1).indexOf(this.evalArg(0, item)) != -1
case Op.NOT_CONTAINS:
return item && this.evalArg(0, item).indexOf(this.evalArg(1, item)) == -1
case Op.CONTAINS:
return item && this.evalArg(0, item).indexOf(this.evalArg(1, item)) != -1
case Op.NULL:
return item && !item.hasOwnProperty(argExprs[0].name)
case Op.NOT_NULL:
return item && item.hasOwnProperty(argExprs[0].name)
default:
throw new Error('Invalid comparison operator \'' + operator + '\'')
}
}
/**
* Represents a value in a conditional expression.
* @param {*} val Any literal value representable in a dynamodb expression
* @constructor
*/
function ConditionExprVal(val) {
ConditionExpr.call(this, [])
this.val = typeUtil.valueToObject(val)
}
util.inherits(ConditionExprVal, ConditionExpr)
/** @override */
ConditionExprVal.prototype.buildExpression = function () {
return ':V' + this.uniqueName
}
/** @override */
ConditionExprVal.prototype.appendAttributeValues = function (result) {
result[this.buildExpression()] = this.val
}
/** @override */
ConditionExprVal.prototype.evaluate = function () {
return typeUtil.objectToValue(this.val)
}
/**
* Represents an item attribute in a conditional expression.
* @param {string} name An attribute name
* @constructor
*/
function ConditionExprAttr(name) {
ConditionExpr.call(this, [])
this.name = name
}
util.inherits(ConditionExprAttr, ConditionExpr)
/** @override */
ConditionExprAttr.prototype.buildExpression = function () {
return typeUtil.getAttributeAlias(this.name)
}
/** @override */
ConditionExprAttr.prototype.evaluate = function (item) {
return item[this.name]
}
/** @override */
ConditionExprAttr.prototype.appendAttributeNames = function (result) {
result.push(this.name)
}
/**
* An enum of all the possible Ops in our ConditionExpr syntax tree.
*/
var Op = {
NOT: 'NOT',
AND: 'AND',
OR: 'OR',
BEGINS_WITH: 'BEGINS_WITH',
EQ: 'EQ',
NE: 'NE',
LE: 'LE',
LT: 'LT',
GE: 'GE',
GT: 'GT',
BETWEEN: 'BETWEEN',
IN: 'IN',
NOT_CONTAINS: 'NOT_CONTAINS',
CONTAINS: 'CONTAINS',
NULL: 'NULL',
NOT_NULL: 'NOT_NULL'
}
module.exports = ConditionBuilder
var ConditionBuilder = require('./ConditionBuilder')
var UpdateExpressionBuilder = require('./UpdateExpressionBuilder')
var typeUtil = require('./typeUtil')

@@ -16,2 +17,4 @@

this._filterBuilder = null
this._conditionBuilder = null
this._updateExpressionBuilder = null
}

@@ -64,5 +67,5 @@

DynamoRequest.prototype.setUpdates = function (attributeUpdates) {
// TODO(nick): Switch this to use UpdateExpression
if (attributeUpdates) {
this.data.AttributeUpdates = attributeUpdates
this._updateExpressionBuilder = UpdateExpressionBuilder.populateUpdateExpression(
this.data, attributeUpdates, this._nameMutex)
}

@@ -124,5 +127,6 @@ return this

DynamoRequest.prototype.setExpected = function (conditions) {
// TODO(nick): Switch this to use ConditionExpression
this.data.Expected = {}
ConditionBuilder.populateFieldFromConditionBuilderList(this.data.Expected, conditions)
if (conditions) {
this._conditionBuilder = ConditionBuilder.populateExpressionField(
this.data, 'ConditionExpression', conditions, this._nameMutex)
}
return this

@@ -276,2 +280,10 @@ }

if (!this.data.ConditionExpression) {
delete this.data.ConditionExpression
}
if (!this.data.UpdateExpression) {
delete this.data.UpdateExpression
}
return this.data

@@ -278,0 +290,0 @@ }

@@ -15,3 +15,7 @@ var Q = require('kew')

function forEachKeyCondition(data, callback) {
return data._requestBuilder._keyConditionBuilder.forEachCondition(callback)
return data._requestBuilder._keyConditionBuilder.visitExpressionsPostOrder(function (expr) {
if (expr.op && expr.args[0] && expr.args[0].name) {
callback(expr, expr.args[0].name)
}
})
}

@@ -38,2 +42,7 @@

function getConditionFn(data) {
var builder = data._requestBuilder._conditionBuilder
return builder ? builder.buildFilterFn() : function() { return true }
}
/**

@@ -159,3 +168,3 @@ * @param {string} name

var hash = data.HashKeyValue ||
typeUtil.objectToValue(getKeyConditionByName(data, this.primaryKey.hash.name).AttributeValueList[0])
getKeyConditionByName(data, this.primaryKey.hash.name).args[1].evaluate()

@@ -226,3 +235,3 @@ var indexedKeyValues = data.IndexName ? this._getIndexedKeyValuesForHash(hash, indexedKeyName) : this._getRangeKeyValuesForHash(hash)

forEachKeyCondition(data, function (condition, key) {
if (!sortByKey && condition.ComparisonOperator != 'EQ') {
if (!sortByKey && condition.op != 'EQ') {
sortByKey = key

@@ -333,7 +342,6 @@ }

var key = this._extractKey(data)
if (data.Expected) {
var item = this._getItemByKey(key)
this._checkExpected(data.Expected, item)
}
var item = this._getItemByKey(key)
this._checkExpected(getConditionFn(data), item)
// create the item to store

@@ -367,5 +375,3 @@ var obj = {}

// run the conditional if it exists
if (data.Expected) {
this._checkExpected(data.Expected, item)
}
this._checkExpected(getConditionFn(data), item)

@@ -384,3 +390,3 @@ var itemExists = !!item

var oldItem = typeUtil.packObjectOrArray(item)
var newItem = localUpdater.update(oldItem, data.AttributeUpdates)
var newItem = localUpdater.update(oldItem, data._requestBuilder._updateExpressionBuilder._attributes)

@@ -406,5 +412,3 @@ // store the item

var item = this._getItemByKey(key)
if (data.Expected) {
this._checkExpected(data.Expected, item)
}
this._checkExpected(getConditionFn(data), item)
this._putItemAtKey(key, undefined)

@@ -467,24 +471,8 @@

*
* @param {Object} expected expected data
* @param {function(Object)} filterFn A filter function that returns false if the item is filtered, true if allowed.
* @param {Object|undefined} currentData current data for the data being changed
*/
FakeTable.prototype._checkExpected = function(expected, currentData) {
for (var key in expected) {
// TODO(nathan) Combine with ConditionBuilder.buildFilterFn
switch (expected[key].ComparisonOperator) {
case 'EQ':
if (!currentData) {
throw new DynamoError('ConditionalCheckFailedException', 'Attribute (' + key + ') missing when expected.')
}
var value = typeUtil.objectToValue(expected[key].AttributeValueList[0])
if (currentData[key] !== value) {
throw new DynamoError('ConditionalCheckFailedException', 'Values are different than expected.')
}
break
case 'NULL':
if (currentData && !typ.isNullish(currentData[key])) {
throw new DynamoError('ConditionalCheckFailedException', 'Attribute (' + key + ') found when none expected.')
}
break
}
FakeTable.prototype._checkExpected = function(filterFn, currentData) {
if (!filterFn(currentData)) {
throw new DynamoError('ConditionalCheckFailedException', 'Values are different than expected.')
}

@@ -491,0 +479,0 @@ }

@@ -26,2 +26,4 @@ var typ = require('typ')

this._returnValues = UpdateBuilder.RETURN_VALUES.ALL_OLD
this._uniqueName = ''
}

@@ -28,0 +30,0 @@ util.inherits(UpdateBuilder, Builder)

{
"name": "dynamite",
"description": "promise-based DynamoDB client",
"version": "0.8.2",
"version": "0.9.0",
"homepage": "https://github.com/Medium/dynamite",

@@ -6,0 +6,0 @@ "license": "Apache-2.0",

@@ -387,4 +387,4 @@ // Copyright 2013 The Obvious Corporation.

test.equal('{"#comment":"comment"}', JSON.stringify(data.ExpressionAttributeNames))
test.equal('{":VC1XcommentX0":{"S":"HEY"}}', JSON.stringify(data.ExpressionAttributeValues))
test.equal('begins_with(#comment, :VC1XcommentX0)', data.KeyConditionExpression)
test.equal('{":VC2":{"S":"HEY"}}', JSON.stringify(data.ExpressionAttributeValues))
test.equal('begins_with(#comment, :VC2)', data.KeyConditionExpression)
test.done()

@@ -391,0 +391,0 @@ })

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc