# frozen_string_literal: true require_relative 'middleware/backoff' require_relative 'middleware/limit' require_relative 'middleware/start_key' module Dynamoid module AdapterPlugin class AwsSdkV3 class Scan attr_reader :client, :table, :conditions, :options def initialize(client, table, conditions = {}, options = {}) @client = client @table = table @conditions = conditions @options = options end def call request = build_request Enumerator.new do |yielder| api_call = lambda do |req| client.scan(req).tap do |response| yielder << response end end middlewares = Middleware::Backoff.new( Middleware::StartKey.new( Middleware::Limit.new(api_call, record_limit: record_limit, scan_limit: scan_limit) ) ) catch :stop_pagination do loop do middlewares.call(request) end end end end private def build_request request = options.slice( :consistent_read, :exclusive_start_key, :select ).compact # Deal with various limits and batching batch_size = options[:batch_size] limit = [record_limit, scan_limit, batch_size].compact.min request[:limit] = limit if limit request[:table_name] = table.name request[:scan_filter] = scan_filter request[:attributes_to_get] = attributes_to_get request end def record_limit options[:record_limit] end def scan_limit options[:scan_limit] end def scan_filter conditions.reduce({}) do |result, (attr, cond)| condition = { comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]], attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze) } # nil means operator doesn't require attribute value list conditions.delete(:attribute_value_list) if conditions[:attribute_value_list].nil? result[attr] = condition result end end def attributes_to_get return if options[:project].nil? options[:project].map(&:to_s) end end end end end