CircleCI

ToWa

"ToWa" adds to_wa method to ActiveRecord based class. to_wa method can receive Hash or JSON argument and add them as Where to ActiveRecord query.

Installation

gem 'to_wa'
bundle install

Use all columns and operators

class TestRecord < ActiveRecord::Base
  extend ToWa

  permit_all_to_wa_operators!
  permit_all_to_wa_columns!

  # read section: Use specific table columns as left and right
  permit_all_to_wa_specified_columns!
end

Or specify columns and operators

class TestRecord < ActiveRecord::Base
  extend ToWa

  permit_to_wa_columns :a, :b, :x
  permit_to_wa_operators :eq, :ne

  # read section: Use specific table columns as left and right
  permit_to_wa_specified_columns foo_records: [:a], bar_records: [:b]
end

Simple usage

TestRecord.to_wa(
  {
    'and': [
      { '=': ['name', 'ToWa'] },
      { '=': ['gender', 'male'] }
    ]
  }
).to_sql
#=> "SELECT `test_records`.* FROM `test_records` WHERE (`test_records`.`name` = 'ToWa' AND `test_records`.`genderb` = 'malebbb')"

Basic syntax

{ "operator": valuesArray }

Comparison operators

They receive [left, right].

{ "=": ["name", "ToWa"] } // means "name eq ToWa"
alias operator
== eq
= eq
eq eq
!= not_eq
<> not_eq
ne not_eq
> gt
gt gt
>= gteq
gteq gteq
< lt
lt lt
<= lteq
lteq lteq
matches matches right like "%right%" (% in right will be escaped.)
like matches
in in right must be Array. left in (right)
between between right must be Array. left between right[0] and right[1]

Logical Operators

They receive data list.

{
  "and": [
    { "=": ["name", "ToWa"] },
    { "=": ["gender", "male"] },
    {
      "or": [
        { "<": ["age", 12] },
        { ">": ["age", 16] }
      ]
    }
  ]
} // means "(name EQ ToWa AND name EQ ToWa AND (age < 12 OR age > 16))"
alias operator
&& and
and and
\ \
or or
not not It must receive Array that includes only one data. { "not": [{ "name": "ToWa" }] }

Usage

(Ofcourse, ActiveRecord::Relation will be provided after to_wa without to_sql.)

TestRecord.to_wa({ '=': ['name', 'ToWa'] }).to_sql
#=> SELECT `test_records`.* FROM `test_records` WHERE `test_records`.`name` = 'ToWa'
TestRecord.to_wa(
  {
    'and': [
      { '=': ['name', 'ToWa'] },
      { '=': ['gender', 'male'] }
    ]
  }
).to_sql
#=> "SELECT `test_records`.* FROM `test_records` WHERE (`test_records`.`name` = 'ToWa' AND `test_records`.`genderb` = 'male')"
TestRecord.to_wa(
  {
    'and': [
      {
        'or': [
          { '=': ['name', 'ToWa'] },
          { '=': ['name', 'to_wa'] }
        ]
      },
      { '=': ['gender', 'male'] }
    ]
  }
).to_sql
#=> "SELECT `test_records`.* FROM `test_records` WHERE ((`test_records`.`name` = 'ToWa' OR `test_records`.`name` = 'to_wa') AND `test_records`.`gender` = 'male')"

Use specific table columns as left and right

class TestRecord < ActiveRecord::Base
  extend ToWa
  has_many :users
end

class User < ActiveRecord::Base
end

TestRecord.left_outer_joins(:users).to_wa(
  {
    '>': [
      { 'col': ['users', 'left_arm_length'] },
      { 'col': ['users', 'right_arm_length'] }
    ]
  }
).to_sql
#=> "SELECT `test_records`.* FROM `test_records` LEFT OUTER JOIN `users` ON `users`.`test_record_id` = `test_records`.`id` WHERE (`users`.`left_arm_length` > `users`.`right_arm_length`)"

Working with other query

TestRecord.select(:id).to_wa({ '=': ['name', 'ToWa'] }).order(id: :desc).to_sql
#=> "SELECT `test_records`.`id` FROM `test_records` WHERE `test_records`.`name` = 'ToWa' ORDER BY `test_records`.`id` DESC"

Providing Arel::Nodes without ActiveRecord based class

a = ToWa(Arel::Table.new('test_records'), { '=': ['name', 'ToWa'] })

a.class
#=> Arel::Nodes::Equality
a.to_sql
#=> "`test_records`.`name` = 'ToWa'"
TestRecord.where(a).to_sql
#=> "SELECT `test_records`.* FROM `test_records` WHERE `test_records`.`name` = 'ToWa'"