squeel 0.5.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.yardopts +3 -0
- data/Gemfile +8 -3
- data/README.md +368 -0
- data/lib/core_ext/hash.rb +8 -8
- data/lib/core_ext/symbol.rb +7 -6
- data/lib/squeel.rb +2 -0
- data/lib/squeel/adapters/active_record.rb +25 -20
- data/lib/squeel/adapters/active_record/3.0/compat.rb +1 -2
- data/lib/squeel/adapters/active_record/3.0/context.rb +6 -7
- data/lib/squeel/adapters/active_record/3.0/join_dependency.rb +5 -5
- data/lib/squeel/adapters/active_record/context.rb +6 -7
- data/lib/squeel/adapters/active_record/join_dependency.rb +5 -5
- data/lib/squeel/configuration.rb +29 -0
- data/lib/squeel/constants.rb +1 -0
- data/lib/squeel/context.rb +36 -7
- data/lib/squeel/dsl.rb +57 -2
- data/lib/squeel/nodes.rb +6 -0
- data/lib/squeel/nodes/and.rb +1 -0
- data/lib/squeel/nodes/binary.rb +11 -2
- data/lib/squeel/nodes/function.rb +30 -48
- data/lib/squeel/nodes/join.rb +56 -12
- data/lib/squeel/nodes/key_path.rb +68 -2
- data/lib/squeel/nodes/nary.rb +12 -2
- data/lib/squeel/nodes/not.rb +1 -0
- data/lib/squeel/nodes/operation.rb +9 -0
- data/lib/squeel/nodes/operators.rb +16 -0
- data/lib/squeel/nodes/or.rb +1 -0
- data/lib/squeel/nodes/order.rb +19 -1
- data/lib/squeel/nodes/predicate.rb +25 -3
- data/lib/squeel/nodes/predicate_operators.rb +12 -0
- data/lib/squeel/nodes/stub.rb +55 -48
- data/lib/squeel/nodes/unary.rb +7 -1
- data/lib/squeel/predicate_methods.rb +2 -10
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors/attribute_visitor.rb +80 -4
- data/lib/squeel/visitors/base.rb +70 -4
- data/lib/squeel/visitors/predicate_visitor.rb +28 -9
- data/lib/squeel/visitors/symbol_visitor.rb +1 -1
- data/spec/core_ext/symbol_spec.rb +2 -2
- data/spec/spec_helper.rb +6 -1
- data/spec/squeel/adapters/active_record/context_spec.rb +0 -7
- data/spec/squeel/adapters/active_record/relation_spec.rb +27 -0
- data/spec/squeel/dsl_spec.rb +20 -1
- data/spec/squeel/nodes/join_spec.rb +11 -4
- data/spec/squeel/nodes/key_path_spec.rb +1 -1
- data/spec/squeel/nodes/predicate_spec.rb +0 -42
- data/spec/squeel/nodes/stub_spec.rb +9 -8
- data/spec/squeel/visitors/predicate_visitor_spec.rb +34 -9
- data/squeel.gemspec +6 -9
- metadata +8 -10
- data/README.rdoc +0 -117
- data/lib/squeel/predicate_methods/function.rb +0 -9
- data/lib/squeel/predicate_methods/predicate.rb +0 -11
- data/lib/squeel/predicate_methods/stub.rb +0 -9
- data/lib/squeel/predicate_methods/symbol.rb +0 -9
@@ -3,35 +3,56 @@ require 'squeel/nodes/predicate_operators'
|
|
3
3
|
|
4
4
|
module Squeel
|
5
5
|
module Nodes
|
6
|
+
# This node is essentially a container that will result in ARel predicate nodes
|
7
|
+
# once visited. It stores the expression (normally an attribute name, function, or
|
8
|
+
# operation), the ARel predicate method name, and a value. these are then interpreted
|
9
|
+
# when visited by the PredicateVisitor to generate a condition against the appropriate
|
10
|
+
# columns.
|
6
11
|
class Predicate
|
7
12
|
|
8
|
-
include PredicateMethods
|
9
13
|
include PredicateOperators
|
10
14
|
|
15
|
+
# @return The right-hand value being considered in this predicate.
|
11
16
|
attr_accessor :value
|
12
|
-
attr_reader :expr, :method_name
|
13
17
|
|
18
|
+
# @return The expression on the left side of this predicate.
|
19
|
+
attr_reader :expr
|
20
|
+
|
21
|
+
# @return [Symbol] The ARel "predication" method name, such as eq, matches, etc.
|
22
|
+
attr_reader :method_name
|
23
|
+
|
24
|
+
# Create a new Predicate node with the given expression, method name, and value
|
25
|
+
# @param expr The expression for the left hand side of the predicate.
|
26
|
+
# @param [Symbol] method_name The ARel predication method
|
27
|
+
# @param value An optional value. If not given, one will need to be supplied
|
28
|
+
# before the node can be visited properly.
|
14
29
|
def initialize(expr, method_name = :eq, value = :__undefined__)
|
15
30
|
@expr, @method_name, @value = expr, method_name, value
|
16
31
|
end
|
17
32
|
|
33
|
+
# Object comparison
|
18
34
|
def eql?(other)
|
19
35
|
self.class.eql?(other.class) &&
|
20
36
|
self.expr.eql?(other.expr) &&
|
21
37
|
self.method_name.eql?(other.method_name) &&
|
22
38
|
self.value.eql?(other.value)
|
23
39
|
end
|
24
|
-
|
25
40
|
alias :== :eql?
|
26
41
|
|
42
|
+
# Implemented for equality testing
|
27
43
|
def hash
|
28
44
|
[self.class, expr, method_name, value].hash
|
29
45
|
end
|
30
46
|
|
47
|
+
# Whether the value has been assigned yet.
|
48
|
+
# @return [Boolean] Has the value been set?
|
31
49
|
def value?
|
32
50
|
@value != :__undefined__
|
33
51
|
end
|
34
52
|
|
53
|
+
# Set the value for this predicate
|
54
|
+
# @param val The value to be set
|
55
|
+
# @return [Predicate] This predicate, with its new value set
|
35
56
|
def %(val)
|
36
57
|
@value = val
|
37
58
|
self
|
@@ -40,6 +61,7 @@ module Squeel
|
|
40
61
|
# expand_hash_conditions_for_aggregates assumes our hash keys can be
|
41
62
|
# converted to symbols, so this has to be implemented, but it doesn't
|
42
63
|
# really have to do anything useful.
|
64
|
+
# @return [NilClass] Just to avoid bombing out on expand_hash_conditions_for_aggregates
|
43
65
|
def to_sym
|
44
66
|
nil
|
45
67
|
end
|
@@ -1,17 +1,29 @@
|
|
1
1
|
module Squeel
|
2
2
|
module Nodes
|
3
|
+
# Operators that act as factories for Or, And, and Not nodes for inclusion
|
4
|
+
# in classes which can be contained inside these nodes.
|
3
5
|
module PredicateOperators
|
6
|
+
|
7
|
+
# Create a new Or node, with this node as its left-hand node.
|
8
|
+
# @param other The right-hand node for the Or
|
9
|
+
# @return [Or] The new Or node
|
4
10
|
def |(other)
|
5
11
|
Or.new(self, other)
|
6
12
|
end
|
7
13
|
|
14
|
+
# Create a new And node, with this node as its left-hand node.
|
15
|
+
# @param other The right-hand node for the And
|
16
|
+
# @return [And] The new And node
|
8
17
|
def &(other)
|
9
18
|
And.new([self, other])
|
10
19
|
end
|
11
20
|
|
21
|
+
# Create a new Not node, with this node as its expression
|
22
|
+
# @return [Not] The new Not node
|
12
23
|
def -@
|
13
24
|
Not.new(self)
|
14
25
|
end
|
26
|
+
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
data/lib/squeel/nodes/stub.rb
CHANGED
@@ -3,111 +3,118 @@ require 'squeel/nodes/operators'
|
|
3
3
|
|
4
4
|
module Squeel
|
5
5
|
module Nodes
|
6
|
+
# Stub nodes are basically a container for a Symbol that can have handy predicate
|
7
|
+
# methods and operators defined on it since doing so on Symbol will incur the
|
8
|
+
# nerdrage of many.
|
6
9
|
class Stub
|
7
10
|
|
8
11
|
include PredicateMethods
|
9
12
|
include Operators
|
10
13
|
|
14
|
+
alias :== :eq
|
15
|
+
alias :'^' :not_eq
|
16
|
+
alias :'!=' :not_eq if respond_to?(:'!=')
|
17
|
+
alias :>> :in
|
18
|
+
alias :<< :not_in
|
19
|
+
alias :=~ :matches
|
20
|
+
alias :'!~' :does_not_match if respond_to?(:'!~')
|
21
|
+
alias :> :gt
|
22
|
+
alias :>= :gteq
|
23
|
+
alias :< :lt
|
24
|
+
alias :<= :lteq
|
25
|
+
|
26
|
+
undef_method :id if method_defined?(:id)
|
27
|
+
|
28
|
+
# @return [Symbol] The symbol contained by this stub
|
11
29
|
attr_reader :symbol
|
12
30
|
|
31
|
+
# Create a new Stub.
|
32
|
+
# @param [Symbol] symbol The symbol that this Stub contains
|
13
33
|
def initialize(symbol)
|
14
34
|
@symbol = symbol
|
15
35
|
end
|
16
36
|
|
37
|
+
# Object comparison
|
17
38
|
def eql?(other)
|
18
39
|
self.class == other.class &&
|
19
40
|
self.symbol == other.symbol
|
20
41
|
end
|
21
42
|
|
43
|
+
# To support object equality tests
|
22
44
|
def hash
|
23
45
|
symbol.hash
|
24
46
|
end
|
25
47
|
|
48
|
+
# @return [Symbol] The symbol this Stub contains.
|
26
49
|
def to_sym
|
27
50
|
symbol
|
28
51
|
end
|
29
52
|
|
53
|
+
# @return [String] The Stub's String equivalent.
|
30
54
|
def to_s
|
31
55
|
symbol.to_s
|
32
56
|
end
|
33
57
|
|
58
|
+
# Create a KeyPath when any undefined method is called on a Stub.
|
59
|
+
# @overload node_name
|
60
|
+
# Creates a new KeyPath with this Stub as the base and the method_name as the endpoint
|
61
|
+
# @return [KeyPath] The new keypath
|
62
|
+
# @overload node_name(klass)
|
63
|
+
# Creates a new KeyPath with this Stub as the base and a polymorphic belongs_to join as the endpoint
|
64
|
+
# @param [Class] klass The polymorphic class for the join
|
65
|
+
# @return [KeyPath] The new keypath
|
34
66
|
def method_missing(method_id, *args)
|
35
67
|
super if method_id == :to_ary
|
36
|
-
if
|
68
|
+
if args.empty?
|
69
|
+
KeyPath.new(self, method_id)
|
70
|
+
elsif (args.size == 1) && (Class === args[0])
|
37
71
|
KeyPath.new(self, Join.new(method_id, Arel::InnerJoin, args[0]))
|
38
72
|
else
|
39
|
-
KeyPath.new(self, method_id)
|
73
|
+
KeyPath.new(self, Nodes::Function.new(method_id, args))
|
40
74
|
end
|
41
75
|
end
|
42
76
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
Predicate.new(self.symbol, :not_eq, value)
|
50
|
-
end if respond_to?('!=')
|
51
|
-
|
52
|
-
def ^(value)
|
53
|
-
Predicate.new self.symbol, :not_eq, value
|
54
|
-
end
|
55
|
-
|
56
|
-
def >>(value)
|
57
|
-
Predicate.new self.symbol, :in, value
|
58
|
-
end
|
59
|
-
|
60
|
-
def <<(value)
|
61
|
-
Predicate.new self.symbol, :not_in, value
|
62
|
-
end
|
63
|
-
|
64
|
-
def =~(value)
|
65
|
-
Predicate.new self.symbol, :matches, value
|
66
|
-
end
|
67
|
-
|
68
|
-
# Won't work on Ruby 1.8.x so need to do this conditionally
|
69
|
-
define_method('!~') do |value|
|
70
|
-
Predicate.new(self.symbol, :does_not_match, value)
|
71
|
-
end if respond_to?('!~')
|
72
|
-
|
73
|
-
def >(value)
|
74
|
-
Predicate.new self.symbol, :gt, value
|
75
|
-
end
|
76
|
-
|
77
|
-
def >=(value)
|
78
|
-
Predicate.new self.symbol, :gteq, value
|
79
|
-
end
|
80
|
-
|
81
|
-
def <(value)
|
82
|
-
Predicate.new self.symbol, :lt, value
|
83
|
-
end
|
84
|
-
|
85
|
-
def <=(value)
|
86
|
-
Predicate.new self.symbol, :lteq, value
|
77
|
+
# Return a KeyPath containing only this Stub, but flagged as absolute.
|
78
|
+
# This helps Stubs behave more like a KeyPath, as anyone using the Squeel
|
79
|
+
# DSL is likely to think of them as such.
|
80
|
+
# @return [KeyPath] An absolute KeyPath, containing only this Stub
|
81
|
+
def ~
|
82
|
+
KeyPath.new [], self, true
|
87
83
|
end
|
88
84
|
|
85
|
+
# Create an ascending Order node with this Stub's symbol as its expression
|
86
|
+
# @return [Order] The new Order node
|
89
87
|
def asc
|
90
88
|
Order.new self.symbol, 1
|
91
89
|
end
|
92
90
|
|
91
|
+
# Create a descending Order node with this Stub's symbol as its expression
|
92
|
+
# @return [Order] The new Order node
|
93
93
|
def desc
|
94
94
|
Order.new self.symbol, -1
|
95
95
|
end
|
96
96
|
|
97
|
+
# Create a Function node for a function named the same as this Stub and with the given arguments
|
98
|
+
# @return [Function] The new Function node
|
97
99
|
def func(*args)
|
98
100
|
Function.new(self.symbol, args)
|
99
101
|
end
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
+
# Create an inner Join node for the association named by this Stub
|
104
|
+
# @return [Join] The new inner Join node
|
103
105
|
def inner
|
104
106
|
Join.new(self.symbol, Arel::InnerJoin)
|
105
107
|
end
|
106
108
|
|
109
|
+
# Create an outer Join node for the association named by this Stub
|
110
|
+
# @return [Join] The new outer Join node
|
107
111
|
def outer
|
108
112
|
Join.new(self.symbol, Arel::OuterJoin)
|
109
113
|
end
|
110
114
|
|
115
|
+
# Create a polymorphic Join node for the association named by this Stub,
|
116
|
+
# @param [Class] klass The polymorphic belongs_to class for this Join
|
117
|
+
# @return [Join] The new polymorphic Join node
|
111
118
|
def of_class(klass)
|
112
119
|
Join.new(self.symbol, Arel::InnerJoin, klass)
|
113
120
|
end
|
data/lib/squeel/nodes/unary.rb
CHANGED
@@ -2,21 +2,27 @@ require 'squeel/nodes/predicate_operators'
|
|
2
2
|
|
3
3
|
module Squeel
|
4
4
|
module Nodes
|
5
|
+
# A node that contains a single expression.
|
5
6
|
class Unary
|
7
|
+
|
6
8
|
include PredicateOperators
|
7
9
|
|
10
|
+
# @return The expression contained in the node
|
8
11
|
attr_reader :expr
|
9
12
|
|
13
|
+
# Create a new Unary node.
|
14
|
+
# @param expr The expression to contain inside the node.
|
10
15
|
def initialize(expr)
|
11
16
|
@expr = expr
|
12
17
|
end
|
13
18
|
|
19
|
+
# Object comparison
|
14
20
|
def eql?(other)
|
15
21
|
self.class == other.class &&
|
16
22
|
self.expr == other.expr
|
17
23
|
end
|
18
|
-
|
19
24
|
alias :== :eql?
|
25
|
+
|
20
26
|
end
|
21
27
|
end
|
22
28
|
end
|
@@ -1,19 +1,11 @@
|
|
1
|
-
require 'squeel/predicate_methods/symbol'
|
2
|
-
require 'squeel/predicate_methods/stub'
|
3
|
-
require 'squeel/predicate_methods/predicate'
|
4
|
-
require 'squeel/predicate_methods/function'
|
5
|
-
|
6
1
|
module Squeel
|
2
|
+
# Defines Nodes::Predicate factories named for each of the ARel predication methods
|
7
3
|
module PredicateMethods
|
8
4
|
|
9
|
-
def self.included(base)
|
10
|
-
base.send :include, const_get(base.name.split(/::/)[-1].to_sym)
|
11
|
-
end
|
12
|
-
|
13
5
|
Constants::PREDICATES.each do |method_name|
|
14
6
|
class_eval <<-RUBY
|
15
7
|
def #{method_name}(value = :__undefined__)
|
16
|
-
|
8
|
+
Nodes::Predicate.new self, :#{method_name}, value
|
17
9
|
end
|
18
10
|
RUBY
|
19
11
|
end
|
data/lib/squeel/version.rb
CHANGED
@@ -2,8 +2,18 @@ require 'squeel/visitors/base'
|
|
2
2
|
|
3
3
|
module Squeel
|
4
4
|
module Visitors
|
5
|
+
# A visitor that tries to convert visited nodes into Arel::Attributes
|
6
|
+
# or other nodes that can be used for grouping, ordering, and the like.
|
5
7
|
class AttributeVisitor < Base
|
6
8
|
|
9
|
+
private
|
10
|
+
|
11
|
+
# Visit a Hash. This entails iterating through each key and value and
|
12
|
+
# visiting each value in turn.
|
13
|
+
#
|
14
|
+
# @param [Hash] o The Hash to visit
|
15
|
+
# @param parent The current parent object in the context
|
16
|
+
# @return [Array] An array of values for use in an ordering, grouping, etc.
|
7
17
|
def visit_Hash(o, parent)
|
8
18
|
o.map do |k, v|
|
9
19
|
if implies_context_change?(v)
|
@@ -14,11 +24,19 @@ module Squeel
|
|
14
24
|
end.flatten
|
15
25
|
end
|
16
26
|
|
27
|
+
# @return [Boolean] Whether the given value implies a context change
|
28
|
+
# @param v The value to consider
|
17
29
|
def implies_context_change?(v)
|
18
|
-
|
19
|
-
(Array === v && !v.empty? && v.all? {|val| can_accept?(val)})
|
30
|
+
can_accept?(v)
|
20
31
|
end
|
21
32
|
|
33
|
+
# Change context (by setting the new parent to the result of a #find or
|
34
|
+
# #traverse on the key), then accept the given value.
|
35
|
+
#
|
36
|
+
# @param k The hash key
|
37
|
+
# @param v The hash value
|
38
|
+
# @param parent The current parent object in the context
|
39
|
+
# @return The visited value
|
22
40
|
def visit_with_context_change(k, v, parent)
|
23
41
|
parent = case k
|
24
42
|
when Nodes::KeyPath
|
@@ -34,32 +52,84 @@ module Squeel
|
|
34
52
|
end
|
35
53
|
end
|
36
54
|
|
55
|
+
# If there is no context change, we'll just return the value unchanged,
|
56
|
+
# currently. Is this really the right behavior? I don't think so, but
|
57
|
+
# it works in this case.
|
58
|
+
#
|
59
|
+
# @param k The hash key
|
60
|
+
# @param v The hash value
|
61
|
+
# @param parent The current parent object in the context
|
62
|
+
# @return The same value we just received. Yeah, this method's pretty pointless,
|
63
|
+
# for now, and only here for consistency's sake.
|
37
64
|
def visit_without_context_change(k, v, parent)
|
38
65
|
v
|
39
66
|
end
|
40
67
|
|
68
|
+
# Visit elements of an array that it's possible to visit -- leave other
|
69
|
+
# elements untouched.
|
70
|
+
#
|
71
|
+
# @param [Array] o The array to visit
|
72
|
+
# @param parent The array's parent within the context
|
73
|
+
# @return [Array] The flattened array with elements visited
|
41
74
|
def visit_Array(o, parent)
|
42
75
|
o.map { |v| can_accept?(v) ? accept(v, parent) : v }.flatten
|
43
76
|
end
|
44
77
|
|
78
|
+
# Visit a symbol. This will return an attribute named after the symbol against
|
79
|
+
# the current parent's contextualized table.
|
80
|
+
#
|
81
|
+
# @param [Symbol] o The symbol to visit
|
82
|
+
# @param parent The symbol's parent within the context
|
83
|
+
# @return [Arel::Attribute] An attribute on the contextualized parent table
|
45
84
|
def visit_Symbol(o, parent)
|
46
85
|
contextualize(parent)[o]
|
47
86
|
end
|
48
87
|
|
88
|
+
# Visit a stub. This will return an attribute named after the stub against
|
89
|
+
# the current parent's contextualized table.
|
90
|
+
#
|
91
|
+
# @param [Nodes::Stub] o The stub to visit
|
92
|
+
# @param parent The stub's parent within the context
|
93
|
+
# @return [Arel::Attribute] An attribute on the contextualized parent table
|
49
94
|
def visit_Squeel_Nodes_Stub(o, parent)
|
50
95
|
contextualize(parent)[o.symbol]
|
51
96
|
end
|
52
97
|
|
98
|
+
# Visit a keypath. This will traverse the keypath's "path", setting a new
|
99
|
+
# parent as though the keypath's endpoint was in a deeply-nested hash,
|
100
|
+
# then visit the endpoint with the new parent.
|
101
|
+
#
|
102
|
+
# @param [Nodes::KeyPath] o The keypath to visit
|
103
|
+
# @param parent The keypath's parent within the context
|
104
|
+
# @return The visited endpoint, with the parent from the KeyPath's path.
|
53
105
|
def visit_Squeel_Nodes_KeyPath(o, parent)
|
54
106
|
parent = traverse(o, parent)
|
55
107
|
|
56
108
|
accept(o.endpoint, parent)
|
57
109
|
end
|
58
110
|
|
111
|
+
# Visit an Order node.
|
112
|
+
#
|
113
|
+
# @param [Nodes::Order] o The order node to visit
|
114
|
+
# @param parent The node's parent within the context
|
115
|
+
# @return [Arel::Nodes::Ordering] An ascending or desending ordering
|
59
116
|
def visit_Squeel_Nodes_Order(o, parent)
|
60
117
|
accept(o.expr, parent).send(o.descending? ? :desc : :asc)
|
61
118
|
end
|
62
119
|
|
120
|
+
# Visit a Function node. Each function argument will be accepted or
|
121
|
+
# contextualized if appropriate. Keep in mind that this occurs with
|
122
|
+
# the current parent within the context.
|
123
|
+
#
|
124
|
+
# @example A function as the endpoint of a keypath
|
125
|
+
# Person.joins{children}.order{children.coalesce(name, '<no name>')}
|
126
|
+
# # => SELECT "people".* FROM "people"
|
127
|
+
# INNER JOIN "people" "children_people"
|
128
|
+
# ON "children_people"."parent_id" = "people"."id"
|
129
|
+
# ORDER BY coalesce("children_people"."name", '<no name>')
|
130
|
+
#
|
131
|
+
# @param [Nodes::Function] o The function node to visit
|
132
|
+
# @param parent The node's parent within the context
|
63
133
|
def visit_Squeel_Nodes_Function(o, parent)
|
64
134
|
args = o.args.map do |arg|
|
65
135
|
case arg
|
@@ -68,12 +138,18 @@ module Squeel
|
|
68
138
|
when Symbol, Nodes::Stub
|
69
139
|
Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym])
|
70
140
|
else
|
71
|
-
|
141
|
+
quote arg
|
72
142
|
end
|
73
143
|
end
|
74
144
|
Arel::Nodes::NamedFunction.new(o.name, args, o.alias)
|
75
145
|
end
|
76
146
|
|
147
|
+
# Visit an Operation node. Each operand will be accepted or
|
148
|
+
# contextualized if appropriate. Keep in mind that this occurs with
|
149
|
+
# the current parent within the context.
|
150
|
+
#
|
151
|
+
# @param [Nodes::Operation] o The operation node to visit
|
152
|
+
# @param parent The node's parent within the context
|
77
153
|
def visit_Squeel_Nodes_Operation(o, parent)
|
78
154
|
args = o.args.map do |arg|
|
79
155
|
case arg
|
@@ -82,7 +158,7 @@ module Squeel
|
|
82
158
|
when Symbol, Nodes::Stub
|
83
159
|
Arel.sql(arel_visitor.accept contextualize(parent)[arg.to_sym])
|
84
160
|
else
|
85
|
-
|
161
|
+
quote arg
|
86
162
|
end
|
87
163
|
end
|
88
164
|
|