squeel 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/ernie/squeel.png)](http://travis-ci.org/ernie/squeel)
|
1
|
+
# Squeel [![Build Status](https://secure.travis-ci.org/ernie/squeel.png)](http://travis-ci.org/ernie/squeel) [![endorse](http://api.coderwall.com/ernie/endorsecount.png)](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
|