squeel 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.yardopts +3 -0
  2. data/Gemfile +8 -3
  3. data/README.md +368 -0
  4. data/lib/core_ext/hash.rb +8 -8
  5. data/lib/core_ext/symbol.rb +7 -6
  6. data/lib/squeel.rb +2 -0
  7. data/lib/squeel/adapters/active_record.rb +25 -20
  8. data/lib/squeel/adapters/active_record/3.0/compat.rb +1 -2
  9. data/lib/squeel/adapters/active_record/3.0/context.rb +6 -7
  10. data/lib/squeel/adapters/active_record/3.0/join_dependency.rb +5 -5
  11. data/lib/squeel/adapters/active_record/context.rb +6 -7
  12. data/lib/squeel/adapters/active_record/join_dependency.rb +5 -5
  13. data/lib/squeel/configuration.rb +29 -0
  14. data/lib/squeel/constants.rb +1 -0
  15. data/lib/squeel/context.rb +36 -7
  16. data/lib/squeel/dsl.rb +57 -2
  17. data/lib/squeel/nodes.rb +6 -0
  18. data/lib/squeel/nodes/and.rb +1 -0
  19. data/lib/squeel/nodes/binary.rb +11 -2
  20. data/lib/squeel/nodes/function.rb +30 -48
  21. data/lib/squeel/nodes/join.rb +56 -12
  22. data/lib/squeel/nodes/key_path.rb +68 -2
  23. data/lib/squeel/nodes/nary.rb +12 -2
  24. data/lib/squeel/nodes/not.rb +1 -0
  25. data/lib/squeel/nodes/operation.rb +9 -0
  26. data/lib/squeel/nodes/operators.rb +16 -0
  27. data/lib/squeel/nodes/or.rb +1 -0
  28. data/lib/squeel/nodes/order.rb +19 -1
  29. data/lib/squeel/nodes/predicate.rb +25 -3
  30. data/lib/squeel/nodes/predicate_operators.rb +12 -0
  31. data/lib/squeel/nodes/stub.rb +55 -48
  32. data/lib/squeel/nodes/unary.rb +7 -1
  33. data/lib/squeel/predicate_methods.rb +2 -10
  34. data/lib/squeel/version.rb +1 -1
  35. data/lib/squeel/visitors/attribute_visitor.rb +80 -4
  36. data/lib/squeel/visitors/base.rb +70 -4
  37. data/lib/squeel/visitors/predicate_visitor.rb +28 -9
  38. data/lib/squeel/visitors/symbol_visitor.rb +1 -1
  39. data/spec/core_ext/symbol_spec.rb +2 -2
  40. data/spec/spec_helper.rb +6 -1
  41. data/spec/squeel/adapters/active_record/context_spec.rb +0 -7
  42. data/spec/squeel/adapters/active_record/relation_spec.rb +27 -0
  43. data/spec/squeel/dsl_spec.rb +20 -1
  44. data/spec/squeel/nodes/join_spec.rb +11 -4
  45. data/spec/squeel/nodes/key_path_spec.rb +1 -1
  46. data/spec/squeel/nodes/predicate_spec.rb +0 -42
  47. data/spec/squeel/nodes/stub_spec.rb +9 -8
  48. data/spec/squeel/visitors/predicate_visitor_spec.rb +34 -9
  49. data/squeel.gemspec +6 -9
  50. metadata +8 -10
  51. data/README.rdoc +0 -117
  52. data/lib/squeel/predicate_methods/function.rb +0 -9
  53. data/lib/squeel/predicate_methods/predicate.rb +0 -11
  54. data/lib/squeel/predicate_methods/stub.rb +0 -9
  55. 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
@@ -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 query syntax on steroids.}
12
+ s.summary = %q{ActiveRecord 3, improved.}
13
13
  s.description = %q{
14
- Squeel offers the ability to call any Arel predicate methods
15
- (with a few convenient aliases) on your model's attributes instead
16
- of the ones normally offered by ActiveRecord's hash parameters. It also
17
- adds convenient syntax for order clauses, smarter mapping of nested hash
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 button if
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.5
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-20 00:00:00 Z
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 offers the ability to call any Arel predicate methods\n (with a few convenient aliases) on your model's attributes instead\n of the ones normally offered by ActiveRecord's hash parameters. It also\n adds convenient syntax for order clauses, smarter mapping of nested hash\n conditions, and a debug_sql method to see the real SQL your code is\n generating without running it against the database. If you like the new\n AR 3.0 query interface, you'll love it with Squeel.\n "
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.rdoc
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 button if\n\
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 query syntax on steroids.
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:
@@ -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...
@@ -1,9 +0,0 @@
1
- module Squeel
2
- module PredicateMethods
3
- module Function
4
- def predicate(method_name, value = :__undefined__)
5
- Nodes::Predicate.new self, method_name, value
6
- end
7
- end
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- module Squeel
2
- module PredicateMethods
3
- module Predicate
4
- def predicate(method_name, value = :__undefined__)
5
- @method_name = method_name
6
- @value = value unless value == :__undefined__
7
- self
8
- end
9
- end
10
- end
11
- end
@@ -1,9 +0,0 @@
1
- module Squeel
2
- module PredicateMethods
3
- module Stub
4
- def predicate(method_name, value = :__undefined__)
5
- Nodes::Predicate.new self.symbol, method_name, value
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Squeel
2
- module PredicateMethods
3
- module Symbol
4
- def predicate(method_name, value = :__undefined__)
5
- Nodes::Predicate.new self, method_name, value
6
- end
7
- end
8
- end
9
- end