Comparing version 0.2.7 to 0.3.0
@@ -1,2 +0,4 @@ | ||
var once = require('once'), | ||
var events = require('events'), | ||
once = require('once'), | ||
Lazy = require('lazy'), | ||
db = require('../db') | ||
@@ -12,7 +14,35 @@ | ||
opts = {}, vals, itemDb = store.getItemDb(data.TableName), | ||
size = 0, capacitySize = 0, count = 0, lastItem | ||
size = 0, capacitySize = 0, count = 0, lastItem, em | ||
hashKey = table.KeySchema[0].AttributeName | ||
if (table.KeySchema[1]) rangeKey = table.KeySchema[1].AttributeName | ||
if (data.IndexName) { | ||
for (i = 0; i < (table.LocalSecondaryIndexes || []).length; i++) { | ||
if (table.LocalSecondaryIndexes[i].IndexName == data.IndexName) { | ||
keySchema = table.LocalSecondaryIndexes[i].KeySchema | ||
if (table.LocalSecondaryIndexes[i].Projection.ProjectionType == 'INCLUDE') | ||
indexAttrs = table.LocalSecondaryIndexes[i].Projection.NonKeyAttributes | ||
break | ||
} | ||
} | ||
for (i = 0; i < (table.GlobalSecondaryIndexes || []).length; i++) { | ||
if (table.GlobalSecondaryIndexes[i].IndexName == data.IndexName) { | ||
if (data.ConsistentRead) | ||
return cb(db.validationError('Consistent reads are not supported on global secondary indexes')) | ||
if (data.Select == 'ALL_ATTRIBUTES' && table.GlobalSecondaryIndexes[i].Projection.ProjectionType != 'ALL') | ||
return cb(db.validationError('One or more parameter values were invalid: ' + | ||
'Select type ALL_ATTRIBUTES is not supported for global secondary index index4 ' + | ||
'because its projection type is not ALL')) | ||
keySchema = table.GlobalSecondaryIndexes[i].KeySchema | ||
if (table.GlobalSecondaryIndexes[i].Projection.ProjectionType == 'INCLUDE') | ||
indexAttrs = table.GlobalSecondaryIndexes[i].Projection.NonKeyAttributes | ||
break | ||
} | ||
} | ||
if (!keySchema) return cb(db.validationError('The table does not have the specified index')) | ||
} else { | ||
keySchema = table.KeySchema | ||
} | ||
hashKey = keySchema[0].AttributeName | ||
if (keySchema[1]) rangeKey = keySchema[1].AttributeName | ||
if (data.ExclusiveStartKey) { | ||
@@ -40,16 +70,2 @@ if (table.KeySchema.some(function(schemaPiece) { return !data.ExclusiveStartKey[schemaPiece.AttributeName] })) { | ||
if (data.IndexName) { | ||
for (i = 0; i < (table.LocalSecondaryIndexes || []).length; i++) { | ||
if (table.LocalSecondaryIndexes[i].IndexName == data.IndexName) { | ||
keySchema = table.LocalSecondaryIndexes[i].KeySchema | ||
if (table.LocalSecondaryIndexes[i].Projection.ProjectionType == 'INCLUDE') | ||
indexAttrs = table.LocalSecondaryIndexes[i].Projection.NonKeyAttributes | ||
break | ||
} | ||
} | ||
if (!keySchema) return cb(db.validationError('The table does not have the specified index')) | ||
} else { | ||
keySchema = table.KeySchema | ||
} | ||
for (i = 0; i < keySchema.length; i++) { | ||
@@ -84,4 +100,41 @@ if (!data.KeyConditions[keySchema[i].AttributeName]) | ||
vals = db.lazy(itemDb.createValueStream(opts), cb) | ||
// TODO: We currently don't deal nicely with indexes or reverse queries | ||
if (data.ScanIndexForward === false || data.IndexName) { | ||
em = new events.EventEmitter | ||
vals = new Lazy(em) | ||
db.lazy(itemDb.createValueStream(), cb) | ||
.filter(function(val) { return db.matchesFilter(val, data.KeyConditions) }) | ||
.join(function(items) { | ||
if (data.IndexName) { | ||
items.sort(function(item1, item2) { | ||
var val1, val2 | ||
if (rangeKey) { | ||
var rangeType = Object.keys(item1[rangeKey] || item2[rangeKey] || {})[0] | ||
val1 = db.toLexiStr(item1[rangeKey][rangeType], rangeType) | ||
val2 = db.toLexiStr(item2[rangeKey][rangeType], rangeType) | ||
} else { | ||
var tableHashKey = table.KeySchema[0].AttributeName, | ||
tableRangeKey = (table.KeySchema[1] || {}).AttributeName, | ||
tableHashType = Object.keys(item1[tableHashKey] || item2[tableHashKey] || {})[0], | ||
tableRangeType = Object.keys(item1[tableRangeKey] || item2[tableRangeKey] || {})[0], | ||
hashVal1 = item1[tableHashKey][tableHashType], | ||
rangeVal1 = (item1[tableRangeKey] || {})[tableRangeType] || '', | ||
hashVal2 = item2[tableHashKey][tableHashType], | ||
rangeVal2 = (item2[tableRangeKey] || {})[tableRangeType] || '' | ||
val1 = db.hashPrefix(hashVal1, tableHashType, rangeVal1, tableRangeType) | ||
val2 = db.hashPrefix(hashVal2, tableHashType, rangeVal2, tableRangeType) | ||
} | ||
return val1.localeCompare(val2) | ||
}) | ||
} | ||
if (data.ScanIndexForward === false) items.reverse() | ||
items.forEach(function(item) { em.emit('data', item) }) | ||
em.emit('end') | ||
}) | ||
} else { | ||
vals = db.lazy(itemDb.createValueStream(opts), cb) | ||
} | ||
vals = vals.filter(function(val) { | ||
@@ -98,4 +151,3 @@ if (!db.matchesFilter(val, data.KeyConditions)) { | ||
vals = vals.takeWhile(function(val) { | ||
// Limits don't currently work for traversing index in reverse | ||
if ((data.ScanIndexForward !== false && count >= data.Limit) || size > 1042000) return false | ||
if (count >= data.Limit || size > 1042000) return false | ||
@@ -123,14 +175,2 @@ size += db.itemSize(val, true) | ||
var result = {Count: items.length} | ||
if (data.Select != 'COUNT') { | ||
if (data.IndexName) { | ||
items.sort(function(item1, item2) { | ||
var type1 = Object.keys(item1[keySchema[1].AttributeName] || {})[0], | ||
val1 = type1 ? item1[keySchema[1].AttributeName][type1] : '', | ||
type2 = Object.keys(item2[keySchema[1].AttributeName] || {})[0], | ||
val2 = type2 ? item2[keySchema[1].AttributeName][type2] : '' | ||
return db.toLexiStr(val1, type1).localeCompare(db.toLexiStr(val2, type2)) | ||
}) | ||
} | ||
if (data.ScanIndexForward === false) items.reverse() | ||
} | ||
// TODO: Check size? | ||
@@ -142,3 +182,3 @@ // TODO: Does this only happen when we're not doing a COUNT? | ||
if (result.Count) { | ||
result.LastEvaluatedKey = table.KeySchema.reduce(function(key, schemaPiece) { | ||
result.LastEvaluatedKey = table.KeySchema.concat(keySchema).reduce(function(key, schemaPiece) { | ||
key[schemaPiece.AttributeName] = items[items.length - 1][schemaPiece.AttributeName] | ||
@@ -145,0 +185,0 @@ return key |
@@ -14,2 +14,3 @@ var crypto = require('crypto'), | ||
exports.toLexiStr = toLexiStr | ||
exports.hashPrefix = hashPrefix | ||
exports.validationError = validationError | ||
@@ -114,3 +115,3 @@ exports.checkConditional = checkConditional | ||
function validateItem(dataItem, table) { | ||
var keyStr, i, j, attr, type, sizeError | ||
var keyStr, i, j, k, attr, type, sizeError | ||
for (i = 0; i < table.KeySchema.length; i++) { | ||
@@ -135,4 +136,19 @@ attr = table.KeySchema[i].AttributeName | ||
} | ||
if (table.GlobalSecondaryIndexes) { | ||
for (i = table.GlobalSecondaryIndexes.length - 1; i >= 0; i--) { | ||
for (k = 0; k < table.GlobalSecondaryIndexes[i].KeySchema.length; k++) { | ||
attr = table.GlobalSecondaryIndexes[i].KeySchema[k].AttributeName | ||
for (j = 0; j < table.AttributeDefinitions.length; j++) { | ||
if (table.AttributeDefinitions[j].AttributeName != attr) continue | ||
type = table.AttributeDefinitions[j].AttributeType | ||
if (dataItem[attr] && !dataItem[attr][type]) | ||
return validationError('One or more parameter values were invalid: ' + | ||
'Type mismatch for Index Key ' + attr + ' Expected: ' + type + ' Actual: ' + | ||
Object.keys(dataItem[attr])[0] + ' IndexName: ' + table.GlobalSecondaryIndexes[i].IndexName) | ||
} | ||
} | ||
} | ||
} | ||
if (table.LocalSecondaryIndexes) { | ||
for (i = 0; i < table.LocalSecondaryIndexes.length; i++) { | ||
for (i = table.LocalSecondaryIndexes.length - 1; i >= 0; i--) { | ||
attr = table.LocalSecondaryIndexes[i].KeySchema[1].AttributeName | ||
@@ -187,12 +203,23 @@ for (j = 0; j < table.AttributeDefinitions.length; j++) { | ||
function hashPrefix(hashKey, type) { | ||
if (type == 'S') { | ||
function hashPrefix(hashKey, hashType, rangeKey, rangeType) { | ||
if (hashType == 'S') { | ||
hashKey = new Buffer(hashKey, 'utf8') | ||
} else if (type == 'N') { | ||
} else if (hashType == 'N') { | ||
hashKey = numToBuffer(hashKey) | ||
} else if (type == 'B') { | ||
} else if (hashType == 'B') { | ||
hashKey = new Buffer(hashKey, 'base64') | ||
} | ||
if (rangeKey) { | ||
if (rangeType == 'S') { | ||
rangeKey = new Buffer(rangeKey, 'utf8') | ||
} else if (rangeType == 'N') { | ||
rangeKey = numToBuffer(rangeKey) | ||
} else if (rangeType == 'B') { | ||
rangeKey = new Buffer(rangeKey, 'base64') | ||
} | ||
} else { | ||
rangeKey = new Buffer(0) | ||
} | ||
// TODO: Can use the whole hash if we deem it important - for now just first six chars | ||
return crypto.createHash('md5').update('Outliers').update(hashKey).digest('hex').slice(0, 6) | ||
return crypto.createHash('md5').update('Outliers').update(hashKey).update(rangeKey).digest('hex').slice(0, 6) | ||
} | ||
@@ -199,0 +226,0 @@ |
{ | ||
"name": "dynalite", | ||
"version": "0.2.7", | ||
"version": "0.3.0", | ||
"description": "A mock implementation of Amazon's DynamoDB built on LevelDB", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -68,4 +68,13 @@ var validateAttributeValue = require('./index').validateAttributeValue | ||
} | ||
if (data.RequestItems[table].AttributesToGet) { | ||
var attrs = Object.create(null) | ||
for (var i = 0; i < data.RequestItems[table].AttributesToGet.length; i++) { | ||
if (attrs[data.RequestItems[table].AttributesToGet[i]]) | ||
return 'One or more parameter values were invalid: Duplicate value in attribute name: ' + | ||
data.RequestItems[table].AttributesToGet[i] | ||
attrs[data.RequestItems[table].AttributesToGet[i]] = true | ||
} | ||
} | ||
} | ||
} | ||
@@ -53,3 +53,12 @@ var validateAttributeValue = require('./index').validateAttributeValue | ||
} | ||
if (data.AttributesToGet) { | ||
var attrs = Object.create(null) | ||
for (var i = 0; i < data.AttributesToGet.length; i++) { | ||
if (attrs[data.AttributesToGet[i]]) | ||
return 'One or more parameter values were invalid: Duplicate value in attribute name: ' + | ||
data.AttributesToGet[i] | ||
attrs[data.AttributesToGet[i]] = true | ||
} | ||
} | ||
} | ||
@@ -141,3 +141,13 @@ var validateAttributeValue = require('./index').validateAttributeValue | ||
} | ||
if (data.AttributesToGet) { | ||
var attrs = Object.create(null) | ||
for (var i = 0; i < data.AttributesToGet.length; i++) { | ||
if (attrs[data.AttributesToGet[i]]) | ||
return 'One or more parameter values were invalid: Duplicate value in attribute name: ' + | ||
data.AttributesToGet[i] | ||
attrs[data.AttributesToGet[i]] = true | ||
} | ||
} | ||
} | ||
@@ -151,3 +151,13 @@ var validateAttributeValue = require('./index').validateAttributeValue | ||
} | ||
if (data.AttributesToGet) { | ||
var attrs = Object.create(null) | ||
for (var i = 0; i < data.AttributesToGet.length; i++) { | ||
if (attrs[data.AttributesToGet[i]]) | ||
return 'One or more parameter values were invalid: Duplicate value in attribute name: ' + | ||
data.AttributesToGet[i] | ||
attrs[data.AttributesToGet[i]] = true | ||
} | ||
} | ||
} | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
116458
2869