squeel 0.5.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -30,6 +30,34 @@ module Squeel
|
|
30
30
|
predicate.right.should eq ['Joe', 'Bob']
|
31
31
|
end
|
32
32
|
|
33
|
+
it 'allows a subquery on the value side of an explicit predicate' do
|
34
|
+
predicate = @v.accept dsl{name.in(Person.select{name}.where{name.in(['Aric Smith', 'Gladyce Kulas'])})}
|
35
|
+
predicate.should be_a Arel::Nodes::In
|
36
|
+
predicate.left.name.should eq :name
|
37
|
+
predicate.right.should be_a Arel::Nodes::SelectStatement
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'allows a subquery on the value side of an implicit predicate' do
|
41
|
+
predicate = @v.accept(:name => Person.select{name}.where{name.in(['Aric Smith', 'Gladyce Kulas'])})
|
42
|
+
predicate.should be_a Arel::Nodes::In
|
43
|
+
predicate.left.name.should eq :name
|
44
|
+
predicate.right.should be_a Arel::Nodes::SelectStatement
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'converts ActiveRecord::Base objects to their id' do
|
48
|
+
predicate = @v.accept(:id => Person.first)
|
49
|
+
predicate.should be_a Arel::Nodes::Equality
|
50
|
+
predicate.left.name.should eq :id
|
51
|
+
predicate.right.should eq 1
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'converts arrays of ActiveRecord::Base objects to their ids' do
|
55
|
+
predicate = @v.accept(:id => [Person.first, Person.last])
|
56
|
+
predicate.should be_a Arel::Nodes::In
|
57
|
+
predicate.left.name.should eq :id
|
58
|
+
predicate.right.should eq [1, 332]
|
59
|
+
end
|
60
|
+
|
33
61
|
it 'creates the node against the proper table for nested hashes' do
|
34
62
|
predicate = @v.accept({
|
35
63
|
:children => {
|
@@ -75,6 +103,12 @@ module Squeel
|
|
75
103
|
keypath.to_sql.should eq standard.to_sql
|
76
104
|
end
|
77
105
|
|
106
|
+
it 'honors absolute keypaths with only an endpoint' do
|
107
|
+
standard = @v.accept({:name => 'Joe'})
|
108
|
+
keypath = @v.accept(dsl{{children => {children => {~name => 'Joe'}}}})
|
109
|
+
keypath.to_sql.should eq standard.to_sql
|
110
|
+
end
|
111
|
+
|
78
112
|
it 'allows incomplete predicates (missing value) as keys' do
|
79
113
|
standard = @v.accept({
|
80
114
|
:children => {
|
@@ -156,15 +190,6 @@ module Squeel
|
|
156
190
|
predicate.right.should eq 'Joe%'
|
157
191
|
end
|
158
192
|
|
159
|
-
it 'treats hash keys as an association when there is an array of "acceptables" on the value side' do
|
160
|
-
predicate = @v.accept(:children => [:name.matches % 'Joe%', :name.eq % 'Bob'])
|
161
|
-
predicate.should be_a Arel::Nodes::Grouping
|
162
|
-
predicate.expr.should be_a Arel::Nodes::And
|
163
|
-
predicate.expr.children.should have(2).items
|
164
|
-
predicate.expr.children.first.should be_a Arel::Nodes::Matches
|
165
|
-
predicate.expr.children.first.left.relation.table_alias.should eq 'children_people'
|
166
|
-
end
|
167
|
-
|
168
193
|
it 'treats hash keys as an association when there is an Or on the value side' do
|
169
194
|
predicate = @v.accept(:children => (:name.matches % 'Joe%' | :name.matches % 'Bob%'))
|
170
195
|
predicate.should be_a Arel::Nodes::Grouping
|
data/squeel.gemspec
CHANGED
@@ -9,20 +9,17 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Ernie Miller"]
|
10
10
|
s.email = ["ernie@metautonomo.us"]
|
11
11
|
s.homepage = "http://metautonomo.us/projects/squeel"
|
12
|
-
s.summary = %q{ActiveRecord 3
|
12
|
+
s.summary = %q{ActiveRecord 3, improved.}
|
13
13
|
s.description = %q{
|
14
|
-
Squeel
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
conditions, and a debug_sql method to see the real SQL your code is
|
19
|
-
generating without running it against the database. If you like the new
|
20
|
-
AR 3.0 query interface, you'll love it with Squeel.
|
14
|
+
Squeel unlocks the power of ARel in your Rails 3 application with
|
15
|
+
a handy block-based syntax. You can write subqueries, access named
|
16
|
+
functions provided by your RDBMS, and more, all without writing
|
17
|
+
SQL strings.
|
21
18
|
}
|
22
19
|
s.post_install_message = %q{
|
23
20
|
*** Thanks for installing Squeel! ***
|
24
21
|
Be sure to check out http://metautonomo.us/projects/squeel/ for a
|
25
|
-
walkthrough of Squeel's features, and click the donate
|
22
|
+
walkthrough of Squeel's features, and click the donate link if
|
26
23
|
you're feeling especially appreciative. It'd help me justify this
|
27
24
|
"open source" stuff to my lovely wife. :)
|
28
25
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: squeel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.6.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ernie Miller
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-04
|
13
|
+
date: 2011-05-04 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -78,7 +78,7 @@ dependencies:
|
|
78
78
|
version: 1.3.3
|
79
79
|
type: :development
|
80
80
|
version_requirements: *id006
|
81
|
-
description: "\n Squeel
|
81
|
+
description: "\n Squeel unlocks the power of ARel in your Rails 3 application with\n a handy block-based syntax. You can write subqueries, access named\n functions provided by your RDBMS, and more, all without writing\n SQL strings.\n "
|
82
82
|
email:
|
83
83
|
- ernie@metautonomo.us
|
84
84
|
executables: []
|
@@ -89,9 +89,10 @@ extra_rdoc_files: []
|
|
89
89
|
|
90
90
|
files:
|
91
91
|
- .gitignore
|
92
|
+
- .yardopts
|
92
93
|
- Gemfile
|
93
94
|
- LICENSE
|
94
|
-
- README.
|
95
|
+
- README.md
|
95
96
|
- Rakefile
|
96
97
|
- lib/core_ext/hash.rb
|
97
98
|
- lib/core_ext/symbol.rb
|
@@ -129,10 +130,6 @@ files:
|
|
129
130
|
- lib/squeel/nodes/stub.rb
|
130
131
|
- lib/squeel/nodes/unary.rb
|
131
132
|
- lib/squeel/predicate_methods.rb
|
132
|
-
- lib/squeel/predicate_methods/function.rb
|
133
|
-
- lib/squeel/predicate_methods/predicate.rb
|
134
|
-
- lib/squeel/predicate_methods/stub.rb
|
135
|
-
- lib/squeel/predicate_methods/symbol.rb
|
136
133
|
- lib/squeel/version.rb
|
137
134
|
- lib/squeel/visitors.rb
|
138
135
|
- lib/squeel/visitors/attribute_visitor.rb
|
@@ -173,7 +170,7 @@ licenses: []
|
|
173
170
|
post_install_message: "\n\
|
174
171
|
*** Thanks for installing Squeel! ***\n\
|
175
172
|
Be sure to check out http://metautonomo.us/projects/squeel/ for a\n\
|
176
|
-
walkthrough of Squeel's features, and click the donate
|
173
|
+
walkthrough of Squeel's features, and click the donate link if\n\
|
177
174
|
you're feeling especially appreciative. It'd help me justify this\n\
|
178
175
|
\"open source\" stuff to my lovely wife. :)\n\n"
|
179
176
|
rdoc_options: []
|
@@ -198,7 +195,7 @@ rubyforge_project: squeel
|
|
198
195
|
rubygems_version: 1.7.2
|
199
196
|
signing_key:
|
200
197
|
specification_version: 3
|
201
|
-
summary: ActiveRecord 3
|
198
|
+
summary: ActiveRecord 3, improved.
|
202
199
|
test_files:
|
203
200
|
- spec/blueprints/articles.rb
|
204
201
|
- spec/blueprints/comments.rb
|
@@ -227,3 +224,4 @@ test_files:
|
|
227
224
|
- spec/squeel/visitors/predicate_visitor_spec.rb
|
228
225
|
- spec/squeel/visitors/symbol_visitor_spec.rb
|
229
226
|
- spec/support/schema.rb
|
227
|
+
has_rdoc:
|
data/README.rdoc
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
=Squeel
|
2
|
-
|
3
|
-
Squeel is a (Rails 3.1-only for now) rewrite of MetaWhere. It's rapidly approaching
|
4
|
-
a point where I could recommend it for daily use. Once it hits feature completion, I'll
|
5
|
-
work on backporting to Rails 3.0.x. In the meantime, please feel free to clone this repo
|
6
|
-
and give it a test drive using <tt>rake console</tt> and the models in the
|
7
|
-
<tt>spec/support/schema.rb</tt> file.
|
8
|
-
|
9
|
-
== Getting started
|
10
|
-
|
11
|
-
In your Gemfile:
|
12
|
-
|
13
|
-
gem "squeel" # Last officially released gem
|
14
|
-
# gem "squeel", :git => "git://github.com/ernie/squeel.git" # Track git repo
|
15
|
-
|
16
|
-
In an intitializer:
|
17
|
-
|
18
|
-
Squeel.configure do |config|
|
19
|
-
# To load hash extensions (to allow for AND (&), OR (|), and NOT (-) against
|
20
|
-
# hashes of conditions)
|
21
|
-
config.load_core_extensions :hash
|
22
|
-
|
23
|
-
# To load symbol extensions (for a subset of the old MetaWhere functionality,
|
24
|
-
# via ARel predicate methods on Symbols: :name.matches, etc)
|
25
|
-
# config.load_core_extensions :symbol
|
26
|
-
|
27
|
-
# To load both hash and symbol extensions
|
28
|
-
# config.load_core_extensions :hash, :symbol
|
29
|
-
end
|
30
|
-
|
31
|
-
== The Squeel Query DSL
|
32
|
-
|
33
|
-
Squeel enhances the normal ActiveRecord query methods by enabling them to accept
|
34
|
-
blocks. Inside a block, the Squeel query DSL can be used. Note the use of curly braces
|
35
|
-
in these examples instead of parentheses. {} denotes a Squeel DSL query.
|
36
|
-
|
37
|
-
=== Stubs
|
38
|
-
|
39
|
-
Stubs are, for most intents and purposes, just like Symbols in a normal call to
|
40
|
-
Relation#where (note the need for doubling up on the curly braces here, the first ones
|
41
|
-
start the block, the second are the hash braces):
|
42
|
-
|
43
|
-
Person.where{{name => 'Ernie'}}
|
44
|
-
=> SELECT "people".* FROM "people" WHERE "people"."name" = 'Ernie'
|
45
|
-
|
46
|
-
You normally wouldn't bother using the DSL in this case, as a simple hash would
|
47
|
-
suffice. However, stubs serve as a building block for keypaths, and keypaths are
|
48
|
-
very handy.
|
49
|
-
|
50
|
-
=== KeyPaths
|
51
|
-
|
52
|
-
A Squeel keypath is essentially a more concise and readable alternative to a
|
53
|
-
deeply nested hash. For instance, in standard ActiveRecord, you might join several
|
54
|
-
associations like this to perform a query:
|
55
|
-
|
56
|
-
Person.joins(:articles => {:comments => :person})
|
57
|
-
=> SELECT "people".* FROM "people"
|
58
|
-
INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
59
|
-
INNER JOIN "comments" ON "comments"."article_id" = "articles"."id"
|
60
|
-
INNER JOIN "people" "people_comments" ON "people_comments"."id" = "comments"."person_id"
|
61
|
-
|
62
|
-
With a keypath, this would look like:
|
63
|
-
|
64
|
-
Person.joins{articles.comments.person}
|
65
|
-
|
66
|
-
A keypath can exist in the context of a hash, and is normally interpreted relative to
|
67
|
-
the current level of nesting. It can be forced into an "absolute" path by anchoring it with
|
68
|
-
a ~, like:
|
69
|
-
|
70
|
-
~articles.comments.person
|
71
|
-
|
72
|
-
This isn't quite so useful in the typical hash context, but can be very useful when it comes
|
73
|
-
to interpreting functions and the like. We'll cover those later.
|
74
|
-
|
75
|
-
=== Joins
|
76
|
-
|
77
|
-
As you saw above, keypaths can be used as shorthand for joins. Additionally, you can
|
78
|
-
specify join types (or join classes, in the case of polymorphic belongs_to joins):
|
79
|
-
|
80
|
-
Person.joins{articles.outer}
|
81
|
-
=> SELECT "people".* FROM "people"
|
82
|
-
LEFT OUTER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
83
|
-
Note.joins{notable(Person).outer}
|
84
|
-
=> SELECT "notes".* FROM "notes"
|
85
|
-
LEFT OUTER JOIN "people"
|
86
|
-
ON "people"."id" = "notes"."notable_id"
|
87
|
-
AND "notes"."notable_type" = 'Person'
|
88
|
-
|
89
|
-
These can also be used inside keypaths:
|
90
|
-
|
91
|
-
Note.joins{notable(Person).articles}
|
92
|
-
=> SELECT "notes".* FROM "notes"
|
93
|
-
INNER JOIN "people" ON "people"."id" = "notes"."notable_id"
|
94
|
-
AND "notes"."notable_type" = 'Person'
|
95
|
-
INNER JOIN "articles" ON "articles"."person_id" = "people"."id"
|
96
|
-
|
97
|
-
=== Functions
|
98
|
-
|
99
|
-
You can call SQL functions just like you would call a method in Ruby...
|
100
|
-
|
101
|
-
Person.select{coalesce(name, '<no name given>')}
|
102
|
-
=> SELECT coalesce("people"."name", '<no name given>') FROM "people"
|
103
|
-
|
104
|
-
...and you can easily give it an alias:
|
105
|
-
|
106
|
-
person = Person.select{
|
107
|
-
coalesce(name, '<no name given>').as(name_with_default)
|
108
|
-
}.first
|
109
|
-
person.name_with_default # name or <no name given>, depending on data
|
110
|
-
|
111
|
-
=== Operators
|
112
|
-
|
113
|
-
You can use the standard mathematical operators (+, -, *, /)inside the Squeel DSL to
|
114
|
-
specify operators in the resulting SQL, or the <tt>op</tt> method to specify another
|
115
|
-
custom operator, such as the standard SQL concatenation operator, ||:
|
116
|
-
|
117
|
-
...more docs to come...
|