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