lib/dynamoid/criteria/chain.rb in dynamoid-3.2.0 vs lib/dynamoid/criteria/chain.rb in dynamoid-3.3.0
- old
+ new
@@ -157,10 +157,15 @@
def find_by_pages(&block)
pages.each(&block)
end
+ def project(*fields)
+ @project = fields.map(&:to_sym)
+ self
+ end
+
private
# The actual records referenced by the association.
#
# @return [Enumerator] an iterator of the found records.
@@ -188,26 +193,32 @@
#
# @return [Enumerator] an iterator of the found pages. An array of records
#
# @since 3.1.0
def pages_via_query
- Enumerator.new do |yielder|
+ Enumerator.new do |y|
Dynamoid.adapter.query(source.table_name, range_query).each do |items, metadata|
- yielder.yield items.map { |hash| source.from_database(hash) }, metadata.slice(:last_evaluated_key)
+ page = items.map { |h| source.from_database(h) }
+ options = metadata.slice(:last_evaluated_key)
+
+ y.yield page, options
end
end
end
# If the query does not match an index, we'll manually scan the associated table to find results.
#
# @return [Enumerator] an iterator of the found pages. An array of records
#
# @since 3.1.0
def pages_via_scan
- Enumerator.new do |yielder|
+ Enumerator.new do |y|
Dynamoid.adapter.scan(source.table_name, scan_query, scan_opts).each do |items, metadata|
- yielder.yield(items.map { |hash| source.from_database(hash) }, metadata.slice(:last_evaluated_key))
+ page = items.map { |h| source.from_database(h) }
+ options = metadata.slice(:last_evaluated_key)
+
+ y.yield page, options
end
end
end
def issue_scan_warning
@@ -269,10 +280,17 @@
{ in: val }
when 'contains'
{ contains: val }
when 'not_contains'
{ not_contains: val }
+ # NULL/NOT_NULL operators don't have parameters
+ # So { null: true } means NULL check and { null: false } means NOT_NULL one
+ # The same logic is used for { not_null: BOOL }
+ when 'null'
+ val ? { null: nil } : { not_null: nil }
+ when 'not_null'
+ val ? { not_null: nil } : { null: nil }
end
{ name.to_sym => hash }
end
@@ -312,14 +330,19 @@
end
opts.merge(query_opts).merge(consistent_opts)
end
+ # TODO casting should be operator aware
+ # e.g. for NULL operator value should be boolean
+ # and isn't related to an attribute own type
def type_cast_condition_parameter(key, value)
return value if %i[array set].include?(source.attributes[key.to_sym][:type])
- if !value.respond_to?(:to_ary)
+ if [true, false].include?(value) # Support argument for null/not_null operators
+ value
+ elsif !value.respond_to?(:to_ary)
options = source.attributes[key.to_sym]
value_casted = TypeCasting.cast_field(value, options)
Dumping.dump_field(value_casted, options)
else
value.to_ary.map do |el|
@@ -354,17 +377,20 @@
key
end
def query_opts
opts = {}
+ # Don't specify select = ALL_ATTRIBUTES option explicitly because it's
+ # already a default value of Select statement. Explicite Select value
+ # conflicts with AttributesToGet statement (project option).
opts[:index_name] = @key_fields_detector.index_name if @key_fields_detector.index_name
- opts[:select] = 'ALL_ATTRIBUTES'
opts[:record_limit] = @record_limit if @record_limit
opts[:scan_limit] = @scan_limit if @scan_limit
opts[:batch_size] = @batch_size if @batch_size
opts[:exclusive_start_key] = start_key if @start
opts[:scan_index_forward] = @scan_index_forward
+ opts[:project] = @project
opts
end
def scan_query
{}.tap do |opts|
@@ -384,9 +410,10 @@
opts[:record_limit] = @record_limit if @record_limit
opts[:scan_limit] = @scan_limit if @scan_limit
opts[:batch_size] = @batch_size if @batch_size
opts[:exclusive_start_key] = start_key if @start
opts[:consistent_read] = true if @consistent_read
+ opts[:project] = @project
opts
end
end
end
end