0.0
No commit activity in last 3 years
No release in over 3 years
Hashed access to in-memory records with ActiveRecord like interface
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

>= 0
>= 0
 Project Readme

HashedRecord

HashedRecord allow to filter in-memory records with ActiveRecord like interface.

example:

We have users with countries we group them into hash and then access by country code as:

users = [
    { username: 'bob', country: 'GB' },
    { username: 'alise', country: 'UA' }
]

hash = users.group_by {|r| r[:country] }
hash['GB'] # => [{:username=>"bob", :country=>"GB"}]

With HashedRecord:

users = HashedRecord.new([
                     { username: 'bob', country: 'GB', group_id: 1 },
                     { username: 'alise', country: 'UA', group_id: 1 },
                     { username: 'serg', country: 'UA', group_id: 2 }
])

users.where(country: 'GB') # => [{:username=>"bob", :country=>"GB", :group_id=>1}]

It supports multiple filters:

users.where(country: 'UA', group_id: 2) # => [{:username=>"serg", :country=>"UA", :group_id=>2}]

It supports array of ids as params:

users.where(country: 'UA', group_id: [1,2]) # => [{:username=>"alise", :country=>"UA", :group_id=>1}, {:username=>"serg", :country=>"UA", :group_id=>2}]

It supports negative filters:

users.not(country: 'UA') # => [{:username=>"bob", :country=>"GB", :group_id=>1}]

It supports chained filters:

users.where(group_id: 1).not(country: 'UA') # => [{:username=>"bob", :country=>"GB", :group_id=>1}]

That allow to make intersections as:

orders = HashedRecord.new([
    { name: 'ball', user_id: 1, category_id: 3 },
    { name: 'rocket', user_id: 1, category_id: 3 }
])
users = HashedRecord.new([
    { id: 1, username: 'bob', country: 'GB' },
    { id: 2, username: 'alise', country: 'UA'}
])

user_ids = orders.where(category_id: 3).map{ |r| r[:user_id] }
users.where(id: user_ids) # => [{:id=>1, :username=>"bob", :country=>"GB"}]

And difference as:

orders = HashedRecord.new([
    { name: 'ball', user_id: 2, category_id: 3 },
    { name: 'rocket', user_id: 2, category_id: 3 }
])
users = HashedRecord.new([
    { id: 1, username: 'bob', country: 'GB' },
    { id: 2, username: 'alise', country: 'UA'}
])

user_ids = orders.where(category_id: 3).map{ |r| r[:user_id] }
users.not(id: user_ids) # => [{:id=>2, :username=>"alise", :country=>"UA"}]

Records data types

It works hashes with string as key:

users = HashedRecord.new([
                     { 'username' => 'bob', 'country' => 'GB' },
                     { 'username' => 'alise', 'country' => 'UA' }
                ])
users.where(country: 'GB') # => [{"username"=>"bob", "country"=>"GB"}]

It works with objects:

users = HashedRecord.new([
                     OpenStruct.new(username: 'bob', country: 'GB'),
                     OpenStruct.new(username: 'alise', country: 'UA')
                ])
users.where(country: 'GB') # => [#<OpenStruct username="bob", country="GB">, #<OpenStruct username="alise", country="UA">]

It allow to specify custom access method:

users = HashedRecord.new([
                     { attributes: { username: 'bob', country: 'GB' } },
                     { attributes: { username: 'alise', country: 'UA' } }
                ], access_method: ->(record, key) { record[:attributes].send(:[], key) })
users.where(country: 'GB') # => [{:attributes=>{:username=>"bob", :country=>"GB"}}]

Performance

Under the hood HashedRecord use ruby hashes, and that makes record access as fast as O(1)

Activerecord and Enumerable

You can extend Enumerable as:

module Enumerable
  def to_hashed
     HashedRecord.new(to_a)
  end
end

That allow to filter as:

users = [
  { 'username' => 'bob', 'country' => 'GB' },
  { 'username' => 'alise', 'country' => 'UA' }
]
users.to_hashed.where(username: 'bob') # => [{:username=>"bob", :country=>"GB"}]

And handle activerecord relation as:

Users.where(country: 'GB').to_hashed.where(group_id: [...])

Install

gem install hashedrecord

or in your Gemfile

gem 'hashedrecord'