579 lines
18 KiB
JavaScript
579 lines
18 KiB
JavaScript
var AWS = require('../core');
|
|
var Translator = require('./translator');
|
|
var DynamoDBSet = require('./set');
|
|
|
|
/**
|
|
* The document client simplifies working with items in Amazon DynamoDB
|
|
* by abstracting away the notion of attribute values. This abstraction
|
|
* annotates native JavaScript types supplied as input parameters, as well
|
|
* as converts annotated response data to native JavaScript types.
|
|
*
|
|
* ## Marshalling Input and Unmarshalling Response Data
|
|
*
|
|
* The document client affords developers the use of native JavaScript types
|
|
* instead of `AttributeValue`s to simplify the JavaScript development
|
|
* experience with Amazon DynamoDB. JavaScript objects passed in as parameters
|
|
* are marshalled into `AttributeValue` shapes required by Amazon DynamoDB.
|
|
* Responses from DynamoDB are unmarshalled into plain JavaScript objects
|
|
* by the `DocumentClient`. The `DocumentClient`, does not accept
|
|
* `AttributeValue`s in favor of native JavaScript types.
|
|
*
|
|
* | JavaScript Type | DynamoDB AttributeValue |
|
|
* |:----------------------------------------------------------------------:|-------------------------|
|
|
* | String | S |
|
|
* | Number | N |
|
|
* | Boolean | BOOL |
|
|
* | null | NULL |
|
|
* | Array | L |
|
|
* | Object | M |
|
|
* | Buffer, File, Blob, ArrayBuffer, DataView, and JavaScript typed arrays | B |
|
|
*
|
|
* ## Support for Sets
|
|
*
|
|
* The `DocumentClient` offers a convenient way to create sets from
|
|
* JavaScript Arrays. The type of set is inferred from the first element
|
|
* in the array. DynamoDB supports string, number, and binary sets. To
|
|
* learn more about supported types see the
|
|
* [Amazon DynamoDB Data Model Documentation](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html)
|
|
* For more information see {AWS.DynamoDB.DocumentClient.createSet}
|
|
*
|
|
*/
|
|
AWS.DynamoDB.DocumentClient = AWS.util.inherit({
|
|
|
|
/**
|
|
* Creates a DynamoDB document client with a set of configuration options.
|
|
*
|
|
* @option options params [map] An optional map of parameters to bind to every
|
|
* request sent by this service object.
|
|
* @option options service [AWS.DynamoDB] An optional pre-configured instance
|
|
* of the AWS.DynamoDB service object to use for requests. The object may
|
|
* bound parameters used by the document client.
|
|
* @option options convertEmptyValues [Boolean] set to true if you would like
|
|
* the document client to convert empty values (0-length strings, binary
|
|
* buffers, and sets) to be converted to NULL types when persisting to
|
|
* DynamoDB.
|
|
* @see AWS.DynamoDB.constructor
|
|
*
|
|
*/
|
|
constructor: function DocumentClient(options) {
|
|
var self = this;
|
|
self.options = options || {};
|
|
self.configure(self.options);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
configure: function configure(options) {
|
|
var self = this;
|
|
self.service = options.service;
|
|
self.bindServiceObject(options);
|
|
self.attrValue = options.attrValue =
|
|
self.service.api.operations.putItem.input.members.Item.value.shape;
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
bindServiceObject: function bindServiceObject(options) {
|
|
var self = this;
|
|
options = options || {};
|
|
|
|
if (!self.service) {
|
|
self.service = new AWS.DynamoDB(options);
|
|
} else {
|
|
var config = AWS.util.copy(self.service.config);
|
|
self.service = new self.service.constructor.__super__(config);
|
|
self.service.config.params =
|
|
AWS.util.merge(self.service.config.params || {}, options.params);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
makeServiceRequest: function(operation, params, callback) {
|
|
var self = this;
|
|
var request = self.service[operation](params);
|
|
self.setupRequest(request);
|
|
self.setupResponse(request);
|
|
if (typeof callback === 'function') {
|
|
request.send(callback);
|
|
}
|
|
return request;
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
serviceClientOperationsMap: {
|
|
batchGet: 'batchGetItem',
|
|
batchWrite: 'batchWriteItem',
|
|
delete: 'deleteItem',
|
|
get: 'getItem',
|
|
put: 'putItem',
|
|
query: 'query',
|
|
scan: 'scan',
|
|
update: 'updateItem',
|
|
transactGet: 'transactGetItems',
|
|
transactWrite: 'transactWriteItems'
|
|
},
|
|
|
|
/**
|
|
* Returns the attributes of one or more items from one or more tables
|
|
* by delegating to `AWS.DynamoDB.batchGetItem()`.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.batchGetItem} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.batchGetItem
|
|
* @example Get items from multiple tables
|
|
* var params = {
|
|
* RequestItems: {
|
|
* 'Table-1': {
|
|
* Keys: [
|
|
* {
|
|
* HashKey: 'haskey',
|
|
* NumberRangeKey: 1
|
|
* }
|
|
* ]
|
|
* },
|
|
* 'Table-2': {
|
|
* Keys: [
|
|
* { foo: 'bar' },
|
|
* ]
|
|
* }
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.batchGet(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
batchGet: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['batchGet'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Puts or deletes multiple items in one or more tables by delegating
|
|
* to `AWS.DynamoDB.batchWriteItem()`.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.batchWriteItem} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.batchWriteItem
|
|
* @example Write to and delete from a table
|
|
* var params = {
|
|
* RequestItems: {
|
|
* 'Table-1': [
|
|
* {
|
|
* DeleteRequest: {
|
|
* Key: { HashKey: 'someKey' }
|
|
* }
|
|
* },
|
|
* {
|
|
* PutRequest: {
|
|
* Item: {
|
|
* HashKey: 'anotherKey',
|
|
* NumAttribute: 1,
|
|
* BoolAttribute: true,
|
|
* ListAttribute: [1, 'two', false],
|
|
* MapAttribute: { foo: 'bar' }
|
|
* }
|
|
* }
|
|
* }
|
|
* ]
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.batchWrite(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
batchWrite: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['batchWrite'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Deletes a single item in a table by primary key by delegating to
|
|
* `AWS.DynamoDB.deleteItem()`
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.deleteItem} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.deleteItem
|
|
* @example Delete an item from a table
|
|
* var params = {
|
|
* TableName : 'Table',
|
|
* Key: {
|
|
* HashKey: 'hashkey',
|
|
* NumberRangeKey: 1
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.delete(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
delete: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['delete'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Returns a set of attributes for the item with the given primary key
|
|
* by delegating to `AWS.DynamoDB.getItem()`.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.getItem} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.getItem
|
|
* @example Get an item from a table
|
|
* var params = {
|
|
* TableName : 'Table',
|
|
* Key: {
|
|
* HashKey: 'hashkey'
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.get(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
get: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['get'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Creates a new item, or replaces an old item with a new item by
|
|
* delegating to `AWS.DynamoDB.putItem()`.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.putItem} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.putItem
|
|
* @example Create a new item in a table
|
|
* var params = {
|
|
* TableName : 'Table',
|
|
* Item: {
|
|
* HashKey: 'haskey',
|
|
* NumAttribute: 1,
|
|
* BoolAttribute: true,
|
|
* ListAttribute: [1, 'two', false],
|
|
* MapAttribute: { foo: 'bar'},
|
|
* NullAttribute: null
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.put(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
put: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['put'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Edits an existing item's attributes, or adds a new item to the table if
|
|
* it does not already exist by delegating to `AWS.DynamoDB.updateItem()`.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.updateItem} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.updateItem
|
|
* @example Update an item with expressions
|
|
* var params = {
|
|
* TableName: 'Table',
|
|
* Key: { HashKey : 'hashkey' },
|
|
* UpdateExpression: 'set #a = :x + :y',
|
|
* ConditionExpression: '#a < :MAX',
|
|
* ExpressionAttributeNames: {'#a' : 'Sum'},
|
|
* ExpressionAttributeValues: {
|
|
* ':x' : 20,
|
|
* ':y' : 45,
|
|
* ':MAX' : 100,
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.update(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
update: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['update'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Returns one or more items and item attributes by accessing every item
|
|
* in a table or a secondary index.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.scan} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.scan
|
|
* @example Scan the table with a filter expression
|
|
* var params = {
|
|
* TableName : 'Table',
|
|
* FilterExpression : 'Year = :this_year',
|
|
* ExpressionAttributeValues : {':this_year' : 2015}
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.scan(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
scan: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['scan'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Directly access items from a table by primary key or a secondary index.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.query} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.query
|
|
* @example Query an index
|
|
* var params = {
|
|
* TableName: 'Table',
|
|
* IndexName: 'Index',
|
|
* KeyConditionExpression: 'HashKey = :hkey and RangeKey > :rkey',
|
|
* ExpressionAttributeValues: {
|
|
* ':hkey': 'key',
|
|
* ':rkey': 2015
|
|
* }
|
|
* };
|
|
*
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* documentClient.query(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
query: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['query'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Synchronous write operation that groups up to 10 action requests
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.transactWriteItems} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.transactWriteItems
|
|
* @example Get items from multiple tables
|
|
* var params = {
|
|
* TransactItems: [{
|
|
* Put: {
|
|
* TableName : 'Table0',
|
|
* Item: {
|
|
* HashKey: 'haskey',
|
|
* NumAttribute: 1,
|
|
* BoolAttribute: true,
|
|
* ListAttribute: [1, 'two', false],
|
|
* MapAttribute: { foo: 'bar'},
|
|
* NullAttribute: null
|
|
* }
|
|
* }
|
|
* }, {
|
|
* Update: {
|
|
* TableName: 'Table1',
|
|
* Key: { HashKey : 'hashkey' },
|
|
* UpdateExpression: 'set #a = :x + :y',
|
|
* ConditionExpression: '#a < :MAX',
|
|
* ExpressionAttributeNames: {'#a' : 'Sum'},
|
|
* ExpressionAttributeValues: {
|
|
* ':x' : 20,
|
|
* ':y' : 45,
|
|
* ':MAX' : 100,
|
|
* }
|
|
* }
|
|
* }]
|
|
* };
|
|
*
|
|
* documentClient.transactWrite(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*/
|
|
transactWrite: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['transactWrite'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Atomically retrieves multiple items from one or more tables (but not from indexes)
|
|
* in a single account and region.
|
|
*
|
|
* Supply the same parameters as {AWS.DynamoDB.transactGetItems} with
|
|
* `AttributeValue`s substituted by native JavaScript types.
|
|
*
|
|
* @see AWS.DynamoDB.transactGetItems
|
|
* @example Get items from multiple tables
|
|
* var params = {
|
|
* TransactItems: [{
|
|
* Get: {
|
|
* TableName : 'Table0',
|
|
* Key: {
|
|
* HashKey: 'hashkey0'
|
|
* }
|
|
* }
|
|
* }, {
|
|
* Get: {
|
|
* TableName : 'Table1',
|
|
* Key: {
|
|
* HashKey: 'hashkey1'
|
|
* }
|
|
* }
|
|
* }]
|
|
* };
|
|
*
|
|
* documentClient.transactGet(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*/
|
|
transactGet: function(params, callback) {
|
|
var operation = this.serviceClientOperationsMap['transactGet'];
|
|
return this.makeServiceRequest(operation, params, callback);
|
|
},
|
|
|
|
/**
|
|
* Creates a set of elements inferring the type of set from
|
|
* the type of the first element. Amazon DynamoDB currently supports
|
|
* the number sets, string sets, and binary sets. For more information
|
|
* about DynamoDB data types see the documentation on the
|
|
* [Amazon DynamoDB Data Model](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModel.DataTypes).
|
|
*
|
|
* @param list [Array] Collection to represent your DynamoDB Set
|
|
* @param options [map]
|
|
* * **validate** [Boolean] set to true if you want to validate the type
|
|
* of each element in the set. Defaults to `false`.
|
|
* @example Creating a number set
|
|
* var documentClient = new AWS.DynamoDB.DocumentClient();
|
|
*
|
|
* var params = {
|
|
* Item: {
|
|
* hashkey: 'hashkey'
|
|
* numbers: documentClient.createSet([1, 2, 3]);
|
|
* }
|
|
* };
|
|
*
|
|
* documentClient.put(params, function(err, data) {
|
|
* if (err) console.log(err);
|
|
* else console.log(data);
|
|
* });
|
|
*
|
|
*/
|
|
createSet: function(list, options) {
|
|
options = options || {};
|
|
return new DynamoDBSet(list, options);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
getTranslator: function() {
|
|
return new Translator(this.options);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
setupRequest: function setupRequest(request) {
|
|
var self = this;
|
|
var translator = self.getTranslator();
|
|
var operation = request.operation;
|
|
var inputShape = request.service.api.operations[operation].input;
|
|
request._events.validate.unshift(function(req) {
|
|
req.rawParams = AWS.util.copy(req.params);
|
|
req.params = translator.translateInput(req.rawParams, inputShape);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
setupResponse: function setupResponse(request) {
|
|
var self = this;
|
|
var translator = self.getTranslator();
|
|
var outputShape = self.service.api.operations[request.operation].output;
|
|
request.on('extractData', function(response) {
|
|
response.data = translator.translateOutput(response.data, outputShape);
|
|
});
|
|
|
|
var response = request.response;
|
|
response.nextPage = function(cb) {
|
|
var resp = this;
|
|
var req = resp.request;
|
|
var config;
|
|
var service = req.service;
|
|
var operation = req.operation;
|
|
try {
|
|
config = service.paginationConfig(operation, true);
|
|
} catch (e) { resp.error = e; }
|
|
|
|
if (!resp.hasNextPage()) {
|
|
if (cb) cb(resp.error, null);
|
|
else if (resp.error) throw resp.error;
|
|
return null;
|
|
}
|
|
|
|
var params = AWS.util.copy(req.rawParams);
|
|
if (!resp.nextPageTokens) {
|
|
return cb ? cb(null, null) : null;
|
|
} else {
|
|
var inputTokens = config.inputToken;
|
|
if (typeof inputTokens === 'string') inputTokens = [inputTokens];
|
|
for (var i = 0; i < inputTokens.length; i++) {
|
|
params[inputTokens[i]] = resp.nextPageTokens[i];
|
|
}
|
|
return self[operation](params, cb);
|
|
}
|
|
};
|
|
}
|
|
|
|
});
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
module.exports = AWS.DynamoDB.DocumentClient;
|