Skip to content

Implement Ruby on Rail's hash conditions #83

@ipundit

Description

@ipundit

Some of RoR's hash conditions are implemented, others are not, and others are implemented differently. This issue is to decide on a consistent API for replicating these features.

From: https://guides.rubyonrails.org/active_record_querying.html#hash-conditions

  1. Range conditions is currently not implemented
    Book.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
    generates
    SELECT * FROM books WHERE (books.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00')

and
Book.where(created_at: (Time.now.midnight - 1.day)..)
generates
SELECT * FROM books WHERE books.created_at >= '2008-12-21 00:00:00'

2. Not conditions are implemented differently
RoR: Customer.where.not(orders_count: [1,3,5])
ActiveRecord:

Customer::not(orders_count: [1,3,5])

This is fine, unless we want not to support the negation of non-where clauses like:

Customer::having()->not(orders_count: [1,3,5])

which is not something RoR supports. Decided that it's not worth supporting.

  1. Nullable fields are not tested. I'm not sure if this works:
Customer.create!(nullable_contry: nil)
Customer.where.not(nullable_country: "UK")
=> []
# But
Customer.create!(nullable_contry: "UK")
Customer.where.not(nullable_country: nil)
=> [#<Customer id: 2, nullable_contry: "UK">]
  1. Or is not yet implemented and neither is and:
    RoR: Customer.where(last_name: 'Smith').or(Customer.where(orders_count: [1,3,5]))
    RoR: Customer.where(last_name: 'Smith').and(Customer.where(orders_count: [1,3,5]))

But if we keep the API breakage theme with not(), wouldn't this be better?

Customer::where(['last_name' => 'Smith'])->or(['orders_count' => [1,3,5])

But what about?

Customer::where(A)->or(B)->and(C)

is this A or (B and C) or (A or B) and C?

The advantage of RoR's implementation of or is that you can remove the ambiguity:

A or (B and C): Customer.where(A)->or(Customer::where(B)->where(C))
(A or B) and C: Customer.where(A)->or(Customer::where(B))->where(C)

But if you want to be consistent which RoR is not, and be able to negate OR'd and AND'ed clauses, then it should be:

Customer::not(Customer::where(A))

so you can do:

Customer::not(Customer::where(A)->or(Customer::where(B)->where(C)))

and perhaps:

Customer::not(Customer::having(A)->or(Customer::having(B)->having(C)))

if it's worth implementing. It's not.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions