require 'aws-sdk' require 'lotus/model/adapters/abstract' require 'lotus/model/adapters/implementation' require 'lotus/model/adapters/dynamodb/coercer' require 'lotus/model/adapters/dynamodb/collection' require 'lotus/model/adapters/dynamodb/command' require 'lotus/model/adapters/dynamodb/query' module Lotus module Model module Adapters # Adapter for Amazon DynamoDB. # # @api private # @since 0.1.0 class DynamodbAdapter < Abstract include Implementation # Initialize the adapter. # # It takes advantage of AWS::DynamoDB::Client to perform all operations. # # @param mapper [Object] the database mapper # # @return [Lotus::Model::Adapters::DynamodbAdapter] # # @see Lotus::Model::Mapper # @see Lotus::Dynamodb::API_VERSION # @see http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/DynamoDB/Client/V20120810.html # # @api private # @since 0.1.0 def initialize(mapper) super @client = AWS::DynamoDB::Client.new( api_version: Lotus::Dynamodb::API_VERSION ) @collections = {} end # Creates a record in the database for the given entity. # It assigns the `id` attribute, in case of success. # # @param collection [Symbol] the target collection (it must be mapped) # @param entity [#id=] the entity to create # # @return [Object] the entity # # @api private # @since 0.1.0 def create(collection, entity) entity.id = command(collection).create(entity) entity end # Updates a record in the database corresponding to the given entity. # # @param collection [Symbol] the target collection (it must be mapped) # @param entity [#id] the entity to update # # @return [Object] the entity # # @api private # @since 0.1.0 def update(collection, entity) command(collection).update(entity) end # Deletes a record in the database corresponding to the given entity. # # @param collection [Symbol] the target collection (it must be mapped) # @param entity [#id] the entity to delete # # @api private # @since 0.1.0 def delete(collection, entity) command(collection).delete(entity) end # Deletes all the records from the given collection. # # This works terribly slow at the moment, and this is only useful for # testing small collections. Consider re-creating table from scratch. # # @param collection [Symbol] the target collection (it must be mapped) # # @api private # @since 0.1.0 def clear(collection) blk = Proc.new {} query(collection, blk).each { |entity| delete(collection, entity) } end # Returns an unique record from the given collection, with the given # id. # # @param collection [Symbol] the target collection (it must be mapped) # @param key [Array] the identity of the object # # @return [Object] the entity # # @api private # @since 0.1.0 def find(collection, *key) command(collection).get(key) end # This method is not implemented. DynamoDB does not allow # table-wide sorting. # # @see http://stackoverflow.com/a/17495069 # # @param collection [Symbol] the target collection (it must be mapped) # # @raise [NotImplementedError] # # @since 0.1.0 def first(collection) raise NotImplementedError end # This method is not implemented. DynamoDB does not allow # table-wide sorting. # # @see http://stackoverflow.com/a/17495069 # # @param collection [Symbol] the target collection (it must be mapped) # # @raise [NotImplementedError] # # @since 0.1.0 def last(collection) raise NotImplementedError end # Fabricates a command for the given query. # # @param collection [Symbol] the target collection (it must be mapped) # # @return [Lotus::Model::Adapters::Dynamodb::Command] # # @see Lotus::Model::Adapters::Dynamodb::Command # # @api private # @since 0.1.0 def command(collection) Dynamodb::Command.new(_collection(collection), _mapped_collection(collection)) end # Fabricates a query # # @param collection [Symbol] the target collection (it must be mapped) # @param context [Object] # @param blk [Proc] a block of code to be executed in the context of # the query. # # @return [Lotus::Model::Adapters::Dynamodb::Query] # # @see Lotus::Model::Adapters::Dynamodb::Query # # @api private # @since 0.1.0 def query(collection, context = nil, &blk) Dynamodb::Query.new(_collection(collection), _mapped_collection(collection), &blk) end private # Returns a collection from the given name. # # @param name [Symbol] a name of the collection (it must be mapped) # # @return [Lotus::Model::Adapters::Dynamodb::Collection] # # @see Lotus::Model::Adapters::Dynamodb::Collection # # @api private # @since 0.1.0 def _collection(name) @collections[name] ||= Dynamodb::Collection.new( @client, Lotus::Model::Adapters::Dynamodb::Coercer.new(_mapped_collection(name)), name, _identity(name), ) end end end end end