/looksist

Redis backed look up for models

Primary LanguageRubyMIT LicenseMIT

Looksist

Build Status Coverage Status Code Climate Gem Version

looksist (adj) - forming positive prejudices based on appearances

Use this gem when you have to lookup attributes from a key-value store based on another attribute as key. This supports redis out-of-the-box and it's blazing fast!

Installation

Add this line to your application's Gemfile:

gem 'looksist'

And then execute:

$ bundle

Or install it yourself as:

$ gem install looksist

Usage

With Object Models (Her, Active Resource or any of your choice)

  • Add an initializer to configure looksist
Looksist.configure do |looksist|
      looksist.lookup_store = Redis.new(:url => (ENV['REDIS_URL'], :driver => :hiredis)
      looksist.driver =  Looksist::Serializers::Her
end

You need to specify the driver to manage the attributes. In this case, we use HER. You can add support for ActiveResource or ActiveRecord as needed (also refer to specs for free form usage without a driver).

  • Please find the sample rspec to understand the usage and internals
it 'should generate declarative attributes on the model with simple lookup value' do
      module SimpleLookup
        class Employee
          include Looksist
          attr_accessor :id
          lookup :name, using= :id

          def initialize(id)
            @id = id
          end
        end
      end

      expect(Looksist.lookup_store).to receive(:get).with('ids/1').and_return('Employee Name')
      e = SimpleLookup::Employee.new(1)
      expect(e.name).to eq('Employee Name')
end

lookup takes the following form:

# will lookup "employees/#{employee_id}" from the store
lookup :name, using = :employee_id  

# will lookup "stars/#{employee_id}" from the store
lookup :name, using = :employee_id, bucket_name="stars" 

# will lookup "stars/#{employee_id}" from the store 
# for an object with two attributes (name, location)
lookup [:name, :location], using = :employee_id 

With Plain Hashes

Columnar Hashes

  • First Level look ups
it 'should inject multiple attribute to an existing hash' do
      class HashService
        include Looksist

        def metrics
          {
              table: {
                  employee_id: [5, 6],
                  employer_id: [3, 4]
              }
          }
        end

        inject after: :metrics, at: :table, 
                    using: :employee_id, populate: :employee_name
        inject after: :metrics, at: :table, 
                    using: :employer_id, populate: :employer_name
      end
      # Removed mock expectations, look at the tests for actuals
      expect(HashService.new.metrics).to eq({table: {
          employee_id: [5, 6],
          employer_id: [3, 4],
          employee_name: ['emp 5', 'emp 6'],
          employer_name: ['empr 3', 'empr 4']
      }})
    end
  end
it 'should inject multiple attribute to an existing deep hash' do
    class EmployeeHash
      include Looksist

      def metrics
        {
            table: {
                database: {
                    employee_id: [15, 16],
                    employer_id: [13, 14]
                }
            }
        }
      end

      inject after: :metrics, at: '$.table.database', 
                    using: :employee_id, populate: :employee_name
      inject after: :metrics, at: '$.table.database', 
                    using: :employer_id, populate: :employer_name
    end

    # Mocks removed to keep it simple.
    expect(EmployeeHash.new.metrics).to eq({table: {
        database: {
            employee_id: [15, 16],
            employer_id: [13, 14],
            employee_name: ['emp 15', 'emp 16'],
            employer_name: ['empr 13', 'empr 14']
        }
    }})
  end

Non Columnar Hashes

it 'should be capable to deep lookup and inject' do
      class Menu
        include Looksist

        def metrics
          {
              table: {
                  menu: [
                      {
                          item_id: 1
                      },
                      {
                          item_id: 2
                      }
                  ]
              }
          }
        end

        inject after: :metrics, at: '$.table.menu', 
                        using: :item_id, populate: :item_name
      end

      expect(Menu.new.metrics).to eq({
                                       table: {
                                         menu: [{
                                               item_id: 1,
                                               item_name: 'Idly'
                                           },
                                           {
                                               item_id: 2,
                                               item_name: 'Pongal'
                                           }]
                                       }
                                     })
    end