Module: ActiveRecord::Refined::AST::Predications

Included in:
Aggregate, Arithmetic, Bitwise, BitwiseNot, Case, Cast, Column, DatetimeValueFunction, Extract, Function, JsonPath, JsonSet, Over, Value
Defined in:
lib/active_record/refined/ast.rb

Overview

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

Instance Method Details

#!=(other) ⇒ Object



53
54
55
56
57
58
# File 'lib/active_record/refined/ast.rb', line 53

def !=(other)
  if other.nil?
    raise ArgumentError, "!= does not take nil; use !null? instead"
  end
  Comparison.new(self, :!=, other)
end

#!~(pattern) ⇒ Object



80
81
82
# File 'lib/active_record/refined/ast.rb', line 80

def !~(pattern)
  Match.new(self, pattern, negated: true)
end

#<(other) ⇒ Object



68
69
70
# File 'lib/active_record/refined/ast.rb', line 68

def <(other)
  Comparison.new(self, :<, other)
end

#<=(other) ⇒ Object



72
73
74
# File 'lib/active_record/refined/ast.rb', line 72

def <=(other)
  Comparison.new(self, :<=, other)
end

#==(other) ⇒ Object

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.



46
47
48
49
50
51
# File 'lib/active_record/refined/ast.rb', line 46

def ==(other)
  if other.nil?
    raise ArgumentError, "== does not take nil; use null? instead"
  end
  Comparison.new(self, :==, other)
end

#=~(pattern) ⇒ Object



76
77
78
# File 'lib/active_record/refined/ast.rb', line 76

def =~(pattern)
  Match.new(self, pattern)
end

#>(other) ⇒ Object



60
61
62
# File 'lib/active_record/refined/ast.rb', line 60

def >(other)
  Comparison.new(self, :>, other)
end

#>=(other) ⇒ Object



64
65
66
# File 'lib/active_record/refined/ast.rb', line 64

def >=(other)
  Comparison.new(self, :>=, other)
end

#between?(min, max) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/active_record/refined/ast.rb', line 125

def between?(min, max)
  In.new(self, min..max)
end

#bury(*path, value) ⇒ Object

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.



234
235
236
# File 'lib/active_record/refined/ast.rb', line 234

def bury(*path, value)
  JsonSet.new(self, path, value)
end

#casecmp?(value) ⇒ Boolean

Case-insensitive equality, folded on both sides rather than left to the collation, so it means the same thing on every adapter.

Returns:

  • (Boolean)


158
159
160
161
162
163
164
# File 'lib/active_record/refined/ast.rb', line 158

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) ⇒ Boolean

Whether the document holds what is given, which SQL calls containment. SQLite has no equivalent.

Returns:

  • (Boolean)


240
241
242
# File 'lib/active_record/refined/ast.rb', line 240

def contains?(value)
  JsonContains.new(self, value)
end

#dig(*path) ⇒ Object

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 the value rather than the JSON, since that is what a comparison wants. dig_json keeps it JSON, for a document to be dug into further or compared whole.



223
224
225
# File 'lib/active_record/refined/ast.rb', line 223

def dig(*path)
  JsonPath.new(self, path)
end

#dig_json(*path) ⇒ Object



227
228
229
# File 'lib/active_record/refined/ast.rb', line 227

def dig_json(*path)
  JsonPath.new(self, path, as_json: true)
end

#distinct_from?(value) ⇒ Boolean

Null-safe comparison: unlike = and <>, these treat NULL as a value, so not_distinct_from? is the one equality that may take nil.

Returns:

  • (Boolean)


168
169
170
# File 'lib/active_record/refined/ast.rb', line 168

def distinct_from?(value)
  DistinctFrom.new(self, value, negated: true)
end

#end_with?(*suffixes) ⇒ Boolean

Returns:

  • (Boolean)


183
184
185
186
187
188
# File 'lib/active_record/refined/ast.rb', line 183

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

#false?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/active_record/refined/ast.rb', line 109

def false?
  TruthValue.new(self, false)
end

#ilike?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/active_record/refined/ast.rb', line 148

def ilike?(pattern)
  Like.new(self, pattern, nil, case_sensitive: false)
end

#in?(values) ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
# File 'lib/active_record/refined/ast.rb', line 117

def in?(values)
  In.new(self, values)
end

#include?(substring) ⇒ Boolean

Returns:

  • (Boolean)


190
191
192
# File 'lib/active_record/refined/ast.rb', line 190

def include?(substring)
  Like.new(self, "%#{Like.escape(substring)}%", Like::ESCAPE)
end

#intersect?(elements) ⇒ Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/active_record/refined/ast.rb', line 214

def intersect?(elements)
  ArrayPredicate.new(self, :"&&", ArrayPredicate.elements(elements, "intersect?"))
end

#key?(key) ⇒ Boolean

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.

Returns:

  • (Boolean)


247
248
249
# File 'lib/active_record/refined/ast.rb', line 247

def key?(key)
  JsonHasKey.new(self, key)
end

#like?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/active_record/refined/ast.rb', line 140

def like?(pattern)
  Like.new(self, pattern)
end

#member?(element) ⇒ Boolean

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.

Returns:

  • (Boolean)


198
199
200
201
202
203
204
# File 'lib/active_record/refined/ast.rb', line 198

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) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/active_record/refined/ast.rb', line 129

def not_between?(min, max)
  In.new(self, min..max, negated: true)
end

#not_distinct_from?(value) ⇒ Boolean

Returns:

  • (Boolean)


172
173
174
# File 'lib/active_record/refined/ast.rb', line 172

def not_distinct_from?(value)
  DistinctFrom.new(self, value)
end

#not_false?Boolean

Returns:

  • (Boolean)


113
114
115
# File 'lib/active_record/refined/ast.rb', line 113

def not_false?
  TruthValue.new(self, false, negated: true)
end

#not_ilike?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


152
153
154
# File 'lib/active_record/refined/ast.rb', line 152

def not_ilike?(pattern)
  Like.new(self, pattern, nil, case_sensitive: false, negated: true)
end

#not_in?(values) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/active_record/refined/ast.rb', line 121

def not_in?(values)
  In.new(self, values, negated: true)
end

#not_like?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


144
145
146
# File 'lib/active_record/refined/ast.rb', line 144

def not_like?(pattern)
  Like.new(self, pattern, negated: true)
end

#not_null?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/active_record/refined/ast.rb', line 92

def not_null?
  Comparison.new(self, :!=, nil)
end

#not_true?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/active_record/refined/ast.rb', line 105

def not_true?
  TruthValue.new(self, true, negated: true)
end

#null?Boolean

! 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.

Returns:

  • (Boolean)


88
89
90
# File 'lib/active_record/refined/ast.rb', line 88

def null?
  Comparison.new(self, :==, nil)
end

#start_with?(*prefixes) ⇒ Boolean

Returns:

  • (Boolean)


176
177
178
179
180
181
# File 'lib/active_record/refined/ast.rb', line 176

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) ⇒ Boolean

Returns:

  • (Boolean)


210
211
212
# File 'lib/active_record/refined/ast.rb', line 210

def subset?(elements)
  ArrayPredicate.new(self, :"<@", ArrayPredicate.elements(elements, "subset?"))
end

#superset?(elements) ⇒ Boolean

Returns:

  • (Boolean)


206
207
208
# File 'lib/active_record/refined/ast.rb', line 206

def superset?(elements)
  ArrayPredicate.new(self, :"@>", ArrayPredicate.elements(elements, "superset?"))
end

#true?Boolean

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.

Returns:

  • (Boolean)


101
102
103
# File 'lib/active_record/refined/ast.rb', line 101

def true?
  TruthValue.new(self, true)
end

#when(value = nil, &block) ⇒ Object

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.



136
137
138
# File 'lib/active_record/refined/ast.rb', line 136

def when(value = nil, &block)
  Case.new(self).when(value, &block)
end