squeel_rbg 0.8.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.
Files changed (80) hide show
  1. data/.gitignore +4 -0
  2. data/.yardopts +3 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +20 -0
  5. data/README.md +398 -0
  6. data/Rakefile +19 -0
  7. data/lib/core_ext/hash.rb +13 -0
  8. data/lib/core_ext/symbol.rb +39 -0
  9. data/lib/squeel/adapters/active_record/3.0/association_preload.rb +15 -0
  10. data/lib/squeel/adapters/active_record/3.0/compat.rb +142 -0
  11. data/lib/squeel/adapters/active_record/3.0/context.rb +66 -0
  12. data/lib/squeel/adapters/active_record/3.0/join_association.rb +54 -0
  13. data/lib/squeel/adapters/active_record/3.0/join_dependency.rb +84 -0
  14. data/lib/squeel/adapters/active_record/3.0/relation.rb +327 -0
  15. data/lib/squeel/adapters/active_record/context.rb +66 -0
  16. data/lib/squeel/adapters/active_record/join_association.rb +44 -0
  17. data/lib/squeel/adapters/active_record/join_dependency.rb +83 -0
  18. data/lib/squeel/adapters/active_record/preloader.rb +21 -0
  19. data/lib/squeel/adapters/active_record/relation.rb +351 -0
  20. data/lib/squeel/adapters/active_record.rb +28 -0
  21. data/lib/squeel/configuration.rb +54 -0
  22. data/lib/squeel/constants.rb +24 -0
  23. data/lib/squeel/context.rb +67 -0
  24. data/lib/squeel/dsl.rb +86 -0
  25. data/lib/squeel/nodes/aliasing.rb +13 -0
  26. data/lib/squeel/nodes/and.rb +9 -0
  27. data/lib/squeel/nodes/as.rb +14 -0
  28. data/lib/squeel/nodes/binary.rb +32 -0
  29. data/lib/squeel/nodes/function.rb +66 -0
  30. data/lib/squeel/nodes/join.rb +113 -0
  31. data/lib/squeel/nodes/key_path.rb +192 -0
  32. data/lib/squeel/nodes/nary.rb +45 -0
  33. data/lib/squeel/nodes/not.rb +9 -0
  34. data/lib/squeel/nodes/operation.rb +32 -0
  35. data/lib/squeel/nodes/operators.rb +43 -0
  36. data/lib/squeel/nodes/or.rb +9 -0
  37. data/lib/squeel/nodes/order.rb +53 -0
  38. data/lib/squeel/nodes/predicate.rb +71 -0
  39. data/lib/squeel/nodes/predicate_operators.rb +29 -0
  40. data/lib/squeel/nodes/stub.rb +125 -0
  41. data/lib/squeel/nodes/unary.rb +28 -0
  42. data/lib/squeel/nodes.rb +17 -0
  43. data/lib/squeel/predicate_methods.rb +14 -0
  44. data/lib/squeel/version.rb +3 -0
  45. data/lib/squeel/visitors/attribute_visitor.rb +191 -0
  46. data/lib/squeel/visitors/base.rb +112 -0
  47. data/lib/squeel/visitors/predicate_visitor.rb +319 -0
  48. data/lib/squeel/visitors/symbol_visitor.rb +48 -0
  49. data/lib/squeel/visitors.rb +3 -0
  50. data/lib/squeel.rb +28 -0
  51. data/lib/squeel_rbg.rb +5 -0
  52. data/spec/blueprints/articles.rb +5 -0
  53. data/spec/blueprints/comments.rb +5 -0
  54. data/spec/blueprints/notes.rb +3 -0
  55. data/spec/blueprints/people.rb +4 -0
  56. data/spec/blueprints/tags.rb +3 -0
  57. data/spec/console.rb +22 -0
  58. data/spec/core_ext/symbol_spec.rb +75 -0
  59. data/spec/helpers/squeel_helper.rb +21 -0
  60. data/spec/spec_helper.rb +66 -0
  61. data/spec/squeel/adapters/active_record/context_spec.rb +44 -0
  62. data/spec/squeel/adapters/active_record/join_association_spec.rb +18 -0
  63. data/spec/squeel/adapters/active_record/join_dependency_spec.rb +66 -0
  64. data/spec/squeel/adapters/active_record/relation_spec.rb +627 -0
  65. data/spec/squeel/dsl_spec.rb +92 -0
  66. data/spec/squeel/nodes/function_spec.rb +149 -0
  67. data/spec/squeel/nodes/join_spec.rb +47 -0
  68. data/spec/squeel/nodes/key_path_spec.rb +100 -0
  69. data/spec/squeel/nodes/operation_spec.rb +149 -0
  70. data/spec/squeel/nodes/operators_spec.rb +87 -0
  71. data/spec/squeel/nodes/order_spec.rb +30 -0
  72. data/spec/squeel/nodes/predicate_operators_spec.rb +88 -0
  73. data/spec/squeel/nodes/predicate_spec.rb +50 -0
  74. data/spec/squeel/nodes/stub_spec.rb +198 -0
  75. data/spec/squeel/visitors/attribute_visitor_spec.rb +142 -0
  76. data/spec/squeel/visitors/predicate_visitor_spec.rb +342 -0
  77. data/spec/squeel/visitors/symbol_visitor_spec.rb +42 -0
  78. data/spec/support/schema.rb +104 -0
  79. data/squeel.gemspec +43 -0
  80. metadata +246 -0
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ module Squeel
4
+ module Nodes
5
+ describe PredicateOperators do
6
+
7
+ describe '&' do
8
+ it 'creates And nodes from hashes' do
9
+ left = {:name.matches => 'J%'}
10
+ right = {:name.matches => '%e'}
11
+ n = left & right
12
+ n.should be_a And
13
+ n.children.should eq [left, right]
14
+ end
15
+
16
+ it 'creates And nodes from predicates' do
17
+ left = :name.matches % 'J%'
18
+ right = :name.matches % '%e'
19
+ n = left & right
20
+ n.should be_a And
21
+ n.children.should eq [left, right]
22
+ end
23
+
24
+ it 'appends nodes to children from other And nodes' do
25
+ left = :name.matches % 'J%' & :name.matches % '%e'
26
+ right = :id.gt % 0
27
+ expected = left.children + [right]
28
+ left & right
29
+ left.should be_a And
30
+ left.children.should eq expected
31
+ end
32
+ end
33
+
34
+ describe '|' do
35
+ it 'creates Or nodes from hashes' do
36
+ left = {:name.matches => 'J%'}
37
+ right = {:name.matches => '%e'}
38
+ n = left | right
39
+ n.should be_a Or
40
+ n.left.should eq left
41
+ n.right.should eq right
42
+ end
43
+
44
+ it 'creates Or nodes from predicates' do
45
+ left = :name.matches % 'J%'
46
+ right = :name.matches % '%e'
47
+ n = left | right
48
+ n.should be_a Or
49
+ n.left.should eq left
50
+ n.right.should eq right
51
+ end
52
+
53
+ it 'creates Or nodes from other Or nodes' do
54
+ left = :name.matches % 'J%' | :name.matches % '%e'
55
+ right = :id.gt % 0 | :id.lt % 100
56
+ n = left | right
57
+ n.should be_a Or
58
+ n.left.should eq left
59
+ n.right.should eq right
60
+ end
61
+ end
62
+
63
+ describe '-@' do
64
+ it 'creates Not nodes from hashes' do
65
+ expr = {:name => 'Joe'}
66
+ n = - expr
67
+ n.should be_a Not
68
+ n.expr.should eq expr
69
+ end
70
+
71
+ it 'creates Not nodes from predicates' do
72
+ expr = :name.matches % 'J%'
73
+ n = - expr
74
+ n.should be_a Not
75
+ n.expr.should eq expr
76
+ end
77
+
78
+ it 'creates Not nodes from other Not nodes' do
79
+ expr = -(:name.matches % '%e')
80
+ n = - expr
81
+ n.should be_a Not
82
+ n.expr.should eq expr
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ module Squeel
4
+ module Nodes
5
+ describe Predicate do
6
+
7
+ it 'accepts a value on instantiation' do
8
+ @p = Predicate.new :name, :eq, 'value'
9
+ @p.value.should eq 'value'
10
+ end
11
+
12
+ it 'sets value via accessor' do
13
+ @p = Predicate.new :name, :eq
14
+ @p.value = 'value'
15
+ @p.value.should eq 'value'
16
+ end
17
+
18
+ it 'sets value via %' do
19
+ @p = Predicate.new :name, :eq
20
+ @p % 'value'
21
+ @p.value.should eq 'value'
22
+ end
23
+
24
+ it 'can be inquired for value presence' do
25
+ @p = Predicate.new :name, :eq
26
+ @p.value?.should be_false
27
+ @p.value = 'value'
28
+ @p.value?.should be_true
29
+ end
30
+
31
+ it 'can be ORed with another predicate' do
32
+ left = Predicate.new :name, :eq, 'Joe'
33
+ right = Predicate.new :name, :eq, 'Bob'
34
+ combined = left | right
35
+ combined.should be_a Nodes::Or
36
+ combined.left.should eq left
37
+ combined.right.should eq right
38
+ end
39
+
40
+ it 'can be ANDed with another predicate' do
41
+ left = Predicate.new :name, :eq, 'Joe'
42
+ right = Predicate.new :name, :eq, 'Bob'
43
+ combined = left & right
44
+ combined.should be_a Nodes::And
45
+ combined.children.should eq [left, right]
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,198 @@
1
+ require 'spec_helper'
2
+
3
+ module Squeel
4
+ module Nodes
5
+ describe Stub do
6
+ before do
7
+ @s = Stub.new :attribute
8
+ end
9
+
10
+ it 'hashes like a symbol' do
11
+ @s.hash.should eq :attribute.hash
12
+ end
13
+
14
+ it 'returns its symbol when sent to_sym' do
15
+ @s.to_sym.should eq :attribute
16
+ end
17
+
18
+ it 'returns a string matching its symbol when sent to_s' do
19
+ @s.to_s.should eq 'attribute'
20
+ end
21
+
22
+ it 'merges against matching stubs' do
23
+ hash1 = {Stub.new(:attribute) => 1}
24
+ hash2 = {Stub.new(:attribute) => 2}
25
+ merged = hash1.merge(hash2)
26
+ merged.keys.should have(1).key
27
+ merged[Stub.new(:attribute)].should eq 2
28
+ end
29
+
30
+ it 'creates a KeyPath when sent an unknown method' do
31
+ keypath = @s.another
32
+ keypath.should be_a KeyPath
33
+ keypath.path_with_endpoint.should eq [@s, Stub.new(:another)]
34
+ end
35
+
36
+ it 'creates a KeyPath with a join endpoint when sent a method with a Class param' do
37
+ keypath = @s.another(Person)
38
+ keypath.should be_a KeyPath
39
+ keypath.path_with_endpoint.should eq [@s, Join.new(:another, Arel::InnerJoin, Person)]
40
+ end
41
+
42
+ it 'creates an absolute keypath with just an endpoint with ~' do
43
+ node = ~@s
44
+ node.should be_a KeyPath
45
+ node.path.should eq []
46
+ node.endpoint.should eq @s
47
+ end
48
+
49
+ Squeel::Constants::PREDICATES.each do |method_name|
50
+ it "creates #{method_name} predicates with no value" do
51
+ predicate = @s.send(method_name)
52
+ predicate.expr.should eq :attribute
53
+ predicate.method_name.should eq method_name
54
+ predicate.value?.should be_false
55
+ end
56
+
57
+ it "creates #{method_name} predicates with a value" do
58
+ predicate = @s.send(method_name, 'value')
59
+ predicate.expr.should eq :attribute
60
+ predicate.method_name.should eq method_name
61
+ predicate.value.should eq 'value'
62
+ end
63
+ end
64
+
65
+ Squeel::Constants::PREDICATE_ALIASES.each do |method_name, aliases|
66
+ aliases.each do |aliaz|
67
+ ['', '_any', '_all'].each do |suffix|
68
+ it "creates #{method_name.to_s + suffix} predicates with no value using the alias #{aliaz.to_s + suffix}" do
69
+ predicate = @s.send(aliaz.to_s + suffix)
70
+ predicate.expr.should eq :attribute
71
+ predicate.method_name.should eq "#{method_name}#{suffix}".to_sym
72
+ predicate.value?.should be_false
73
+ end
74
+
75
+ it "creates #{method_name.to_s + suffix} predicates with a value using the alias #{aliaz.to_s + suffix}" do
76
+ predicate = @s.send((aliaz.to_s + suffix), 'value')
77
+ predicate.expr.should eq :attribute
78
+ predicate.method_name.should eq "#{method_name}#{suffix}".to_sym
79
+ predicate.value.should eq 'value'
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ it 'creates eq predicates with ==' do
86
+ predicate = @s == 1
87
+ predicate.expr.should eq :attribute
88
+ predicate.method_name.should eq :eq
89
+ predicate.value.should eq 1
90
+ end
91
+
92
+ it 'creates not_eq predicates with ^' do
93
+ predicate = @s ^ 1
94
+ predicate.expr.should eq :attribute
95
+ predicate.method_name.should eq :not_eq
96
+ predicate.value.should eq 1
97
+ end
98
+
99
+ it 'creates not_eq predicates with !=' do
100
+ predicate = @s != 1
101
+ predicate.expr.should eq :attribute
102
+ predicate.method_name.should eq :not_eq
103
+ predicate.value.should eq 1
104
+ end if respond_to?('!=')
105
+
106
+ it 'creates in predicates with >>' do
107
+ predicate = @s >> [1,2,3]
108
+ predicate.expr.should eq :attribute
109
+ predicate.method_name.should eq :in
110
+ predicate.value.should eq [1,2,3]
111
+ end
112
+
113
+ it 'creates not_in predicates with <<' do
114
+ predicate = @s << [1,2,3]
115
+ predicate.expr.should eq :attribute
116
+ predicate.method_name.should eq :not_in
117
+ predicate.value.should eq [1,2,3]
118
+ end
119
+
120
+ it 'creates matches predicates with =~' do
121
+ predicate = @s =~ '%bob%'
122
+ predicate.expr.should eq :attribute
123
+ predicate.method_name.should eq :matches
124
+ predicate.value.should eq '%bob%'
125
+ end
126
+
127
+ it 'creates does_not_match predicates with !~' do
128
+ predicate = @s !~ '%bob%'
129
+ predicate.expr.should eq :attribute
130
+ predicate.method_name.should eq :does_not_match
131
+ predicate.value.should eq '%bob%'
132
+ end if respond_to?('!~')
133
+
134
+ it 'creates gt predicates with >' do
135
+ predicate = @s > 1
136
+ predicate.expr.should eq :attribute
137
+ predicate.method_name.should eq :gt
138
+ predicate.value.should eq 1
139
+ end
140
+
141
+ it 'creates gteq predicates with >=' do
142
+ predicate = @s >= 1
143
+ predicate.expr.should eq :attribute
144
+ predicate.method_name.should eq :gteq
145
+ predicate.value.should eq 1
146
+ end
147
+
148
+ it 'creates lt predicates with <' do
149
+ predicate = @s < 1
150
+ predicate.expr.should eq :attribute
151
+ predicate.method_name.should eq :lt
152
+ predicate.value.should eq 1
153
+ end
154
+
155
+ it 'creates lteq predicates with <=' do
156
+ predicate = @s <= 1
157
+ predicate.expr.should eq :attribute
158
+ predicate.method_name.should eq :lteq
159
+ predicate.value.should eq 1
160
+ end
161
+
162
+ it 'creates ascending orders' do
163
+ order = @s.asc
164
+ order.should be_ascending
165
+ end
166
+
167
+ it 'creates descending orders' do
168
+ order = @s.desc
169
+ order.should be_descending
170
+ end
171
+
172
+ it 'creates inner joins' do
173
+ join = @s.inner
174
+ join.should be_a Join
175
+ join._type.should eq Arel::InnerJoin
176
+ end
177
+
178
+ it 'creates outer joins' do
179
+ join = @s.outer
180
+ join.should be_a Join
181
+ join._type.should eq Arel::OuterJoin
182
+ end
183
+
184
+ it 'creates functions with #func' do
185
+ function = @s.func
186
+ function.should be_a Function
187
+ end
188
+
189
+ it 'creates as nodes with #as' do
190
+ as = @s.as('other_name')
191
+ as.should be_a Squeel::Nodes::As
192
+ as.left.should eq @s
193
+ as.right.should eq 'other_name'
194
+ end
195
+
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,142 @@
1
+ module Squeel
2
+ module Visitors
3
+ describe AttributeVisitor do
4
+
5
+ before do
6
+ @jd = new_join_dependency(Person, {
7
+ :children => {
8
+ :children => {
9
+ :parent => :parent
10
+ }
11
+ }
12
+ }, [])
13
+ @c = Squeel::Adapters::ActiveRecord::Context.new(@jd)
14
+ @v = AttributeVisitor.new(@c)
15
+ end
16
+
17
+ it 'creates a bare ARel attribute given a symbol with no asc/desc' do
18
+ attribute = @v.accept(:name)
19
+ attribute.should be_a Arel::Attribute
20
+ attribute.name.should eq :name
21
+ attribute.relation.name.should eq 'people'
22
+ end
23
+
24
+ it 'creates the ordering against the proper table for nested hashes' do
25
+ orders = @v.accept({
26
+ :children => {
27
+ :children => {
28
+ :parent => {
29
+ :parent => :name.asc
30
+ }
31
+ }
32
+ }
33
+ })
34
+ orders.should be_a Array
35
+ ordering = orders.first
36
+ ordering.should be_a Arel::Nodes::Ordering
37
+ ordering.expr.relation.table_alias.should eq 'parents_people_2'
38
+ ordering.direction.should eq :asc
39
+ end
40
+
41
+ it 'does not alter values it is unable to accept' do
42
+ orders = @v.accept(['THIS PARAMETER', 'WHAT DOES IT MEAN???'])
43
+ orders.should eq ['THIS PARAMETER', 'WHAT DOES IT MEAN???']
44
+ end
45
+
46
+ it 'treats keypath keys like nested hashes' do
47
+ ordering = @v.accept(Nodes::Stub.new(:children).children.parent.parent.name.asc)
48
+ ordering.should be_a Arel::Nodes::Ordering
49
+ ordering.expr.relation.table_alias.should eq 'parents_people_2'
50
+ ordering.direction.should eq :asc
51
+ end
52
+
53
+ it 'honors absolute keypaths' do
54
+ orders = @v.accept(dsl{{children => {children => ~children.children.name.asc}}})
55
+ orders.should be_a Array
56
+ ordering = orders.first
57
+ ordering.expr.relation.table_alias.should eq 'children_people_2'
58
+ ordering.direction.should eq :asc
59
+ end
60
+
61
+ it 'allows hashes with keypath keys' do
62
+ orders = @v.accept(Nodes::Stub.new(:children).children.parent.parent => :name.asc)
63
+ orders.should be_a Array
64
+ ordering = orders.first
65
+ ordering.should be_a Arel::Nodes::Ordering
66
+ ordering.expr.relation.table_alias.should eq 'parents_people_2'
67
+ ordering.direction.should eq :asc
68
+ end
69
+
70
+ it 'creates an ARel NamedFunction node for a Function node' do
71
+ function = @v.accept(:find_in_set.func())
72
+ function.should be_a Arel::Nodes::NamedFunction
73
+ end
74
+
75
+ it 'maps symbols in Function args to ARel attributes' do
76
+ function = @v.accept(:find_in_set.func(:id, '1,2,3'))
77
+ function.to_sql.should match /find_in_set\("people"."id", '1,2,3'\)/
78
+ end
79
+
80
+ it 'accepts Order with Function expression' do
81
+ function = @v.accept(dsl{find_in_set(children.children.id, '1,2,3').desc})
82
+ function.to_sql.should match /find_in_set\("children_people_2"."id", '1,2,3'\) DESC/
83
+ end
84
+
85
+ it 'accepts keypaths as function args' do
86
+ function = @v.accept(dsl{find_in_set(children.children.id, '1,2,3')})
87
+ function.to_sql.should match /find_in_set\("children_people_2"."id", '1,2,3'\)/
88
+ end
89
+
90
+ it 'sets the alias on the ARel NamedFunction from the Function alias' do
91
+ function = @v.accept(:find_in_set.func(:id, '1,2,3').as('newname'))
92
+ function.to_sql.should match /newname/
93
+ end
94
+
95
+ it 'accepts As nodes containing symbols' do
96
+ as = @v.accept(:name.as('other_name'))
97
+ as.to_sql.should match /"people"."name" AS other_name/
98
+ end
99
+
100
+ it 'accepts As nodes containing stubs' do
101
+ as = @v.accept(dsl{name.as(other_name)})
102
+ as.to_sql.should match /"people"."name" AS other_name/
103
+ end
104
+
105
+ it 'accepts As nodes containing keypaths' do
106
+ as = @v.accept(dsl{children.name.as(other_name)})
107
+ as.to_sql.should match /"children_people"."name" AS other_name/
108
+ end
109
+
110
+ it 'creates an ARel Addition node for an Operation node with + as operator' do
111
+ operation = @v.accept(dsl{id + 1})
112
+ operation.should be_a Arel::Nodes::Addition
113
+ end
114
+
115
+ it 'creates an ARel Subtraction node for an Operation node with - as operator' do
116
+ operation = @v.accept(dsl{id - 1})
117
+ operation.should be_a Arel::Nodes::Subtraction
118
+ end
119
+
120
+ it 'creates an ARel Multiplication node for an Operation node with * as operator' do
121
+ operation = @v.accept(dsl{id * 1})
122
+ operation.should be_a Arel::Nodes::Multiplication
123
+ end
124
+
125
+ it 'creates an ARel Division node for an Operation node with / as operator' do
126
+ operation = @v.accept(dsl{id / 1})
127
+ operation.should be_a Arel::Nodes::Division
128
+ end
129
+
130
+ it 'sets the alias on an InfixOperation from the Operation alias' do
131
+ operation = @v.accept(dsl{(id + 1).as(:incremented_id)})
132
+ operation.to_sql.should match /incremented_id/
133
+ end
134
+
135
+ it 'accepts Order with Operation expression' do
136
+ operation = @v.accept(dsl{(id / 1).desc})
137
+ operation.to_sql.should match /"people"."id" \/ 1 DESC/
138
+ end
139
+
140
+ end
141
+ end
142
+ end