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 ==.
76 77 78 79 80 81 |
# File 'lib/active_record/refined/ast.rb', line 76 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.
118 119 120 |
# File 'lib/active_record/refined/ast.rb', line 118 def !~(pattern) Match.new(self, pattern, negated: true) end |
#<(other) ⇒ AST::Predicate
<.
97 98 99 |
# File 'lib/active_record/refined/ast.rb', line 97 def <(other) Comparison.new(self, :<, other) end |
#<=(other) ⇒ AST::Predicate
<=.
103 104 105 |
# File 'lib/active_record/refined/ast.rb', line 103 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.
67 68 69 70 71 72 |
# File 'lib/active_record/refined/ast.rb', line 67 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.
112 113 114 |
# File 'lib/active_record/refined/ast.rb', line 112 def =~(pattern) Match.new(self, pattern) end |
#>(other) ⇒ AST::Predicate
>.
85 86 87 |
# File 'lib/active_record/refined/ast.rb', line 85 def >(other) Comparison.new(self, :>, other) end |
#>=(other) ⇒ AST::Predicate
>=.
91 92 93 |
# File 'lib/active_record/refined/ast.rb', line 91 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.
196 197 198 |
# File 'lib/active_record/refined/ast.rb', line 196 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.
386 387 388 |
# File 'lib/active_record/refined/ast.rb', line 386 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.
252 253 254 255 256 257 258 |
# File 'lib/active_record/refined/ast.rb', line 252 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.
397 398 399 |
# File 'lib/active_record/refined/ast.rb', line 397 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.
354 355 356 |
# File 'lib/active_record/refined/ast.rb', line 354 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.
362 363 364 |
# File 'lib/active_record/refined/ast.rb', line 362 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.
265 266 267 |
# File 'lib/active_record/refined/ast.rb', line 265 def distinct_from?(value) DistinctFrom.new(self, value, negated: true) end |
#end_with?(*suffixes) ⇒ AST::Predicate
LIKE '%suffix', escaped as #start_with? escapes.
290 291 292 293 294 295 |
# File 'lib/active_record/refined/ast.rb', line 290 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.
374 375 376 |
# File 'lib/active_record/refined/ast.rb', line 374 def except(*keys) JsonExcept.new(self, keys) end |
#false? ⇒ AST::Predicate
IS FALSE.
163 164 165 |
# File 'lib/active_record/refined/ast.rb', line 163 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.
235 236 237 |
# File 'lib/active_record/refined/ast.rb', line 235 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.
179 180 181 |
# File 'lib/active_record/refined/ast.rb', line 179 def in?(values) In.new(self, values) end |
#include?(substring) ⇒ AST::Predicate
LIKE '%substring%', escaped as #start_with? escapes.
301 302 303 |
# File 'lib/active_record/refined/ast.rb', line 301 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: &&.
338 339 340 |
# File 'lib/active_record/refined/ast.rb', line 338 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.
409 410 411 |
# File 'lib/active_record/refined/ast.rb', line 409 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 has none. The keys of the document, as Hash#keys gives them: a JSON array.
417 418 419 |
# File 'lib/active_record/refined/ast.rb', line 417 def keys JsonKeys.new(self) end |
#like?(pattern) ⇒ AST::Predicate
LIKE pattern, the pattern as written: % and _ are its wildcards.
223 224 225 |
# File 'lib/active_record/refined/ast.rb', line 223 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.
314 315 316 317 318 319 320 |
# File 'lib/active_record/refined/ast.rb', line 314 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.
202 203 204 |
# File 'lib/active_record/refined/ast.rb', line 202 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.
273 274 275 |
# File 'lib/active_record/refined/ast.rb', line 273 def not_distinct_from?(value) DistinctFrom.new(self, value) end |
#not_false? ⇒ AST::Predicate
IS NOT FALSE.
169 170 171 |
# File 'lib/active_record/refined/ast.rb', line 169 def not_false? TruthValue.new(self, false, negated: true) end |
#not_ilike?(pattern) ⇒ AST::Predicate
The negated case-insensitive LIKE.
241 242 243 |
# File 'lib/active_record/refined/ast.rb', line 241 def not_ilike?(pattern) Like.new(self, pattern, nil, case_sensitive: false, negated: true) end |
#not_in?(values) ⇒ AST::Predicate
NOT IN (...).
185 186 187 |
# File 'lib/active_record/refined/ast.rb', line 185 def not_in?(values) In.new(self, values, negated: true) end |
#not_like?(pattern) ⇒ AST::Predicate
NOT LIKE pattern.
229 230 231 |
# File 'lib/active_record/refined/ast.rb', line 229 def not_like?(pattern) Like.new(self, pattern, negated: true) end |
#not_null? ⇒ AST::Predicate
IS NOT NULL.
137 138 139 |
# File 'lib/active_record/refined/ast.rb', line 137 def not_null? Comparison.new(self, :!=, nil) end |
#not_true? ⇒ AST::Predicate
IS NOT TRUE: keeps the NULL rows that !(:flag == true) drops.
157 158 159 |
# File 'lib/active_record/refined/ast.rb', line 157 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.
131 132 133 |
# File 'lib/active_record/refined/ast.rb', line 131 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.
281 282 283 284 285 286 |
# File 'lib/active_record/refined/ast.rb', line 281 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: <@.
330 331 332 |
# File 'lib/active_record/refined/ast.rb', line 330 def subset?(elements) ArrayPredicate.new(self, :"<@", ArrayPredicate.elements(elements, "subset?")) end |
#superset?(elements) ⇒ AST::Predicate
Whether an array column holds every element given: @>.
324 325 326 |
# File 'lib/active_record/refined/ast.rb', line 324 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.
151 152 153 |
# File 'lib/active_record/refined/ast.rb', line 151 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.
214 215 216 |
# File 'lib/active_record/refined/ast.rb', line 214 def when(value = nil, &block) Case.new(self).when(value, &block) end |