simple-dynamo is a abstraction layer to simplify Jed Schmidt's dynamo Node.js driver.
is a abstraction layer to Jed Schmidt's dynamo Node.js driver.
Travis currently fails because the credentials are no longer vaild
It provides a absolute simple JSON-CRUD Interface without any knowledge of Dynamos specialties.
A special feature is the combineTableTo options for tables. It adds the ability to combine multiple models into one Dymamo-table, but use them separately in your application. So you have to pay only one throughput capacity.
Need a offline version of Dynamo?
mysql-dynamo is a solution to use the same interface of this simple-dynamo module with a MySQL database.
Written in coffee-script
INFO: all examples are written in coffee-script
npm install simple-dynamo
first you have to define the connection and table attributes and get an instance of the simple-dynamo interface.
new SimpleDynamo( connectionSettings, tables )
An Object of Tables.
The key you are using will be the key to get the table object.
Every object can have the following keys:
String required )String required )String optional: default = S )hashKey. Possible values are: S = String and N = NumericString optional: default = N )rangeKey. Possible values are: S = String and N = NumericFunction optional: default = new UUID )Array optional )options.fields.String optional )
Option to combine multiple models into one dynamo-table. Makes sense if you want to pay only one table. Combinations are not allowed for tables of different types ( Hash-table and HashRange-table ) and you have to use the same hashKey and rangeKey. The module will handle all interactions with the models transparent, so you only have to define this option.name of the table in front of every id/hash.Boolean optional: default = false )create of an existing hash. Boolean optional: default = false )table.get() and table.find() as defaultcb( "my-special-hash" )
Function optional: default = current Timestamp )cb( "my-special-range" )
Array of Objects required )String required )String required )string = String, number = Numeric and array = Array/Set of Strings
Boolean optional: default = false )Example
# import module
SimpleDynamo = require "simple-dynamo"
# define connection settings
connectionSettings =
accessKeyId: "-"
secretAccessKey: "-"
region: "eu-west-1"
# define tables
tables =
"Users":
name: "users"
hashKey: "id"
attributes: [
{ key: "name", type: "string", required: true }
{ key: "email", type: "string" }
]
"Todos":
name: "todos"
hashKey: "id"
rangeKey: "_t"
rangeKeyType: "N"
fnCreateHash: ( attributes, cb )=>
cb( attributes.user_id )
return
attributes: [
{ key: "title", type: "string", required: true }
{ key: "done", type: "number" }
]
# example for a combined table usage
"Combined1":
name: "c1"
hashKey: "id"
combineTableTo: "combined_hash"
attributes: [
{ key: "title", type: "string", required: true }
]
"Combined2":
name: "c2"
hashKey: "id"
combineTableTo: "combined_hash"
attributes: [
{ key: "title", type: "string", required: true }
]
# create instance
sdManager = new SimpleDynamo( connectionSettings, tables )
# connect
sdManager.connect ( err )->
console.log( "simple-dynamo ready to use" )
The module has to know about the existing AWS tables so you have to read them first.
If you do not run .connect() the module will throw an error everytime
Manager.connect( fnCallback ) Arguments :
Function required )null
Example
sdManager.connect ( err )->
if err
console.error( "connect ERROR", err )
else
console.log( "simple-dynamo ready to use" )
to create all missing tables just call .createAll().
This is not necessary if you know the tables has been created in the past.
Note! The generating of tables could take a few Minutes
Manager.generateAll( fnCallback ) Arguments :
Function required )null
Example
sdManager.generateAll ( err )->
if err
console.error( "connect ERROR", err )
else
console.log( "simple-dynamo ready to use" )
To interact with a table you have to retrieve the table object. It's defined in the table-definitions
Manager.get( 'tableName' ) Arguments :
String required )Example
tblTodos = sdManager.get( 'Todos' )
destroy table at AWS. This removes the table from AWS will all the data
Table.destroy( fnCallback ) Arguments :
Function required )null. On an error a object with error and msg
Example
tblTodos.del ( err )->
if err
console.error( "destroy ERROR", err )
else
console.log( "table destroyed" )
Create a new item in a select table. You can also add some attributes not defined in the table-definition, which will be saved, too.
Table.set( data, options, fnCallback ) Arguments :
Object required )name out of the table-config in front of every hash.Object optional )Array ) An array of fields to receiveBoolean optional: default = [tableConfig.overwriteExistingHash] ) Overwrite a item it already exists. Function required )null. On an error a object with error and msg
Example
data =
title: "My First Todo"
done: 0
aditionalData: "Foo bar"
tblTodos.set data, ( err, todo )->
if err
console.error( "insert ERROR", err )
else
console.log( todo )
Get an existing element by id/hash
Table.get( id, fnCallback ) Arguments :
String|Number|Array required )[hash,range] as combined id. Otherwise you will get an error. Object optional )Array ) An array of fields to receive. If nothing is defined all fields are returned.Boolean optional: default = [tableConfig.consistent] ) do a consitent readFunction required )null. On an error a object with error and msg
null
Example
tblTodos.get 'myTodoId', ( err, todo )->
if err
console.error( "get ERROR", err )
else
console.log( todo )
tblRangeTodos.get [ 'myHash', 'myRange' ], ( err, todo )->
if err
console.error( "get ERROR", err )
else
console.log( todo )
Get an many existing elements by id/hash in one request
Table.mget( [ id1, id2, .. ], options, fnCallback ) Arguments :
Array required )[hash,range] as combined id. Otherwise you will get an error. Object optional )Array ) An array of fields to receive. If nothing is defined all fields are returned.Function required )null. On an error a object with error and msg
Example
tblTodos.mget [ 'myTodoIdA', 'myTodoIdB' ], ( err, todos )->
if err
console.error( "get ERROR", err )
else
console.log( todos )
tblRangeTodos.mget [ [ 'myHash', 1 ], [ 'myHash', 2 ] ], ( err, todos )->
if err
console.error( "get ERROR", err )
else
console.log( todos )
update an existing item.
To remove a attribute you have to set the value to null
Table.set( id, data, options, fnCallback ) Arguments :
String|Number|Array required )[hash,range] as combined id. Otherwise you will get an error. Object required )Object optional )Array ) An array of fields to receiveObject ) A query object to define a conditional. Only {"==": value}, {"==": null}, and {"!=": null} are allowed. How to build? … have a look at Jed's Predicates
Function required )null. On an error a object with error and msg
null
Example
data =
title: "My First Update"
done: 1
tblTodos.set 'myTodoId', data, ( err, todo )->
if err
console.error( "update ERROR", err )
else
# note. the key 'aditionalData' will be gone
console.log( todo )
delete an item by id/hash
Table.del( id, fnCallback ) Arguments :
String|Number|Array required )[hash,range] as combined id. Otherwise you will get an error. Function required )null. On an error a object with error and msg
Example
tblTodos.del 'myTodoId', ( err )->
if err
console.error( "delete ERROR", err )
else
console.log( "delete done" )
run a query on a table. The module automatically trys to do a Dynamo.db scan or Dynamo query.
Table.find( query, startAt, options, fnCallback ) Arguments :
Object : default = {} all )String|Number|Array optional )startAt. Usually the last item of a list. If you define startAt with the last item of the previous find you get the next collection of items without the given startAt item.[hash,range] as combined startAt. Otherwise you will get an error. Object optional )Array ) An array of fields to receiveNumber ) Define the max. items to returnBoolean default = true ) define the direction acs or desc for range querys. Boolean optional: default = [tableConfig.consistent] ) do a consitent read.Function required )null. On an error a object with error and msg
Example
tblTodos.find {}, ( err, items )->
if err
console.error( "delete ERROR", err )
else
console.log( "all existend items", items )
Advanced Examples
# create a query to read all todos from last hour
_query =
id: { "!=": null }
_t: { "<": ( Date.now() - ( 1000 * 60 * 60 ) ) }
tblTodos.find , ( err, items )->
if err
console.error( "delete ERROR", err )
else
console.log( "found items", items )
# read 4 todos from last hour beginning starting with a known id
_query =
id: { "!=": null }
_t: { "<": ( Date.now() - ( 1000 * 60 * 60 ) ) }
_startAt = "myid_todoItem12"
_options = { "limit": 4, "fields": [ "id", "_t", "title" ] }
tblTodos.find _query, _startAt, _options, ( err, items )->
if err
console.error( "delete ERROR", err )
else
console.log( "4 found items", items )
Dynamo has the ability to work with sets. That means you can save a Set of Strings as an Array.
During an update you have the ability to add or remove a single value out of the set. Or you can reset the whole set.
But you can only perform one action per key and you obnly can use the functionalty if defined through the table-definition ( type:"array" ).
Existing values will be ignored.
The following key variants are availible:
"key":[ "a", "b", "c" ]': Resets the whole value of the key"key":{ "$add": [ "d", "e" ] }: Add some values to the set"key":{ "$rem": [ "a", "b" ] }: remove some values"key":{ "$reset": [ "x", "y" ] }: reset the whole value. Same as "key":[ "x", "y" ]'
"key":{ "$add": "d"}: Add a single value to the set"key":{ "$rem": "a" }: remove a single value"key":{ "$reset": "y" }: reset the whole set to a single value. Same as "key":[ "y" ]'
Examples
# Source "key: [ "a", "b", "c" ]"
data =
key: [ "x", "y", "z" ]
tblSets.set 'mySetsId', data, ( err, setData )->
# Result "key: [ "x", "y", "z" ]"
console.log( setData )
# Source "key: [ "a", "b", "c" ]"
data =
key: { "$add": [ "a", "d", "e" ] }
tblSets.set 'mySetsId', data, ( err, setData )->
# Result "key: [ "a", "b", "c", "d", "e" ]"
console.log( setData )
# Source "key: [ "a", "b", "c" ]"
data =
key: { "$rem": [ "a", "b", "x" ] }
tblSets.set 'mySetsId', data, ( err, setData )->
# Result "key: [ "c" ]"
console.log( setData )
# Source "key: [ "a", "b", "c" ]"
data =
key: { "$reset": [ "x", "y", "z" ] }
tblSets.set 'mySetsId', data, ( err, setData )->
# Result "key: [ "x", "y", "z" ]"
console.log( setData )
To provide a API to react on different events you can listen to a bunch of events.
new-table: Table object initialized and ready to use. This means only the client model is ready. Eventually you have to create the table first.Table objecttable-generated: Fired after all a new tables has been generated.
Event Argumentsall-tables-generated: Fired after all tables are generated.create-status: fired on table create.already-active, waiting, active
get: fired after a table.get.get-empty: fired after a table.get with an empty result.mget: fired after a table.mget.mget-empty: fired after a table.mget with no results.create: fired after a item has been created.update: fired after a item has been updated.delete: fired after a item has been deleted.BETWEEN predicatesnull will lead to a removal. For a string attribute a set to an empty string will also lead to a attribute removaldefaultfields option to table-config.update by testing for a object with one of the keys $add, $rem and $reset option.forward on find.()
update, no longer with new and old value. Just the new value. This is a victim to the removal of get before set.conditionals to update. So you can define conditions to your updateremoveMissing. Now you have to set a attribute to null to remove it.forward option to .find() to define the direction of a range querythroughput exceedwith a retrysimple-dynamo is work in progress. Your ideas, suggestions etc. are very welcome.
(The MIT License)
Copyright (c) 2010 TCS <dev (at) tcs.de>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.