Code Monkey home page Code Monkey logo

relation_to_struct's Introduction

RelationToStruct

Build Status

When one needs to use ActiveRecord to fetch specific values (whether subset columns of a model or arbitrary calculated columns), it's desirable to avoid the overhead of model instances and any associated callbacks.

ActiveRecord::Relation#pluck solves a similar problem but returns tuples; I wanted to be able to return Ruby structs to benefit from named instance methods.

Installation

Add this line to your application's Gemfile:

gem 'relation_to_struct'

And then execute:

$ bundle

Or install it yourself as:

$ gem install relation_to_struct

Examples

You can query either via direct SQL or from an ActiveRecord relation.

From an existing relation

UserPostsSummary = Struct.new(:user_name, :post_count)
relation = User.joins(:blog_posts).where(name: 'Hayek').group('users.id').select('users.name, COUNT(blog_posts.id)')
relation.to_structs(UserPostsSummary) # => array of structs

From raw SQL

Note: In order to provide a consistent user experience regardless of the abstraction level used by your code, all of the following methods are available on both ActiveRecord::Base and ActiveRecord::Base.connection.

UserPostsSummary = Struct.new(:user_name, :post_count)
sql = <<-eos
  SELECT users.name, COUNT(blog_posts.id)
  FROM users
  LEFT OUTER JOIN blog_posts ON blog_posts.user_id = users.id
  GROUP BY users.id
eos

ActiveRecord::Base.structs_from_sql(UserPostsSummary, sql) # => array of structs
ActiveRecord::Base.pluck_from_sql(sql) # => array of tuples
sql = <<-eos
  SELECT users.name
  FROM users
  LIMIT 1
eos

ActiveRecord::Base.value_from_sql(sql) # => single value
sql = <<-eos
  SELECT users.id, users.name
  FROM users
  LIMIT 1
eos

ActiveRecord::Base.tuple_from_sql(sql) # => [id, name]
sql = <<-eos
  SELECT 1
eos

ActiveRecord::Base.run_sql(sql) # => <no defined result>
sql = <<-eos
  INSERT INTO foos(bar) VALUES(1)
eos

ActiveRecord::Base.run_sql(sql) # => <number of rows modified>

Project Policy/Philosophy

Executing database queries should be clearly explicit in your application code. Implicit queries (e.g., in association accesses) is an anti-pattern that results in problems like N+1 querying.

Query Caching

Query caching is another problem downstream from implicit querying. Because queries are happening "behind the scenes" and there's no obvious place for explicit result caching, it seems desirable to cache at the query level. But this approach applies caching at the wrong level: your application code must still expend all of the effort required to build a SQL query and (potentially) interpret results. Caching queries automatically (as Rails does by default in a web request) can easily lead to gotchas because the framework has no way of determining when caching is actually safe (both from a business logic and query contents perspective).

For this reason, all methods added to ActiveRecord::Base explicitly disable query caching. Rails defaults are respected, however, on extensions to ActiveRecord::Relation since it's not as obvious that those queries are intended to be explicit.

Contributing

  1. Fork it ( https://github.com/jcoleman/relation_to_struct/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Test your changes (bundle install && bundle exec appraisal install && bundle exec rake)
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request

Releasing

  1. Bump version in lib/relation_to_struct/version.rb and commit.
  2. Run rake build to build the *.gem file.
  3. Run rake release to publish the gem to Rubygems. Note: if while releasing the gem you get the error Your rubygems.org credentials aren't set. Run `gem push` to set them. you can more simply run gem signin.

relation_to_struct's People

Contributors

braintreeps avatar jcoleman avatar rkrage avatar roman-melnyk avatar shaicoleman avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.