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

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



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

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

#!~(pattern) ⇒ Object



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

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

#<(other) ⇒ Object



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

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

#<=(other) ⇒ Object



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

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.



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



97
98
99
# File 'lib/active_record/refined/ast.rb', line 97

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

#>(other) ⇒ Object



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

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

#>=(other) ⇒ Object



85
86
87
# File 'lib/active_record/refined/ast.rb', line 85

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

#between?(min, max) ⇒ Boolean

Not min..max: an endpoint may be an expression, which Range would refuse to hold, since expressions do not compare among themselves.

Returns:

  • (Boolean)


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

def between?(min, max)
  In.new(self, In::QuotedRange.new(min, max, false))
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.



265
266
267
# File 'lib/active_record/refined/ast.rb', line 265

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)


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

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)


271
272
273
# File 'lib/active_record/refined/ast.rb', line 271

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



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

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

#dig_text(*path) ⇒ Object



251
252
253
# File 'lib/active_record/refined/ast.rb', line 251

def dig_text(*path)
  JsonPath.new(self, path, json_value: false)
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)


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

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

#end_with?(*suffixes) ⇒ Boolean

Returns:

  • (Boolean)


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

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

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.



258
259
260
# File 'lib/active_record/refined/ast.rb', line 258

def except(*keys)
  JsonExcept.new(self, keys)
end

#false?Boolean

Returns:

  • (Boolean)


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

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

#ilike?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#in?(values) ⇒ Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/active_record/refined/ast.rb', line 138

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

#include?(substring) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#intersect?(elements) ⇒ Boolean

Returns:

  • (Boolean)


237
238
239
# File 'lib/active_record/refined/ast.rb', line 237

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)


278
279
280
# File 'lib/active_record/refined/ast.rb', line 278

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

#keysObject

The keys of the document, as Hash#keys gives them: a JSON array.



283
284
285
# File 'lib/active_record/refined/ast.rb', line 283

def keys
  JsonKeys.new(self)
end

#like?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


163
164
165
# File 'lib/active_record/refined/ast.rb', line 163

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)


221
222
223
224
225
226
227
# File 'lib/active_record/refined/ast.rb', line 221

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)


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

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

#not_distinct_from?(value) ⇒ Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/active_record/refined/ast.rb', line 195

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

#not_false?Boolean

Returns:

  • (Boolean)


134
135
136
# File 'lib/active_record/refined/ast.rb', line 134

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

#not_ilike?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/active_record/refined/ast.rb', line 175

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

#not_in?(values) ⇒ Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/active_record/refined/ast.rb', line 142

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

#not_like?(pattern) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#not_null?Boolean

Returns:

  • (Boolean)


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

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

#not_true?Boolean

Returns:

  • (Boolean)


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

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)


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

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

#start_with?(*prefixes) ⇒ Boolean

Returns:

  • (Boolean)


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

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)


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

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

#superset?(elements) ⇒ Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/active_record/refined/ast.rb', line 229

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)


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

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.



159
160
161
# File 'lib/active_record/refined/ast.rb', line 159

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