lib/dynamoid/criteria/chain.rb in dynamoid-0.5.0 vs lib/dynamoid/criteria/chain.rb in dynamoid-0.6.0

- old
+ new

@@ -14,10 +14,11 @@ # @param [Class] source the class upon which the ultimate query will be performed. def initialize(source) @query = {} @source = source @consistent_read = false + @scan_index_forward = true end # The workhorse method of the criteria chain. Each key in the passed in hash will become another criteria that the # ultimate query must match. A key can either be a symbol or a string, and should be an attribute name or # an attribute name with a range operator. @@ -43,10 +44,67 @@ # # @since 0.2.0 def all records end + + # Destroys all the records matching the criteria. + # + def destroy_all + ids = [] + + if range? + ranges = [] + Dynamoid::Adapter.query(source.table_name, range_query).collect do |hash| + ids << hash[source.hash_key.to_sym] + ranges << hash[source.range_key.to_sym] + end + + Dynamoid::Adapter.delete(source.table_name, ids,{:range_key => ranges}) + elsif index + #TODO: test this throughly and find a way to delete all index table records for one source record + if index.range_key? + results = Dynamoid::Adapter.query(index.table_name, index_query.merge(consistent_opts)) + else + results = Dynamoid::Adapter.read(index.table_name, index_query[:hash_value], consistent_opts) + end + + results.collect do |hash| + ids << hash[source.hash_key.to_sym] + index_ranges << hash[source.range_key.to_sym] + end + + unless ids.nil? || ids.empty? + ids = ids.to_a + + if @start + ids = ids.drop_while { |id| id != @start.hash_key }.drop(1) + index_ranges = index_ranges.drop_while { |range| range != @start.hash_key }.drop(1) unless index_ranges.nil? + end + + if @limit + ids = ids.take(@limit) + index_ranges = index_ranges.take(@limit) + end + + Dynamoid::Adapter.delete(source.table_name, ids) + + if index.range_key? + Dynamoid::Adapter.delete(index.table_name, ids,{:range_key => index_ranges}) + else + Dynamoid::Adapter.delete(index.table_name, ids) + end + + end + else + Dynamoid::Adapter.scan(source.table_name, query, scan_opts).collect do |hash| + ids << hash[source.hash_key.to_sym] + end + + Dynamoid::Adapter.delete(source.table_name, ids) + end + end # Returns the first record matching the criteria. # # @since 0.2.0 def first @@ -61,10 +119,15 @@ def start(start) @start = start self end + def scan_index_forward(scan_index_forward) + @scan_index_forward = scan_index_forward + self + end + # Allows you to use the results of a search as an enumerable over the results found. # # @since 0.2.0 def each(&block) records.each(&block) @@ -143,11 +206,11 @@ if @consistent_read raise Dynamoid::Errors::InvalidQuery, 'Consistent read is not supported by SCAN operation' end - Dynamoid::Adapter.scan(source.table_name, query, query_opts).collect {|hash| source.from_database(hash) } + Dynamoid::Adapter.scan(source.table_name, query, scan_opts).collect {|hash| source.from_database(hash) } end # Format the provided query so that it can be used to query results from DynamoDB. # # @return [Hash] a hash with keys of :hash_value and :range_value @@ -188,11 +251,11 @@ end def range_query opts = { :hash_value => query[source.hash_key] } if key = query.keys.find { |k| k.to_s.include?('.') } - opts.merge!(range_key(key)) + opts.merge!(range_hash(key)) end opts.merge(query_opts).merge(consistent_opts) end # Return an index that fulfills all the attributes the criteria is querying, or nil if none is found. @@ -212,18 +275,27 @@ return false unless source.range_key query_keys == [source.hash_key.to_s] || (query_keys.to_set == [source.hash_key.to_s, source.range_key.to_s].to_set) end def start_key - key = { :hash_key_element => { 'S' => @start.hash_key } } + hash_key_type = @start.class.attributes[@start.class.hash_key][:type] == :string ? 'S' : 'N' + key = { :hash_key_element => { hash_key_type => @start.hash_key.to_s } } if range_key = @start.class.range_key range_key_type = @start.class.attributes[range_key][:type] == :string ? 'S' : 'N' - key.merge!({:range_key_element => { range_key_type => @start.send(range_key) } }) + key.merge!({:range_key_element => { range_key_type => @start.send(range_key).to_s } }) end key end def query_opts + opts = {} + opts[:limit] = @limit if @limit + opts[:next_token] = start_key if @start + opts[:scan_index_forward] = @scan_index_forward + opts + end + + def scan_opts opts = {} opts[:limit] = @limit if @limit opts[:next_token] = start_key if @start opts end