lib/daru/io/importers/redis.rb
require 'daru/io/importers/base' module Daru module IO module Importers # Redis Importer Class, that extends `from_redis` method to `Daru::DataFrame` class Redis < Base Daru::DataFrame.register_io_module :from_redis, self # Checks for required gem dependencies of Redis Importer def initialize require 'json' optional_gem 'redis' end # Loads data from a given connection # # @!method self.from(connection) # # @param connection [Hash or Redis Instance] Either a Hash of *Redis* configurations, # or an existing *Redis* instance. For the hash configurations, have a # look at # [Redis#initialize](http://www.rubydoc.info/github/redis/redis-rb/Redis:initialize). # # @return [Daru::IO::Importers::Redis] # # @example Loading from a hash # instance = Daru::IO::Importers::Redis.from({url: "redis://:[password]@[hostname]:[port]/[db]"}) # # @example Loading from a Redis connection # instance = Daru::IO::Importers::Redis.from(Redis.new({url: "redis://:[password]@[hostname]:[port]/[db]"})) def from(connection={}) @client = get_client(connection) self end # Imports a `Daru::DataFrame` from a Redis Importer instance # # @param keys [Array] Redis key(s) from whom, the `Daru::DataFrame` # should be constructed. If no keys are given, all keys in the *Redis* # connection will be used. # @param match [String] A pattern to get matching keys. # @param count [Integer] Number of matching keys to be obtained. Defaults to # nil, to collect ALL matching keys. # # @return [Daru::DataFrame] # # @example Importing with no options # # Say, the Redis connection has this setup # # Key "10001" => { "name" => "Tyrion", "age" => 32 }.to_json # # Key "10002" => { "name" => "Jamie", "age" => 37 }.to_json # # Key "10003" => { "name" => "Cersei", "age" => 37 }.to_json # # Key "10004" => { "name" => "Joffrey", "age" => 19 }.to_json # # df = instance.call # # #=> <Daru::DataFrame(4x2)> # # name age # # 10001 Tyrion 32 # # 10002 Jamie 37 # # 10003 Cersei 37 # # 10004 Joffrey 19 # # @example Importing with keys # # Say, the Redis connection has this setup # # Key "10001" => { "name" => "Tyrion", "age" => 32 }.to_json # # Key "10002" => { "name" => "Jamie", "age" => 37 }.to_json # # Key "10003" => { "name" => "Cersei", "age" => 37 }.to_json # # Key "10004" => { "name" => "Joffrey", "age" => 19 }.to_json # # df = instance.call("10001", "10002") # # #=> <Daru::DataFrame(2x2)> # # name age # # 10001 Tyrion 32 # # 10002 Jamie 37 # # @example Importing with query for matching keys and count # # Say, the Redis connection has this setup # # Key "key:1" => { "name" => "name1", "age" => "age1" }.to_json # # Key "key:2" => { "name" => "name2", "age" => "age2" }.to_json # # Key "key:3" => { "name" => "name3", "age" => "age3" }.to_json # # ... # # Key "key:2000" => { "name" => "name2000", "age" => "age2000" }.to_json # # df = instance.call(match: "key:1*", count: 200) # # #=> #<Daru::DataFrame(200x2)> # # name age # # key:1927 name1927 age1927 # # key:1759 name1759 age1759 # # key:1703 name1703 age1703 # # key:1640 name1640 age1640 # # ... ... ... def call(*keys, match: nil, count: nil) @match = match @count = count @keys = keys @keys = choose_keys(*@keys).map(&:to_sym) vals = @keys.map { |key| ::JSON.parse(@client.get(key), symbolize_names: true) } Base.guess_parse(@keys, vals) end private Method `choose_keys` has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring. def choose_keys(*keys) return keys.to_a unless keys.empty? cursor = nil # Loop to iterate through paginated results of Redis#scan. until cursor == '0' || (!@count.nil? && keys.count > (@count-1)) cursor, chunk = @client.scan(cursor, match: @match, count: @count) keys.concat(chunk).uniq! end return keys[0..-1] if @count.nil? keys[0..@count-1] end def get_client(connection) case connection when ::Redis connection when Hash ::Redis.new connection else raise ArgumentError, "Expected '#{connection}' to be either "\ 'a Hash or an initialized Redis instance, '\ "but received #{connection.class} instead." end end end end endend