Project

opt_ar

0.0
No release in over 3 years
Low commit activity in last 3 years
Generates memory-optimal immutable ActiveRecord dupes that are easily serializable and behaves much like ARs. Define required attributes before-hand and use them just as you would on an AR, for better memory optimization. Ideally, suitable in place of caching AR objects with cache stores like Memcached, where serialization and de-serialization are memory-hungry. Optars can save upto 90% of your memory(object allocations), while being upto 20x faster, when fetching huge AR results.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.16
~> 5.0
~> 10.0

Runtime

>= 0.3
 Project Readme

OptAR

CircleCI Coverage Status Gem Version

Generates memory-optimal immutable ActiveRecord dupes that are easily serializable and behaves much like ARs. Request attributes that will be read before-hand, and use them later just as you would on an AR, for better memory optimization.

Ideally, suitable in place of caching AR objects with cache stores like Memcached, where serialization and de-serialization are memory-hungry. Optars can save upto 90% of your memory(object allocations), while being upto 20x faster, when fetching huge AR results.

Installation

Add this line to your application's Gemfile:

gem 'opt_ar'

And then execute:

$ bundle

Or install it yourself as:

$ gem install opt_ar

Usage

Declare OptAR scopes for an ActiveRecord model like below

class Employee < ActiveRecord::Base
  self.table_name =  'employee'.freeze
  self.primary_key = 'emp_id'.freeze


  scope :male_employees, lambda {
    where(gender: 1)
  }

  swindle :male_names,
          scope: :male_employees,
          attrs: %i[emp_id first_name last_name]

  swindle :emp_birth_dates
          attrs: %i[birth_date]

  swindle :all_emp_ids
end
  • scope - You can use a predefined scope/association.

If not given, gets the default scope for the model

  • attrs - Request attributes that will be read later. Reading unrequested attributes is an anti-pattern.

If not given, stores only the primary key

 > emp = Employee.male_names
 # [#<OptAR::OAR:0x007fe5d1dc1dd8 @attributes={:emp_id=>10082, :first_name=>"Parviz", :last_name=>"Lortz"}, @klass_name="Employee">, #<OptAR::OAR:0x007fe5d1dc1810 @attributes={:emp_id=>10096, :first_name=>"Jayson", :last_name=>"Mandell"}, @klass_name="Employee">,..]

 > emp.first.first_name
 # => "Parviz"
 
 > emp.first.birth_date
 # WARNING :: Trying to access attr that was not requested :: birth_date
 # Employee Load (1.1ms)  SELECT  `employee`.* FROM `employee` WHERE emp_id=10082 LIMIT 1
 # => Mon, 09 Sep 1963

Things to remember:

  • All OAR objects are immutable. Trying to write or change it will raise exceptions.
  • Again, OARs are read-optimized AR dupes
  • Utilize it better for querying/caching, by defining attributes, only that are required

Use them on AR relations/ Array of ARs as well

 > rel = Employee.all
 
 > rel.optars
 # => [#<OptAR::OAR:0x007fe5d11f2b88 @attributes={:emp_id=>10082}, @klass_name="Employee">, #<OptAR::OAR:0x007fe5d11f25c0 @attributes={:emp_id=>10096}, @klass_name="Employee">,..]
 
 > arr = rel.to_a
 # => [#<OptAR::OAR:0x007fe5d11885f8 @attributes={:emp_id=>10082}, @klass_name="Employee">, #<OptAR::OAR:0x007fe5d11939a8  @attributes={:emp_id=>10096}, @klass_name="Employee">,..]

 > arr.optars(attrs: [:first_name])
 # => [#<OptAR::OAR:0x007fe5d0953400 @attributes={:first_name=>"Parviz", :emp_id=>10082}, @klass_name="Employee">, #<OptAR::OAR:0x007fe5d09530b8 @attributes={:first_name=>"Jayson", :emp_id=>10096}, @klass_name="Employee">,..]
 

On an ActiveRecord,

> emp = Employee.first

> emp.optar(attrs: [:last_name, :birth_date])
# => #<OptAR::OAR:0x007fe5d096d558 @attributes={:last_name=>"Lortz", :birth_date=>Mon, 09 Sep 1963, :emp_id=>10082}, @klass_name="Employee">

created_at and updated_at fields are by default considered to be Time objects. Override them using the const,

    DATE_TIME_ATTRIBUTES = %i[last_login_time]

in your model.

  • Why do I need to do this?

Beleive me, this will spare some memory for you.


Restrict storing sensitive/PII info outside, by blacklisting them. Simply add this const to your model

    BLACKLISTED_ATTRIBUTES = %i[password persist_token]

Benchmarks

Benchmark results for executing selects, marshal dumping and loads on ActiveRecord vs Optars are as follows:

Execution time Memory saved
Select queries 2-4x faster 20-70%
Dumps 2-6x faster 30-80%
Loads 5-20x faster 70-90%

* Larger the data, greater the results

Common caching solutions like Memcached by default, uses Marshalling to store and retrieve objects. Storing and retrieving AR objects, creates a lot of ruby objects in memory, which grows linearly with the number of ARs.

Optars are here to save you, use them well.

Scripts used for benchmarking can be found inside benchmarks folder.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ragav0102/opt_ar. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the OptAR project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Available at https://rubygems.org/gems/opt_ar