squeel 1.0.1 → 1.0.2
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/CHANGELOG.md +20 -0
- data/README.md +1 -1
- data/lib/squeel.rb +1 -2
- data/lib/squeel/adapters/active_record.rb +3 -1
- data/lib/squeel/adapters/active_record/3.0/compat.rb +5 -1
- data/lib/squeel/adapters/active_record/3.0/context.rb +2 -2
- data/lib/squeel/adapters/active_record/3.1/compat.rb +22 -0
- data/lib/squeel/adapters/active_record/3.1/context.rb +2 -2
- data/lib/squeel/adapters/active_record/compat.rb +22 -0
- data/lib/squeel/adapters/active_record/join_dependency_extensions.rb +2 -2
- data/lib/squeel/configuration.rb +2 -2
- data/lib/squeel/core_ext/symbol.rb +3 -13
- data/lib/squeel/dsl.rb +10 -1
- data/lib/squeel/nodes.rb +9 -1
- data/lib/squeel/nodes/aliasing.rb +2 -2
- data/lib/squeel/nodes/as.rb +1 -1
- data/lib/squeel/nodes/binary.rb +1 -4
- data/lib/squeel/nodes/function.rb +1 -10
- data/lib/squeel/nodes/grouping.rb +35 -0
- data/lib/squeel/nodes/join.rb +3 -3
- data/lib/squeel/nodes/key_path.rb +26 -24
- data/lib/squeel/nodes/literal.rb +2 -17
- data/lib/squeel/nodes/nary.rb +1 -2
- data/lib/squeel/nodes/ordering.rb +21 -0
- data/lib/squeel/nodes/predicate.rb +1 -4
- data/lib/squeel/nodes/predicate_methods.rb +16 -0
- data/lib/squeel/nodes/stub.rb +11 -21
- data/lib/squeel/nodes/unary.rb +1 -4
- data/lib/squeel/version.rb +1 -1
- data/lib/squeel/visitors/attribute_visitor.rb +12 -13
- data/lib/squeel/visitors/predicate_visitor.rb +38 -15
- data/lib/squeel/visitors/symbol_visitor.rb +2 -6
- data/lib/squeel/visitors/visitor.rb +24 -1
- data/spec/squeel/adapters/active_record/relation_extensions_spec.rb +6 -1
- data/spec/squeel/dsl_spec.rb +9 -1
- data/spec/squeel/nodes/grouping_spec.rb +177 -0
- data/spec/squeel/nodes/join_spec.rb +4 -5
- data/spec/squeel/nodes/key_path_spec.rb +3 -5
- data/spec/squeel/nodes/operators_spec.rb +3 -3
- data/spec/squeel/nodes/stub_spec.rb +6 -7
- data/spec/squeel/visitors/attribute_visitor_spec.rb +6 -1
- data/spec/squeel/visitors/predicate_visitor_spec.rb +28 -0
- metadata +62 -22
- data/lib/squeel/predicate_methods.rb +0 -14
data/CHANGELOG.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# v1.0.2
|
2
|
+
## 2012-05-30
|
3
|
+
|
4
|
+
* Add groupings to DSL. Allows control of matched sets of
|
5
|
+
parentheses in the absence of not/and/etc. Accessed via
|
6
|
+
`_()`.
|
7
|
+
* Allow As nodes in predicates. This allows casting inside
|
8
|
+
a where/having clause with PostgreSQL: `cast(value.as type)`
|
9
|
+
* Work around issue with Relation#count when where_values
|
10
|
+
contains InfixOperations. Fixes #122.
|
11
|
+
|
12
|
+
# v1.0.1
|
13
|
+
## 2012-05-02
|
14
|
+
|
15
|
+
* Undefine `type` method on Stubs/KeyPaths for 1.8.x compat.
|
16
|
+
|
17
|
+
# v1.0.0
|
18
|
+
## 2012-04-22
|
19
|
+
|
20
|
+
* Official 1.0.0 release.
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Squeel [](http://travis-ci.org/ernie/squeel)
|
1
|
+
# Squeel [](http://travis-ci.org/ernie/squeel) [](http://coderwall.com/ernie)
|
2
2
|
|
3
3
|
Squeel lets you write your ActiveRecord queries with fewer strings, and more Ruby,
|
4
4
|
by making the ARel awesomeness that lies beneath ActiveRecord more accessible.
|
data/lib/squeel.rb
CHANGED
@@ -16,6 +16,7 @@ when 3
|
|
16
16
|
ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependencyExtensions
|
17
17
|
ActiveRecord::Base.extend Squeel::Adapters::ActiveRecord::AssociationPreloadExtensions
|
18
18
|
when 1
|
19
|
+
require 'squeel/adapters/active_record/3.1/compat'
|
19
20
|
require 'squeel/adapters/active_record/3.1/relation_extensions'
|
20
21
|
require 'squeel/adapters/active_record/3.1/preloader_extensions'
|
21
22
|
require 'squeel/adapters/active_record/3.1/context'
|
@@ -24,6 +25,7 @@ when 3
|
|
24
25
|
ActiveRecord::Associations::JoinDependency.send :include, Squeel::Adapters::ActiveRecord::JoinDependencyExtensions
|
25
26
|
ActiveRecord::Associations::Preloader.send :include, Squeel::Adapters::ActiveRecord::PreloaderExtensions
|
26
27
|
else
|
28
|
+
require 'squeel/adapters/active_record/compat'
|
27
29
|
require 'squeel/adapters/active_record/relation_extensions'
|
28
30
|
require 'squeel/adapters/active_record/preloader_extensions'
|
29
31
|
require 'squeel/adapters/active_record/context'
|
@@ -34,4 +36,4 @@ when 3
|
|
34
36
|
end
|
35
37
|
else
|
36
38
|
raise NotImplementedError, "Squeel does not support ActiveRecord version #{ActiveRecord::VERSION::STRING}"
|
37
|
-
end
|
39
|
+
end
|
@@ -95,6 +95,10 @@ module Arel
|
|
95
95
|
super(:-, left, right)
|
96
96
|
end
|
97
97
|
end
|
98
|
+
|
99
|
+
class Grouping < Unary
|
100
|
+
include Arel::Predications
|
101
|
+
end unless Grouping.include?(Arel::Predications)
|
98
102
|
end
|
99
103
|
|
100
104
|
module Visitors
|
@@ -157,4 +161,4 @@ module Arel
|
|
157
161
|
end
|
158
162
|
end
|
159
163
|
|
160
|
-
end
|
164
|
+
end
|
@@ -38,7 +38,7 @@ module Squeel
|
|
38
38
|
|
39
39
|
def traverse(keypath, parent = @base, include_endpoint = false)
|
40
40
|
parent = @base if keypath.absolute?
|
41
|
-
keypath.
|
41
|
+
keypath.path_without_endpoint.each do |key|
|
42
42
|
parent = find(key, parent) || key
|
43
43
|
end
|
44
44
|
parent = find(keypath.endpoint, parent) if include_endpoint
|
@@ -73,4 +73,4 @@ module Squeel
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
|
-
end
|
76
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Arel
|
2
|
+
|
3
|
+
module Nodes
|
4
|
+
|
5
|
+
class Grouping < Unary
|
6
|
+
include Arel::Predications
|
7
|
+
end unless Grouping.include?(Arel::Predications)
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Visitors
|
12
|
+
|
13
|
+
class DepthFirst < Visitor
|
14
|
+
|
15
|
+
unless method_defined?(:visit_Arel_Nodes_InfixOperation)
|
16
|
+
alias :visit_Arel_Nodes_InfixOperation :binary
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -38,7 +38,7 @@ module Squeel
|
|
38
38
|
|
39
39
|
def traverse(keypath, parent = @base, include_endpoint = false)
|
40
40
|
parent = @base if keypath.absolute?
|
41
|
-
keypath.
|
41
|
+
keypath.path_without_endpoint.each do |key|
|
42
42
|
parent = find(key, parent) || key
|
43
43
|
end
|
44
44
|
parent = find(keypath.endpoint, parent) if include_endpoint
|
@@ -73,4 +73,4 @@ module Squeel
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
|
-
end
|
76
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Arel
|
2
|
+
|
3
|
+
module Nodes
|
4
|
+
|
5
|
+
class Grouping < Unary
|
6
|
+
include Arel::Predications
|
7
|
+
end unless Grouping.include?(Arel::Predications)
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Visitors
|
12
|
+
|
13
|
+
class DepthFirst < Visitor
|
14
|
+
|
15
|
+
unless method_defined?(:visit_Arel_Nodes_InfixOperation)
|
16
|
+
alias :visit_Arel_Nodes_InfixOperation :binary
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -21,7 +21,7 @@ module Squeel
|
|
21
21
|
|
22
22
|
if Nodes::KeyPath === associations
|
23
23
|
parent ||= _join_parts.last
|
24
|
-
associations.
|
24
|
+
associations.path.each do |key|
|
25
25
|
parent = build(key, parent, join_type)
|
26
26
|
end
|
27
27
|
parent
|
@@ -33,4 +33,4 @@ module Squeel
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
data/lib/squeel/configuration.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'squeel/constants'
|
2
|
-
require 'squeel/
|
2
|
+
require 'squeel/nodes'
|
3
3
|
|
4
4
|
module Squeel
|
5
5
|
# The Squeel configuration module. The Squeel module extends this to provide its
|
@@ -46,7 +46,7 @@ module Squeel
|
|
46
46
|
def alias_predicate(new_name, existing_name)
|
47
47
|
raise ArgumentError, 'the existing name should be the base name, not an _any/_all variation' if existing_name.to_s =~ /(_any|_all)$/
|
48
48
|
['', '_any', '_all'].each do |suffix|
|
49
|
-
PredicateMethods.class_eval "alias :#{new_name}#{suffix} :#{existing_name}#{suffix} unless defined?(#{new_name}#{suffix})"
|
49
|
+
Nodes::PredicateMethods.class_eval "alias :#{new_name}#{suffix} :#{existing_name}#{suffix} unless defined?(#{new_name}#{suffix})"
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'squeel/predicate_methods'
|
2
|
-
require 'squeel/nodes/aliasing'
|
3
|
-
|
4
1
|
# These extensions to Symbol are loaded optionally, mostly to provide
|
5
2
|
# a small amount of backwards compatibility with MetaWhere.
|
6
3
|
#
|
@@ -9,16 +6,9 @@ require 'squeel/nodes/aliasing'
|
|
9
6
|
# config.load_core_extensions :symbol
|
10
7
|
# end
|
11
8
|
class Symbol
|
12
|
-
include Squeel::PredicateMethods
|
9
|
+
include Squeel::Nodes::PredicateMethods
|
13
10
|
include Squeel::Nodes::Aliasing
|
14
|
-
|
15
|
-
def asc
|
16
|
-
Squeel::Nodes::Order.new self, 1
|
17
|
-
end
|
18
|
-
|
19
|
-
def desc
|
20
|
-
Squeel::Nodes::Order.new self, -1
|
21
|
-
end
|
11
|
+
include Squeel::Nodes::Ordering
|
22
12
|
|
23
13
|
def func(*args)
|
24
14
|
Squeel::Nodes::Function.new(self, args)
|
@@ -36,4 +26,4 @@ class Symbol
|
|
36
26
|
Squeel::Nodes::Join.new(self, Arel::InnerJoin, klass)
|
37
27
|
end
|
38
28
|
|
39
|
-
end
|
29
|
+
end
|
data/lib/squeel/dsl.rb
CHANGED
@@ -71,6 +71,15 @@ module Squeel
|
|
71
71
|
Nodes::Literal.new(string)
|
72
72
|
end
|
73
73
|
|
74
|
+
# Create a Squeel Grouping node. This allows you to set balanced
|
75
|
+
# pairs of parentheses around your SQL.
|
76
|
+
#
|
77
|
+
# @param expr The expression to group
|
78
|
+
# @return [Nodes::Grouping] The grouping node
|
79
|
+
def _(expr)
|
80
|
+
Nodes::Grouping.new(expr)
|
81
|
+
end
|
82
|
+
|
74
83
|
# Create a Squeel Sifter node. This essentially substitutes the
|
75
84
|
# sifter block of the supplied name from the model.
|
76
85
|
#
|
@@ -109,4 +118,4 @@ module Squeel
|
|
109
118
|
end
|
110
119
|
|
111
120
|
end
|
112
|
-
end
|
121
|
+
end
|
data/lib/squeel/nodes.rb
CHANGED
@@ -4,6 +4,13 @@ module Squeel
|
|
4
4
|
module Nodes
|
5
5
|
end
|
6
6
|
end
|
7
|
+
|
8
|
+
require 'squeel/nodes/predicate_methods'
|
9
|
+
require 'squeel/nodes/operators'
|
10
|
+
require 'squeel/nodes/predicate_operators'
|
11
|
+
require 'squeel/nodes/aliasing'
|
12
|
+
require 'squeel/nodes/ordering'
|
13
|
+
|
7
14
|
require 'squeel/nodes/literal'
|
8
15
|
require 'squeel/nodes/stub'
|
9
16
|
require 'squeel/nodes/key_path'
|
@@ -16,4 +23,5 @@ require 'squeel/nodes/and'
|
|
16
23
|
require 'squeel/nodes/or'
|
17
24
|
require 'squeel/nodes/as'
|
18
25
|
require 'squeel/nodes/not'
|
19
|
-
require 'squeel/nodes/join'
|
26
|
+
require 'squeel/nodes/join'
|
27
|
+
require 'squeel/nodes/grouping'
|
data/lib/squeel/nodes/as.rb
CHANGED
data/lib/squeel/nodes/binary.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'squeel/nodes/predicate_operators'
|
2
|
-
|
3
1
|
module Squeel
|
4
2
|
module Nodes
|
5
3
|
# A node that represents an operation with two operands.
|
@@ -25,8 +23,7 @@ module Squeel
|
|
25
23
|
self.left.eql?(other.left) &&
|
26
24
|
self.right.eql?(other.right)
|
27
25
|
end
|
28
|
-
alias :== :eql?
|
29
26
|
|
30
27
|
end
|
31
28
|
end
|
32
|
-
end
|
29
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'squeel/predicate_methods'
|
2
|
-
|
3
1
|
module Squeel
|
4
2
|
module Nodes
|
5
3
|
# A node that represents an SQL function call
|
@@ -8,6 +6,7 @@ module Squeel
|
|
8
6
|
include PredicateMethods
|
9
7
|
include PredicateOperators
|
10
8
|
include Operators
|
9
|
+
include Ordering
|
11
10
|
|
12
11
|
alias :== :eq
|
13
12
|
alias :'^' :not_eq
|
@@ -46,14 +45,6 @@ module Squeel
|
|
46
45
|
self
|
47
46
|
end
|
48
47
|
|
49
|
-
def asc
|
50
|
-
Order.new self, 1
|
51
|
-
end
|
52
|
-
|
53
|
-
def desc
|
54
|
-
Order.new self, -1
|
55
|
-
end
|
56
|
-
|
57
48
|
# expand_hash_conditions_for_aggregates assumes our hash keys can be
|
58
49
|
# converted to symbols, so this has to be implemented, but it doesn't
|
59
50
|
# really have to do anything useful.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Squeel
|
2
|
+
module Nodes
|
3
|
+
# A node that represents an SQL function call
|
4
|
+
class Grouping < Unary
|
5
|
+
|
6
|
+
include PredicateMethods
|
7
|
+
include PredicateOperators
|
8
|
+
include Operators
|
9
|
+
include Aliasing
|
10
|
+
include Ordering
|
11
|
+
|
12
|
+
alias :== :eq
|
13
|
+
alias :'^' :not_eq
|
14
|
+
alias :'!=' :not_eq if respond_to?(:'!=')
|
15
|
+
alias :>> :in
|
16
|
+
alias :<< :not_in
|
17
|
+
alias :=~ :matches
|
18
|
+
alias :'!~' :does_not_match if respond_to?(:'!~')
|
19
|
+
alias :> :gt
|
20
|
+
alias :>= :gteq
|
21
|
+
alias :< :lt
|
22
|
+
alias :<= :lteq
|
23
|
+
|
24
|
+
# expand_hash_conditions_for_aggregates assumes our hash keys can be
|
25
|
+
# converted to symbols, so this has to be implemented, but it doesn't
|
26
|
+
# really have to do anything useful.
|
27
|
+
# @return [NilClass] Just to avoid bombing out on expand_hash_conditions_for_aggregates
|
28
|
+
def to_sym
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
data/lib/squeel/nodes/join.rb
CHANGED
@@ -61,9 +61,9 @@ module Squeel
|
|
61
61
|
def method_missing(method_id, *args)
|
62
62
|
super if method_id == :to_ary
|
63
63
|
if (args.size == 1) && (Class === args[0])
|
64
|
-
KeyPath.new(self, Join.new(method_id, Arel::InnerJoin, args[0]))
|
64
|
+
KeyPath.new([self, Join.new(method_id, Arel::InnerJoin, args[0])])
|
65
65
|
else
|
66
|
-
KeyPath.new(self, method_id)
|
66
|
+
KeyPath.new([self, method_id])
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
@@ -72,7 +72,7 @@ module Squeel
|
|
72
72
|
# DSL is likely to think of them as such.
|
73
73
|
# @return [KeyPath] An absolute KeyPath, containing only this Join
|
74
74
|
def ~
|
75
|
-
KeyPath.new [],
|
75
|
+
KeyPath.new [self], true
|
76
76
|
end
|
77
77
|
|
78
78
|
# expand_hash_conditions_for_aggregates assumes our hash keys can be
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'squeel/nodes/operators'
|
2
|
-
require 'squeel/nodes/predicate_operators'
|
3
1
|
require 'active_support/core_ext/module'
|
4
2
|
|
5
3
|
module Squeel
|
@@ -20,18 +18,13 @@ module Squeel
|
|
20
18
|
# @return [Array<Symbol, Stub, Join>] The path
|
21
19
|
attr_reader :path
|
22
20
|
|
23
|
-
# @return The endpoint, either another key as in the path, or a predicate, function, etc.
|
24
|
-
attr_reader :endpoint
|
25
|
-
|
26
21
|
# Create a new KeyPath.
|
27
22
|
# @param [Array, Object] path The intial path. Will be converted to an array if it isn't already.
|
28
|
-
# @param endpoint the endpoint of the KeyPath
|
29
23
|
# @param [Boolean] absolute If the KeyPath should start from the base
|
30
24
|
# or remain relative to whatever location it's found.
|
31
|
-
def initialize(path,
|
32
|
-
@path
|
33
|
-
|
34
|
-
@endpoint = Stub.new(@endpoint) if Symbol === @endpoint
|
25
|
+
def initialize(path, absolute = false)
|
26
|
+
@path = Array(path)
|
27
|
+
self.endpoint = Stub.new(endpoint) if Symbol === endpoint
|
35
28
|
@absolute = absolute
|
36
29
|
end
|
37
30
|
|
@@ -42,11 +35,22 @@ module Squeel
|
|
42
35
|
@absolute
|
43
36
|
end
|
44
37
|
|
38
|
+
# @return The endpoint, either another key as in the path, or a predicate, function, etc.
|
39
|
+
def endpoint
|
40
|
+
@path[-1]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Set the new value of the KeyPath's endpoint.
|
44
|
+
# @param [Object] val The new endpoint.
|
45
|
+
# @return The value just set.
|
46
|
+
def endpoint=(val)
|
47
|
+
@path[-1] = val
|
48
|
+
end
|
49
|
+
|
45
50
|
# Object comparison
|
46
51
|
def eql?(other)
|
47
52
|
self.class.eql?(other.class) &&
|
48
53
|
self.path.eql?(other.path) &&
|
49
|
-
self.endpoint.eql?(other.endpoint) &&
|
50
54
|
self.absolute?.eql?(other.absolute?)
|
51
55
|
end
|
52
56
|
|
@@ -120,8 +124,7 @@ module Squeel
|
|
120
124
|
# @return [KeyPath] This keypath, with a sifter as its endpoint
|
121
125
|
def sift(name, *args)
|
122
126
|
if Stub === endpoint || Join === endpoint
|
123
|
-
@path <<
|
124
|
-
@endpoint = Sifter.new(name, args)
|
127
|
+
@path << Sifter.new(name, args)
|
125
128
|
self
|
126
129
|
else
|
127
130
|
no_method_error :sift
|
@@ -137,7 +140,7 @@ module Squeel
|
|
137
140
|
|
138
141
|
# For use with equality tests
|
139
142
|
def hash
|
140
|
-
[self.class,
|
143
|
+
[self.class, *path].hash
|
141
144
|
end
|
142
145
|
|
143
146
|
# expand_hash_conditions_for_aggregates assumes our hash keys can be
|
@@ -162,14 +165,14 @@ module Squeel
|
|
162
165
|
end
|
163
166
|
end
|
164
167
|
|
165
|
-
# @return [Array] The KeyPath's path,
|
166
|
-
def
|
167
|
-
path
|
168
|
+
# @return [Array] The KeyPath's path, minus its endpoint, as a single array.
|
169
|
+
def path_without_endpoint
|
170
|
+
path[0..-2]
|
168
171
|
end
|
169
172
|
|
170
|
-
# Implement (and alias to
|
173
|
+
# Implement #to_s (and alias to #to_str) to play nicely with ActiveRecord grouped calculations
|
171
174
|
def to_s
|
172
|
-
path.map(&:to_s).join('.')
|
175
|
+
path.map(&:to_s).join('.')
|
173
176
|
end
|
174
177
|
alias :to_str :to_s
|
175
178
|
|
@@ -179,16 +182,15 @@ module Squeel
|
|
179
182
|
super if method_id == :to_ary
|
180
183
|
|
181
184
|
if endpoint.respond_to? method_id
|
182
|
-
|
185
|
+
self.endpoint = endpoint.send(method_id, *args)
|
183
186
|
self
|
184
187
|
elsif Stub === endpoint || Join === endpoint
|
185
|
-
@path << endpoint
|
186
188
|
if args.empty?
|
187
|
-
@
|
189
|
+
@path << Stub.new(method_id)
|
188
190
|
elsif (args.size == 1) && (Class === args[0])
|
189
|
-
@
|
191
|
+
@path << Join.new(method_id, Arel::InnerJoin, args[0])
|
190
192
|
else
|
191
|
-
@
|
193
|
+
@path << Nodes::Function.new(method_id, args)
|
192
194
|
end
|
193
195
|
self
|
194
196
|
else
|