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