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