Module: ActiveRecord::Refined::AST::Predications
- Included in:
- Aggregate, Arithmetic, Bitwise, BitwiseNot, Case, Cast, Collate, Column, DatetimeValueFunction, Extract, Function, JsonAggregate, JsonBuild, JsonExcept, JsonKeys, JsonPath, JsonSet, Operation, Over, Sql, StringAggregate, Value, BlockSyntax
- Defined in:
- lib/active_record/refined/ast.rb
Overview
The conditions a column or an expression can be put in. Every one
gives back a condition that combines with &, | and !, and the
comparisons quote a Ruby value on the right the way Active Record
does, or take a column, an expression or a subquery there.
Predicate builders shared by symbols, qualified columns and expressions. Imported into the Symbol refinement with Refinement#import_methods, so every method must be defined with def.
Instance Method Summary collapse
-
#!=(other) ⇒ AST::Predicate
!=;nilis refused, as with==. -
#!~(pattern) ⇒ AST::Predicate
The negated regular expression match.
-
#<(other) ⇒ AST::Predicate
<. -
#<=(other) ⇒ AST::Predicate
<=. -
#==(other) ⇒ AST::Predicate
=. -
#=~(pattern) ⇒ AST::Predicate
A regular expression match:
~on PostgreSQL,REGEXPon MySQL, and what the adapter has elsewhere. -
#>(other) ⇒ AST::Predicate
>. -
#>=(other) ⇒ AST::Predicate
>=. -
#between?(min, max) ⇒ AST::Predicate
BETWEEN min AND max, with either end a value, a column or an expression. -
#bury(*path, value) ⇒ AST::JsonSet
The document with a value set at a path, as #dig reads one; an expression, for
update_allto write back. -
#casecmp?(value) ⇒ AST::Predicate
Case-insensitive equality:
LOWER(column) = LOWER(value). -
#contains?(value) ⇒ AST::Predicate
Whether the document contains the Ruby document given, which SQL calls containment:
@>on PostgreSQL,JSON_CONTAINSon MySQL. -
#dig(*path) ⇒ AST::JsonPath
The JSON at a path into a JSON column, still JSON -- to be dug further, compared with a Ruby value, or asked #key? and the rest.
-
#dig_text(*path) ⇒ AST::JsonPath
The value at a path as text, which is what a comparison against a string wants where the JSON type would not do:
#>>on PostgreSQL,JSON_UNQUOTE(JSON_EXTRACT(...))on MySQL,->>on SQLite. -
#distinct_from?(value) ⇒ AST::Predicate
IS DISTINCT FROM:!=that treats NULL as a value. -
#end_with?(*suffixes) ⇒ AST::Predicate
LIKE '%suffix', escaped as #start_with? escapes. -
#except(*keys) ⇒ AST::JsonExcept
The document without the keys given, as Hash#except gives it; an expression, for
update_allto write back. -
#false? ⇒ AST::Predicate
IS FALSE. -
#ilike?(pattern) ⇒ AST::Predicate
A case-insensitive
LIKE:ILIKEon PostgreSQL, andLIKEover both sides lower-cased elsewhere. -
#in?(values) ⇒ AST::Predicate
IN (...): an array of values, a range, or a relation as a subquery. -
#include?(substring) ⇒ AST::Predicate
LIKE '%substring%', escaped as #start_with? escapes. -
#intersect?(elements) ⇒ AST::Predicate
Whether an array column and the elements given share any:
&&. -
#key?(key) ⇒ AST::Predicate
Whether the object has the key, as Hash#key? asks.
-
#keys ⇒ AST::JsonKeys
The keys of the object as a JSON array, as Hash#keys gives them.
-
#like?(pattern) ⇒ AST::Predicate
LIKE pattern, the pattern as written:%and_are its wildcards. -
#member?(element) ⇒ AST::Predicate
Whether a PostgreSQL array column holds the element:
@> ARRAY[element]. -
#not_between?(min, max) ⇒ AST::Predicate
NOT BETWEEN min AND max. -
#not_distinct_from?(value) ⇒ AST::Predicate
IS NOT DISTINCT FROM:=that treats NULL as a value, so this is the one equality that takesnil. -
#not_false? ⇒ AST::Predicate
IS NOT FALSE. -
#not_ilike?(pattern) ⇒ AST::Predicate
The negated case-insensitive
LIKE. -
#not_in?(values) ⇒ AST::Predicate
NOT IN (...). -
#not_like?(pattern) ⇒ AST::Predicate
NOT LIKE pattern. -
#not_null? ⇒ AST::Predicate
IS NOT NULL. -
#not_true? ⇒ AST::Predicate
IS NOT TRUE: keeps the NULL rows that!(:flag == true)drops. -
#null? ⇒ AST::Predicate
IS NULL. -
#start_with?(*prefixes) ⇒ AST::Predicate
LIKE 'prefix%', the prefix escaped so that a%or_in it is itself; several prefixes areORed. -
#subset?(elements) ⇒ AST::Predicate
Whether every element of an array column is among those given:
<@. -
#superset?(elements) ⇒ AST::Predicate
Whether an array column holds every element given:
@>. -
#true? ⇒ AST::Predicate
IS TRUE: true of the rows where the boolean is true, false where it is false or NULL -- where== truewould be NULL. -
#when(value = nil, &block) ⇒ AST::Case::When
CASE column WHEN value THEN ...: a CASE with this as the operand, eachwhena value it is compared against, followed bythenand finallyelse.
Instance Method Details
#!=(other) ⇒ AST::Predicate
!=; nil is refused, as with ==.
119 120 121 122 123 124 |
# File 'lib/active_record/refined/ast.rb', line 119 def !=(other) if other.nil? raise ArgumentError, "!= does not take nil; use !null? instead" end Comparison.new(self, :!=, other) end |
#!~(pattern) ⇒ AST::Predicate
The negated regular expression match.
161 162 163 |
# File 'lib/active_record/refined/ast.rb', line 161 def !~(pattern) Match.new(self, pattern, negated: true) end |
#<(other) ⇒ AST::Predicate
<.
140 141 142 |
# File 'lib/active_record/refined/ast.rb', line 140 def <(other) Comparison.new(self, :<, other) end |
#<=(other) ⇒ AST::Predicate
<=.
146 147 148 |
# File 'lib/active_record/refined/ast.rb', line 146 def <=(other) Comparison.new(self, :<=, other) end |
#==(other) ⇒ AST::Predicate
=. A value, a column, an expression or a scalar subquery on the right; nil is refused, since = NULL is never true -- #null? is the spelling.
and != mean SQL = and <>, and = NULL is never true there, so nil
is rejected rather than silently rewritten to IS NULL. null? builds its node directly and stays clear of this check.
110 111 112 113 114 115 |
# File 'lib/active_record/refined/ast.rb', line 110 def ==(other) if other.nil? raise ArgumentError, "== does not take nil; use null? instead" end Comparison.new(self, :==, other) end |
#=~(pattern) ⇒ AST::Predicate
A regular expression match: ~ on PostgreSQL, REGEXP on MySQL, and what the adapter has elsewhere. A Ruby Regexp's source is the pattern.
155 156 157 |
# File 'lib/active_record/refined/ast.rb', line 155 def =~(pattern) Match.new(self, pattern) end |
#>(other) ⇒ AST::Predicate
>.
128 129 130 |
# File 'lib/active_record/refined/ast.rb', line 128 def >(other) Comparison.new(self, :>, other) end |
#>=(other) ⇒ AST::Predicate
>=.
134 135 136 |
# File 'lib/active_record/refined/ast.rb', line 134 def >=(other) Comparison.new(self, :>=, other) end |
#between?(min, max) ⇒ AST::Predicate
BETWEEN min AND max, with either end a value, a column or an expression.
Not min..max: an endpoint may be an expression, which Range would
refuse to hold, since expressions do not compare among themselves.
239 240 241 |
# File 'lib/active_record/refined/ast.rb', line 239 def between?(min, max) In.new(self, In::QuotedRange.new(min, max, false)) end |
#bury(*path, value) ⇒ AST::JsonSet
The document with a value set at a path, as #dig reads one; an expression, for update_all to write back.
What dig reads, bury sets: the last argument is the value and the
rest are the path to it. The document comes back changed rather
than being written anywhere, which update_all is for.
429 430 431 |
# File 'lib/active_record/refined/ast.rb', line 429 def bury(*path, value) JsonSet.new(self, path, value) end |
#casecmp?(value) ⇒ AST::Predicate
Case-insensitive equality: LOWER(column) = LOWER(value).
Case-insensitive equality, folded on both sides rather than left to
the collation, so it means the same thing on every adapter.
295 296 297 298 299 300 301 |
# File 'lib/active_record/refined/ast.rb', line 295 def casecmp?(value) if value.nil? raise ArgumentError, "casecmp? does not take nil; use null? instead" end Comparison.new(Function.new("LOWER", [self]), :==, Function.new("LOWER", [value])) end |
#contains?(value) ⇒ AST::Predicate
Whether the document contains the Ruby document given, which SQL calls containment: @> on PostgreSQL, JSON_CONTAINS on MySQL. SQLite and MariaDB have none.
Whether the document holds what is given, which SQL calls
containment. SQLite has no equivalent.
440 441 442 |
# File 'lib/active_record/refined/ast.rb', line 440 def contains?(value) JsonContains.new(self, value) end |
#dig(*path) ⇒ AST::JsonPath
The JSON at a path into a JSON column, still JSON -- to be dug further, compared with a Ruby value, or asked #key? and the rest. A string or a symbol steps into an object, an integer into an array. #> on PostgreSQL, JSON_EXTRACT on MySQL, -> on SQLite.
Reading inside a JSON document, by the name of what Hash does. A
string or symbol steps into an object, an integer into an array, and
what comes back is still JSON, the way Hash#dig hands back the
structure itself -- for a document to be dug into further or asked
the JSON questions. dig_text gives the value as text instead,
which is what a comparison wants.
397 398 399 |
# File 'lib/active_record/refined/ast.rb', line 397 def dig(*path) JsonPath.new(self, path) end |
#dig_text(*path) ⇒ AST::JsonPath
The value at a path as text, which is what a comparison against a string wants where the JSON type would not do: #>> on PostgreSQL, JSON_UNQUOTE(JSON_EXTRACT(...)) on MySQL, ->> on SQLite.
405 406 407 |
# File 'lib/active_record/refined/ast.rb', line 405 def dig_text(*path) JsonPath.new(self, path, json_value: false) end |
#distinct_from?(value) ⇒ AST::Predicate
IS DISTINCT FROM: != that treats NULL as a value. IS NOT on SQLite, NOT <=> on MySQL.
Null-safe comparison: unlike = and <>, these treat NULL as a value,
so not_distinct_from? is the one equality that may take nil.
308 309 310 |
# File 'lib/active_record/refined/ast.rb', line 308 def distinct_from?(value) DistinctFrom.new(self, value, negated: true) end |
#end_with?(*suffixes) ⇒ AST::Predicate
LIKE '%suffix', escaped as #start_with? escapes.
333 334 335 336 337 338 |
# File 'lib/active_record/refined/ast.rb', line 333 def end_with?(*suffixes) if suffixes.empty? raise ArgumentError, "end_with? needs at least one suffix" end Like.any(self, suffixes.map { |suffix| "%#{Like.escape(suffix)}" }) end |
#except(*keys) ⇒ AST::JsonExcept
The document without the keys given, as Hash#except gives it; an expression, for update_all to write back.
Keys taken out of a JSON document, by the name of what Hash does,
and taking keys as Hash#except takes them. Like bury it gives back
the document changed rather than writing it anywhere.
417 418 419 |
# File 'lib/active_record/refined/ast.rb', line 417 def except(*keys) JsonExcept.new(self, keys) end |
#false? ⇒ AST::Predicate
IS FALSE.
206 207 208 |
# File 'lib/active_record/refined/ast.rb', line 206 def false? TruthValue.new(self, false) end |
#ilike?(pattern) ⇒ AST::Predicate
A case-insensitive LIKE: ILIKE on PostgreSQL, and LIKE over both sides lower-cased elsewhere.
278 279 280 |
# File 'lib/active_record/refined/ast.rb', line 278 def ilike?(pattern) Like.new(self, pattern, nil, case_sensitive: false) end |
#in?(values) ⇒ AST::Predicate
IN (...): an array of values, a range, or a relation as a subquery.
222 223 224 |
# File 'lib/active_record/refined/ast.rb', line 222 def in?(values) In.new(self, values) end |
#include?(substring) ⇒ AST::Predicate
LIKE '%substring%', escaped as #start_with? escapes.
344 345 346 |
# File 'lib/active_record/refined/ast.rb', line 344 def include?(substring) Like.new(self, "%#{Like.escape(substring)}%", Like::ESCAPE) end |
#intersect?(elements) ⇒ AST::Predicate
Whether an array column and the elements given share any: &&.
381 382 383 |
# File 'lib/active_record/refined/ast.rb', line 381 def intersect?(elements) ArrayPredicate.new(self, :"&&", ArrayPredicate.elements(elements, "intersect?")) end |
#key?(key) ⇒ AST::Predicate
Whether the object has the key, as Hash#key? asks. Whether the key is there at all, as Hash#key? asks. Hash has has_key? too; one name is enough, and this is the one Ruby's own style prefers.
452 453 454 |
# File 'lib/active_record/refined/ast.rb', line 452 def key?(key) JsonHasKey.new(self, key) end |
#keys ⇒ AST::JsonKeys
The keys of the object as a JSON array, as Hash#keys gives them. Oracle and SQL Server have none. The keys of the document, as Hash#keys gives them: a JSON array.
460 461 462 |
# File 'lib/active_record/refined/ast.rb', line 460 def keys JsonKeys.new(self) end |
#like?(pattern) ⇒ AST::Predicate
LIKE pattern, the pattern as written: % and _ are its wildcards.
266 267 268 |
# File 'lib/active_record/refined/ast.rb', line 266 def like?(pattern) Like.new(self, pattern) end |
#member?(element) ⇒ AST::Predicate
Whether a PostgreSQL array column holds the element: @> ARRAY[element].
The array comparisons carry the meaning of their Ruby namesakes.
member? is Enumerable's element test, so an Array argument is
rejected rather than quietly meaning something Array#member? does
not; whole-array comparisons go by the Set and Array names.
357 358 359 360 361 362 363 |
# File 'lib/active_record/refined/ast.rb', line 357 def member?(element) if element.is_a?(::Array) || element.is_a?(::Set) raise ArgumentError, "member? takes a single element; use superset? to require every element" end ArrayPredicate.new(self, :"@>", [element]) end |
#not_between?(min, max) ⇒ AST::Predicate
NOT BETWEEN min AND max.
245 246 247 |
# File 'lib/active_record/refined/ast.rb', line 245 def not_between?(min, max) In.new(self, In::QuotedRange.new(min, max, false), negated: true) end |
#not_distinct_from?(value) ⇒ AST::Predicate
IS NOT DISTINCT FROM: = that treats NULL as a value, so this is the one equality that takes nil.
316 317 318 |
# File 'lib/active_record/refined/ast.rb', line 316 def not_distinct_from?(value) DistinctFrom.new(self, value) end |
#not_false? ⇒ AST::Predicate
IS NOT FALSE.
212 213 214 |
# File 'lib/active_record/refined/ast.rb', line 212 def not_false? TruthValue.new(self, false, negated: true) end |
#not_ilike?(pattern) ⇒ AST::Predicate
The negated case-insensitive LIKE.
284 285 286 |
# File 'lib/active_record/refined/ast.rb', line 284 def not_ilike?(pattern) Like.new(self, pattern, nil, case_sensitive: false, negated: true) end |
#not_in?(values) ⇒ AST::Predicate
NOT IN (...).
228 229 230 |
# File 'lib/active_record/refined/ast.rb', line 228 def not_in?(values) In.new(self, values, negated: true) end |
#not_like?(pattern) ⇒ AST::Predicate
NOT LIKE pattern.
272 273 274 |
# File 'lib/active_record/refined/ast.rb', line 272 def not_like?(pattern) Like.new(self, pattern, negated: true) end |
#not_null? ⇒ AST::Predicate
IS NOT NULL.
180 181 182 |
# File 'lib/active_record/refined/ast.rb', line 180 def not_null? Comparison.new(self, :!=, nil) end |
#not_true? ⇒ AST::Predicate
IS NOT TRUE: keeps the NULL rows that !(:flag == true) drops.
200 201 202 |
# File 'lib/active_record/refined/ast.rb', line 200 def not_true? TruthValue.new(self, true, negated: true) end |
#null? ⇒ AST::Predicate
IS NULL.
! negates any predicate, so these are here for the four that SQL
spells for itself: IS NOT NULL rather than NOT (... IS NULL), and
likewise NOT IN and NOT LIKE. They mean the same thing either way,
including when the column is NULL; what they save is the reading.
174 175 176 |
# File 'lib/active_record/refined/ast.rb', line 174 def null? Comparison.new(self, :==, nil) end |
#start_with?(*prefixes) ⇒ AST::Predicate
LIKE 'prefix%', the prefix escaped so that a % or _ in it is itself; several prefixes are ORed.
324 325 326 327 328 329 |
# File 'lib/active_record/refined/ast.rb', line 324 def start_with?(*prefixes) if prefixes.empty? raise ArgumentError, "start_with? needs at least one prefix" end Like.any(self, prefixes.map { |prefix| "#{Like.escape(prefix)}%" }) end |
#subset?(elements) ⇒ AST::Predicate
Whether every element of an array column is among those given: <@.
373 374 375 |
# File 'lib/active_record/refined/ast.rb', line 373 def subset?(elements) ArrayPredicate.new(self, :"<@", ArrayPredicate.elements(elements, "subset?")) end |
#superset?(elements) ⇒ AST::Predicate
Whether an array column holds every element given: @>.
367 368 369 |
# File 'lib/active_record/refined/ast.rb', line 367 def superset?(elements) ArrayPredicate.new(self, :"@>", ArrayPredicate.elements(elements, "superset?")) end |
#true? ⇒ AST::Predicate
IS TRUE: true of the rows where the boolean is true, false where it is false or NULL -- where == true would be NULL.
IS TRUE and IS FALSE differ from a comparison against the literal in
what they make of NULL: flag = TRUE is itself NULL there, and a
NULL predicate selects nothing, while these two answer false. So the
difference shows in the negations: not_true? keeps the NULL rows
that !(:flag == true) drops.
194 195 196 |
# File 'lib/active_record/refined/ast.rb', line 194 def true? TruthValue.new(self, true) end |
#when(value = nil, &block) ⇒ AST::Case::When
CASE column WHEN value THEN ...: a CASE with this as the operand, each when a value it is compared against, followed by then and finally else.
CASE with this as the operand, compared against each when:
:age.when(10).then(1).else(0). The other shape, where each when
carries its own condition, starts at case_when.
257 258 259 |
# File 'lib/active_record/refined/ast.rb', line 257 def when(value = nil, &block) Case.new(self).when(value, &block) end |