-
-
Notifications
You must be signed in to change notification settings - Fork 16
Predicate Builder
This is just somewhat specific to PostgreSQL, but mostly an enhancement to Rails ActiveRecord::PredicateBuilder
, whose primary purpose is to make .where
and .where.not
calls in the format for (attribute: value)
correctly translate into several distinct Arel and SQL operations. Its sole purpose is to ease the process of writing queries, without the need to use Arel directly for everything.
The inspiration for these features, and some notable examples, is the handling of Array
, Range
, and ActiveRecord::Base
(A model). Each one of them gives the developer exactly what they would expect from their respective operation. That said, here are a few more options that are now made available.
You can pick and choose the ones you want enabled/disabled using predicate_builder.enabled
config.
Translate the given Regexp into a bind param while identifying the proper infix operator to use based on the case-insensitive indicator.
Video.where(title: /(one|two)/) # WHERE "videos"."title" ~ '(one|two)'
Video.where(title: /(one|two)/i) # WHERE "videos"."title" ~* '(one|two)'
The rare use of [].lazy
, where we would usually have to call .force
, but there are cases where we would like to support both lazy and non-lazy operations simultaneously. This also makes it safe to use due to predicate_builder.lazy_timeout
and predicate_builder.lazy_limit
, which limit the resources used.
Video.where(user_id: [1,2].lazy) # WHERE "videos"."user_id" IN (1,2)
At first, this may seem unnecessary. However, when working with joins, this can be particularly helpful.
Video.joins(:tags).where(language: Tag.arel_table['language']) # WHERE "videos"."language" = "tags"."language"
Another great advantage of this is the proper handling of array columns, which completely facilitated the operations of Belongs to Many features.
Video.where(tag_ids: Tag.arel_table['id']) # WHERE "tags"."id" = ANY("videos"."tag_ids")
Tag.where(id: Video.arel_table['tag_ids']) # WHERE "tags"."id" = ANY("videos"."tag_ids")
Video.where(tag_ids: User.arel_table['tag_ids']) # WHERE "videos"."tag_ids" && "users"."tag_ids"
This feature needs to be enabled via
predicate_builder.handle_array_attributes
because it may break the current state of your application if you have been using.where
with array columns and any type of value (eg,.where(tag_ids: [1,2,3])
).
The primary purpose of this feature is to more accurately convey the meaning of array and non-array values in these operations. It only takes place when .where
is used against an array column.
Video.where(tag_ids: [1,2,3]) # WHERE "videos"."tag_ids" && '{1,2,3}'
Video.where(tag_ids: 1) # WHERE 1 = ANY("videos"."tag_ids")
Video.where(tag_ids: []) # WHERE CARDINALITY("videos"."tag_ids") = 0
Can't find what you're looking for? Add an issue to the issue tracker.