Code Monkey home page Code Monkey logo

activerecord-hash_options's Introduction

ActiveRecord::HashOptions

What is it?

This enhances active record so that it can be used in more cases than the pure equality case.

Equality only - SOLVED

Active record hash syntax only support equality. For things like case insensitivity or regular expression matching, arel is needed.

It would be nice to use where(:book_count => gt(22)) like type syntax for more complicated operations, too.

Ranges do provide some operations, so a number of these cases may not be necessary. E.g. where(:book_count => 5..)

Problem 2

Active record caches data in an association. When a similar association has a where clause, it also needs to be fetched since the where() clause is only executable in the database.

has_many :books has_many :overdue_books, -> { where(:overdue => true) }

It would be nice to only have 1 copy of the data locally.

Problem 3

Active record only supports sorting case sensitive.

It would be nice to use standard order(insensitive(:name))

Problem 4

The user needs to search and provide custom query logic.

Result

Hash Options handles the first use case but has grand aspirations to handle all 4.

Thanks to the example from codesnik

Usage

There are a number of ways to use active record hash options, contingent upon how much you want to monkey patch your environment.

require 'active_record/hash_options'

Person.where(:name => ActiveRecord::HashOptions::LIKE('Smith%'))
Person.where(:age => ActiveRecord::HashOptions::GTE(21))

require 'active_record/hash_options'
include ActiveRecord::HashOptions

Person.where(:name => LIKE('Smith%'))
Person.where.not(:age => GTE(21))

ActiveRecord::HashOptions.filter(Person.all, :name => LIKE('Smith%'))
ActiveRecord::HashOptions.filter(Person.all.to_a, :name => LIKE('Smith%'))
ActiveRecord::HashOptions.filter(Person.all.to_a, :age => GTE(21), true)

require 'active_record/hash_options'
include ActiveRecord::HashOptions::Helpers

Person.where(:name => like('Smith%'))
Person.where.not(:age => gte(21))

ActiveRecord::HashOptions.filter(Person.all.to_a, :name => like('Smith%'))

require 'active_record/hash_options'
include ActiveRecord::HashOptions::Helpers
Array.send(:include, ActiveRecord::HashOptions::Enumerable)

Person.all.to_a.where(:name => like('Smith%'))
Person.all.to_a.where.not(:age => gte(21))

A note about nil vs null.

Sql uses null to represent unknown, ruby uses nil to represent no value. These are similar. Unfortunatly sql and ruby handle comparisons with these values differently.

In ruby, you can compare a value with nil. x != nil is true and nil == nil is true In sql you can not. x <> null and null = null are both false. Instead, sql has a special operator, IS NULL. x IS NOT NULL and null IS NULL are both true. This causes ruby and sql logic to deviate a little.

ActiveRecord takes the ruby definition of equality and translates where(:x => nil) to be x IS NULL and not literally x == NULL. Please note, this also means a null in a column is handle differently from a null in a literal comparison clause.

The implications can be seen by comparing ruby, sql, and active record of the same logic. The ruby expression is shown, but is easily converted to the other forms:

language expression negation
ruby col == "x" col != "x"
sql WHERE col == "x" WHERE col <> "x"
active record Model.where(:col => "x") Model.where.not(:col => "x")
arel Model.arel_table[:col].eq("x") Model.arel_table[:col].neq("x")
hash_options [].where(:col => "x") [].where.not(:col => "x")

Arel, Active Record, and Hash Options all follow the same logic

expression col value ruby sql Active Record
col == 'x' "x" true true true
col != 'x' "x" false false false
col == nil "x" false false false (treated as IS NULL)
col != nil "x" true false true (treated as IS NOT NULL)
col == nil nil true false true (treated as IS NULL)
col != nil nil false false false (treated as IS NOT NULL)
col IS NULL nil n/a true n/a (merged with the == nil case)
col == 'x' nil false false false (NOTE: these are not treated as IS NULL)
col != 'x' nil true false false
!(col =='x') nil true true true
!(col !='x') nil false true true
!(col ==nil) "x" true true true (treated as IS NULL)
!(col !=nil) "x" false true false? (treated as IS NULL)
col1 == col2 nil,nil true false false (no translation occurs)

So note, in active record, the following nuances occur for the null edge case, especially around inequality. It stems around a null literal is treated differentaly than a null in a column.

Comunicative property does not work: nil != 'x' has a different value from 'x' != nil. Distributive property does not work: nil != 'x' has a different value from !(x == nil). Also note, the in the column to column case, this is not always what the user intended.

Installation

Add this line to your application's Gemfile:

gem 'activerecord-hash_options'

And then execute:

$ bundle

Or install it yourself as:

$ gem install activerecord-hash_options

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake to run the tests.

You can also run bin/console for an interactive prompt that will allow you to experiment. This runs against sqlite and has the Author, Book, Bookmark, and Photo models avaiable for your convenience.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kbrock/activerecord-hash_options.

License

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

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.