squeel_rbg 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.yardopts +3 -0
- data/Gemfile +13 -0
- data/LICENSE +20 -0
- data/README.md +398 -0
- data/Rakefile +19 -0
- data/lib/core_ext/hash.rb +13 -0
- data/lib/core_ext/symbol.rb +39 -0
- data/lib/squeel/adapters/active_record/3.0/association_preload.rb +15 -0
- data/lib/squeel/adapters/active_record/3.0/compat.rb +142 -0
- data/lib/squeel/adapters/active_record/3.0/context.rb +66 -0
- data/lib/squeel/adapters/active_record/3.0/join_association.rb +54 -0
- data/lib/squeel/adapters/active_record/3.0/join_dependency.rb +84 -0
- data/lib/squeel/adapters/active_record/3.0/relation.rb +327 -0
- data/lib/squeel/adapters/active_record/context.rb +66 -0
- data/lib/squeel/adapters/active_record/join_association.rb +44 -0
- data/lib/squeel/adapters/active_record/join_dependency.rb +83 -0
- data/lib/squeel/adapters/active_record/preloader.rb +21 -0
- data/lib/squeel/adapters/active_record/relation.rb +351 -0
- data/lib/squeel/adapters/active_record.rb +28 -0
- data/lib/squeel/configuration.rb +54 -0
- data/lib/squeel/constants.rb +24 -0
- data/lib/squeel/context.rb +67 -0
- data/lib/squeel/dsl.rb +86 -0
- data/lib/squeel/nodes/aliasing.rb +13 -0
- data/lib/squeel/nodes/and.rb +9 -0
- data/lib/squeel/nodes/as.rb +14 -0
- data/lib/squeel/nodes/binary.rb +32 -0
- data/lib/squeel/nodes/function.rb +66 -0
- data/lib/squeel/nodes/join.rb +113 -0
- data/lib/squeel/nodes/key_path.rb +192 -0
- data/lib/squeel/nodes/nary.rb +45 -0
- data/lib/squeel/nodes/not.rb +9 -0
- data/lib/squeel/nodes/operation.rb +32 -0
- data/lib/squeel/nodes/operators.rb +43 -0
- data/lib/squeel/nodes/or.rb +9 -0
- data/lib/squeel/nodes/order.rb +53 -0
- data/lib/squeel/nodes/predicate.rb +71 -0
- data/lib/squeel/nodes/predicate_operators.rb +29 -0
- data/lib/squeel/nodes/stub.rb +125 -0
- data/lib/squeel/nodes/unary.rb +28 -0
- data/lib/squeel/nodes.rb +17 -0
- data/lib/squeel/predicate_methods.rb +14 -0
- data/lib/squeel/version.rb +3 -0
- data/lib/squeel/visitors/attribute_visitor.rb +191 -0
- data/lib/squeel/visitors/base.rb +112 -0
- data/lib/squeel/visitors/predicate_visitor.rb +319 -0
- data/lib/squeel/visitors/symbol_visitor.rb +48 -0
- data/lib/squeel/visitors.rb +3 -0
- data/lib/squeel.rb +28 -0
- data/lib/squeel_rbg.rb +5 -0
- data/spec/blueprints/articles.rb +5 -0
- data/spec/blueprints/comments.rb +5 -0
- data/spec/blueprints/notes.rb +3 -0
- data/spec/blueprints/people.rb +4 -0
- data/spec/blueprints/tags.rb +3 -0
- data/spec/console.rb +22 -0
- data/spec/core_ext/symbol_spec.rb +75 -0
- data/spec/helpers/squeel_helper.rb +21 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/squeel/adapters/active_record/context_spec.rb +44 -0
- data/spec/squeel/adapters/active_record/join_association_spec.rb +18 -0
- data/spec/squeel/adapters/active_record/join_dependency_spec.rb +66 -0
- data/spec/squeel/adapters/active_record/relation_spec.rb +627 -0
- data/spec/squeel/dsl_spec.rb +92 -0
- data/spec/squeel/nodes/function_spec.rb +149 -0
- data/spec/squeel/nodes/join_spec.rb +47 -0
- data/spec/squeel/nodes/key_path_spec.rb +100 -0
- data/spec/squeel/nodes/operation_spec.rb +149 -0
- data/spec/squeel/nodes/operators_spec.rb +87 -0
- data/spec/squeel/nodes/order_spec.rb +30 -0
- data/spec/squeel/nodes/predicate_operators_spec.rb +88 -0
- data/spec/squeel/nodes/predicate_spec.rb +50 -0
- data/spec/squeel/nodes/stub_spec.rb +198 -0
- data/spec/squeel/visitors/attribute_visitor_spec.rb +142 -0
- data/spec/squeel/visitors/predicate_visitor_spec.rb +342 -0
- data/spec/squeel/visitors/symbol_visitor_spec.rb +42 -0
- data/spec/support/schema.rb +104 -0
- data/squeel.gemspec +43 -0
- metadata +246 -0
@@ -0,0 +1,342 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Visitors
|
5
|
+
describe PredicateVisitor do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@jd = new_join_dependency(Person, {
|
9
|
+
:children => {
|
10
|
+
:children => {
|
11
|
+
:parent => :parent
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}, [])
|
15
|
+
@c = Squeel::Adapters::ActiveRecord::Context.new(@jd)
|
16
|
+
@v = PredicateVisitor.new(@c)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'does not quote Arel::SelectManager values in Predicate nodes' do
|
20
|
+
predicate = Nodes::Predicate.new(Nodes::Function.new(:blah, [1, 2]), :in, Person.select(:id).arel)
|
21
|
+
node = @v.accept(predicate)
|
22
|
+
node.should be_a Arel::Nodes::In
|
23
|
+
node.right.should be_a Arel::Nodes::SelectStatement
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'creates Equality nodes for simple hashes' do
|
27
|
+
predicate = @v.accept(:name => 'Joe')
|
28
|
+
predicate.should be_a Arel::Nodes::Equality
|
29
|
+
predicate.left.name.should eq :name
|
30
|
+
predicate.right.should eq 'Joe'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'creates In nodes for simple hashes with an array as a value' do
|
34
|
+
predicate = @v.accept(:name => ['Joe', 'Bob'])
|
35
|
+
predicate.should be_a Arel::Nodes::In
|
36
|
+
predicate.left.name.should eq :name
|
37
|
+
predicate.right.should eq ['Joe', 'Bob']
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'generates "1=0" when given an empty array value in a hash' do
|
41
|
+
predicate = @v.accept(:id => [])
|
42
|
+
predicate.should be_a Arel::Nodes::SqlLiteral
|
43
|
+
predicate.should eq '1=0'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'generates "1=0" for in predicates when given an empty array value' do
|
47
|
+
predicate = @v.accept(:id.in => [])
|
48
|
+
predicate.should be_a Arel::Nodes::SqlLiteral
|
49
|
+
predicate.should eq '1=0'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'generates "1=1" for not_in predicates when given an empty array value' do
|
53
|
+
predicate = @v.accept(:id.not_in => [])
|
54
|
+
predicate.should be_a Arel::Nodes::SqlLiteral
|
55
|
+
predicate.should eq '1=1'
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'allows a subquery on the value side of an explicit predicate' do
|
59
|
+
predicate = @v.accept dsl{name.in(Person.select{name}.where{name.in(['Aric Smith', 'Gladyce Kulas'])})}
|
60
|
+
predicate.should be_a Arel::Nodes::In
|
61
|
+
predicate.left.name.should eq :name
|
62
|
+
predicate.right.should be_a Arel::Nodes::SelectStatement
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'allows a subquery on the value side of an implicit predicate' do
|
66
|
+
predicate = @v.accept(:name => Person.select{name}.where{name.in(['Aric Smith', 'Gladyce Kulas'])})
|
67
|
+
predicate.should be_a Arel::Nodes::In
|
68
|
+
predicate.left.name.should eq :name
|
69
|
+
predicate.right.should be_a Arel::Nodes::SelectStatement
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'converts ActiveRecord::Base objects to their id' do
|
73
|
+
predicate = @v.accept(:id => Person.first)
|
74
|
+
predicate.should be_a Arel::Nodes::Equality
|
75
|
+
predicate.left.name.should eq :id
|
76
|
+
predicate.right.should eq 1
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'converts arrays of ActiveRecord::Base objects to their ids' do
|
80
|
+
predicate = @v.accept(:id => [Person.first, Person.last])
|
81
|
+
predicate.should be_a Arel::Nodes::In
|
82
|
+
predicate.left.name.should eq :id
|
83
|
+
predicate.right.should eq [1, 332]
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'creates the node against the proper table for nested hashes' do
|
87
|
+
predicate = @v.accept({
|
88
|
+
:children => {
|
89
|
+
:children => {
|
90
|
+
:parent => {
|
91
|
+
:parent => {
|
92
|
+
:name => 'Joe'
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
})
|
98
|
+
predicate.should be_a Arel::Nodes::Equality
|
99
|
+
predicate.left.relation.table_alias.should eq 'parents_people_2'
|
100
|
+
predicate.right.should eq 'Joe'
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'treats keypath keys like nested hashes' do
|
104
|
+
standard = @v.accept({
|
105
|
+
:children => {
|
106
|
+
:children => {
|
107
|
+
:parent => {
|
108
|
+
:parent => {
|
109
|
+
:name => 'Joe'
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
})
|
115
|
+
keypath = @v.accept(Nodes::Stub.new(:children).children.parent.parent.name => 'Joe')
|
116
|
+
keypath.to_sql.should eq standard.to_sql
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'honors absolute keypaths' do
|
120
|
+
standard = @v.accept({
|
121
|
+
:children => {
|
122
|
+
:children => {
|
123
|
+
:name => 'Joe'
|
124
|
+
}
|
125
|
+
}
|
126
|
+
})
|
127
|
+
keypath = @v.accept(dsl{{children => {children => {~children.children.name => 'Joe'}}}})
|
128
|
+
keypath.to_sql.should eq standard.to_sql
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'honors absolute keypaths with only an endpoint' do
|
132
|
+
standard = @v.accept({:name => 'Joe'})
|
133
|
+
keypath = @v.accept(dsl{{children => {children => {~name => 'Joe'}}}})
|
134
|
+
keypath.to_sql.should eq standard.to_sql
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'allows incomplete predicates (missing value) as keys' do
|
138
|
+
standard = @v.accept({
|
139
|
+
:children => {
|
140
|
+
:children => {
|
141
|
+
:parent => {
|
142
|
+
:parent => {
|
143
|
+
:name.matches => 'Joe%'
|
144
|
+
}
|
145
|
+
}
|
146
|
+
}
|
147
|
+
}
|
148
|
+
})
|
149
|
+
keypath = @v.accept(Nodes::Stub.new(:children).children.parent.parent.name.matches => 'Joe%')
|
150
|
+
keypath.to_sql.should eq standard.to_sql
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'allows hashes as values with keypath keys' do
|
154
|
+
standard = @v.accept({
|
155
|
+
:children => {
|
156
|
+
:children => {
|
157
|
+
:parent => {
|
158
|
+
:parent => {
|
159
|
+
:name => 'Joe'
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
})
|
165
|
+
keypath = @v.accept(Nodes::Stub.new(:children).children.parent.parent => {:name => 'Joe'})
|
166
|
+
keypath.to_sql.should eq standard.to_sql
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'contextualizes Stub values' do
|
170
|
+
predicate = @v.accept(dsl{{name => name}})
|
171
|
+
predicate.should be_a Arel::Nodes::Equality
|
172
|
+
predicate.right.should be_a Arel::Attribute
|
173
|
+
predicate.to_sql.should match /"people"."name" = "people"."name"/
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'contextualizes Symbol values' do
|
177
|
+
predicate = @v.accept(:name => :name)
|
178
|
+
predicate.should be_a Arel::Nodes::Equality
|
179
|
+
predicate.right.should be_a Arel::Attribute
|
180
|
+
predicate.to_sql.should match /"people"."name" = "people"."name"/
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'contextualizes KeyPath values in hashes' do
|
184
|
+
predicate = @v.accept(dsl{{name => children.name}})
|
185
|
+
predicate.should be_a Arel::Nodes::Equality
|
186
|
+
predicate.right.should be_a Arel::Attribute
|
187
|
+
predicate.to_sql.should match /"people"."name" = "children_people"."name"/
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'contextualizes KeyPath values in predicates' do
|
191
|
+
predicate = @v.accept(dsl{name == children.name})
|
192
|
+
predicate.should be_a Arel::Nodes::Equality
|
193
|
+
predicate.right.should be_a Arel::Attribute
|
194
|
+
predicate.to_sql.should match /"people"."name" = "children_people"."name"/
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'honors an explicit table in string keys' do
|
198
|
+
predicate = @v.accept('things.attribute' => 'retro')
|
199
|
+
predicate.should be_a Arel::Nodes::Equality
|
200
|
+
predicate.to_sql.should match /"things"."attribute" = 'retro'/
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'visits ActiveRecord::Relation values in predicates' do
|
204
|
+
predicate = @v.accept(dsl{id >> Person.select{id}.limit(3).order{id.desc}})
|
205
|
+
predicate.should be_a Arel::Nodes::In
|
206
|
+
predicate.right.should be_a Arel::Nodes::SelectStatement
|
207
|
+
predicate.to_sql.should be_like '"people"."id" IN (SELECT "people"."id" FROM "people" ORDER BY "people"."id" DESC LIMIT 3)'
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'converts ActiveRecord::Relation values in function arguments to their ARel AST' do
|
211
|
+
predicate = @v.accept(dsl{exists(Person.where{name == 'Aric Smith'})})
|
212
|
+
predicate.should be_a Arel::Nodes::NamedFunction
|
213
|
+
predicate.expressions.first.should be_a Arel::Nodes::SelectStatement
|
214
|
+
predicate.to_sql.should be_like "exists(SELECT \"people\".* FROM \"people\" WHERE \"people\".\"name\" = 'Aric Smith')"
|
215
|
+
end
|
216
|
+
|
217
|
+
it "doesn't try to sanitize_sql an array of strings in the value of a Predicate" do
|
218
|
+
predicate = @v.accept(dsl{name >> ['Aric Smith', 'Gladyce Kulas']})
|
219
|
+
predicate.should be_a Arel::Nodes::In
|
220
|
+
predicate.right.should be_an Array
|
221
|
+
predicate.to_sql.should match /"people"."name" IN \('Aric Smith', 'Gladyce Kulas'\)/
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'creates a node of the proper type when a hash has a Predicate as a key' do
|
225
|
+
predicate = @v.accept(:name.matches => 'Joe%')
|
226
|
+
predicate.should be_a Arel::Nodes::Matches
|
227
|
+
predicate.left.name.should eq :name
|
228
|
+
predicate.right.should eq 'Joe%'
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'treats hash keys as an association when there is an Or on the value side' do
|
232
|
+
predicate = @v.accept(:children => (:name.matches % 'Joe%' | :name.matches % 'Bob%'))
|
233
|
+
predicate.should be_a Arel::Nodes::Grouping
|
234
|
+
predicate.expr.should be_a Arel::Nodes::Or
|
235
|
+
predicate.expr.left.should be_a Arel::Nodes::Matches
|
236
|
+
predicate.expr.left.left.relation.table_alias.should eq 'children_people'
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'treats hash keys as an association when there is an And on the value side' do
|
240
|
+
predicate = @v.accept(:children => (:name.matches % 'Joe%' & :name.matches % 'Bob%'))
|
241
|
+
predicate.should be_a Arel::Nodes::Grouping
|
242
|
+
predicate.expr.should be_a Arel::Nodes::And
|
243
|
+
predicate.expr.children.should have(2).items
|
244
|
+
predicate.expr.children.first.should be_a Arel::Nodes::Matches
|
245
|
+
predicate.expr.children.first.left.relation.table_alias.should eq 'children_people'
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'treats hash keys as an association when there is a Not on the value side' do
|
249
|
+
predicate = @v.accept(:children => -(:name.matches % 'Joe%'))
|
250
|
+
predicate.should be_a Arel::Nodes::Not
|
251
|
+
predicate.expr.should be_a Arel::Nodes::Matches
|
252
|
+
predicate.expr.left.relation.table_alias.should eq 'children_people'
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'treats hash keys as an association when there is a Predicate on the value side' do
|
256
|
+
predicate = @v.accept(:children => (:name.matches % 'Joe%'))
|
257
|
+
predicate.should be_a Arel::Nodes::Matches
|
258
|
+
predicate.left.relation.table_alias.should eq 'children_people'
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'treats hash keys as an association when there is a KeyPath on the value side' do
|
262
|
+
predicate = @v.accept(:children => Nodes::Stub.new(:children).name.eq('Joe'))
|
263
|
+
predicate.should be_a Arel::Nodes::Equality
|
264
|
+
predicate.left.relation.table_alias.should eq 'children_people_2'
|
265
|
+
predicate.left.name.should eq :name
|
266
|
+
predicate.right.should eq 'Joe'
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'creates an ARel Grouping node containing an Or node for Or nodes' do
|
270
|
+
left = :name.matches % 'Joe%'
|
271
|
+
right = :id.gt % 1
|
272
|
+
predicate = @v.accept(left | right)
|
273
|
+
predicate.should be_a Arel::Nodes::Grouping
|
274
|
+
predicate.expr.should be_a Arel::Nodes::Or
|
275
|
+
predicate.expr.left.should be_a Arel::Nodes::Matches
|
276
|
+
predicate.expr.right.should be_a Arel::Nodes::GreaterThan
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'creates an ARel Not node for a Not node' do
|
280
|
+
expr = -(:name.matches % 'Joe%')
|
281
|
+
predicate = @v.accept(expr)
|
282
|
+
predicate.should be_a Arel::Nodes::Not
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'creates an ARel NamedFunction node for a Function node' do
|
286
|
+
function = @v.accept(:find_in_set.func())
|
287
|
+
function.should be_a Arel::Nodes::NamedFunction
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'maps symbols in Function args to ARel attributes' do
|
291
|
+
function = @v.accept(:find_in_set.func(:id, '1,2,3'))
|
292
|
+
function.to_sql.should match /"people"."id"/
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'sets the alias on the ARel NamedFunction from the Function alias' do
|
296
|
+
function = @v.accept(:find_in_set.func(:id, '1,2,3').as('newname'))
|
297
|
+
function.to_sql.should match /newname/
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'creates an ARel Addition node for an Operation node with + as operator' do
|
301
|
+
operation = @v.accept(dsl{id + 1})
|
302
|
+
operation.should be_a Arel::Nodes::Addition
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'creates an ARel Subtraction node for an Operation node with - as operator' do
|
306
|
+
operation = @v.accept(dsl{id - 1})
|
307
|
+
operation.should be_a Arel::Nodes::Subtraction
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'creates an ARel Multiplication node for an Operation node with * as operator' do
|
311
|
+
operation = @v.accept(dsl{id * 1})
|
312
|
+
operation.should be_a Arel::Nodes::Multiplication
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'creates an ARel Division node for an Operation node with / as operator' do
|
316
|
+
operation = @v.accept(dsl{id / 1})
|
317
|
+
operation.should be_a Arel::Nodes::Division
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'sets the alias on an InfixOperation from the Operation alias' do
|
321
|
+
operation = @v.accept(dsl{(id + 1).as(:incremented_id)})
|
322
|
+
operation.to_sql.should match /incremented_id/
|
323
|
+
end
|
324
|
+
|
325
|
+
context 'with polymorphic joins in the JoinDependency' do
|
326
|
+
before do
|
327
|
+
@jd = new_join_dependency(Note, dsl{[notable(Article), notable(Person)]}, [])
|
328
|
+
@c = Squeel::Adapters::ActiveRecord::Context.new(@jd)
|
329
|
+
@v = PredicateVisitor.new(@c)
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'respects the polymorphic class in conditions' do
|
333
|
+
article_predicate = @v.accept dsl{{notable(Article) => {:title => 'Hello world!'}}}
|
334
|
+
person_predicate = @v.accept dsl{{notable(Person) => {:name => 'Ernie'}}}
|
335
|
+
article_predicate.left.relation.name.should eq 'articles'
|
336
|
+
person_predicate.left.relation.name.should eq 'people'
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Visitors
|
5
|
+
describe SymbolVisitor do
|
6
|
+
before do
|
7
|
+
@v = SymbolVisitor.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns symbols unmodified' do
|
11
|
+
@v.accept(:blah).should eq :blah
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'converts stubs to symbols' do
|
15
|
+
@v.accept(dsl{blah}).should eq :blah
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'converts joins to their names' do
|
19
|
+
@v.accept(dsl{blah(Article)}).should eq :blah
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'converts keypaths to their hash equivalents' do
|
23
|
+
@v.accept(dsl{one.two.three.four}).should eq({
|
24
|
+
:one => {:two => {:three => :four}}
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'visits hashes' do
|
29
|
+
@v.accept(dsl{{
|
30
|
+
blah1 => {blah2(Article) => blah3}
|
31
|
+
}}).should eq({:blah1 => {:blah2 => :blah3}})
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'visits arrays' do
|
35
|
+
@v.accept(dsl{[{
|
36
|
+
blah1 => {blah2(Article) => blah3}
|
37
|
+
}]}).should eq([{:blah1 => {:blah2 => :blah3}}])
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection(
|
4
|
+
:adapter => 'sqlite3',
|
5
|
+
:database => ':memory:'
|
6
|
+
)
|
7
|
+
|
8
|
+
class Person < ActiveRecord::Base
|
9
|
+
belongs_to :parent, :class_name => 'Person', :foreign_key => :parent_id
|
10
|
+
has_many :children, :class_name => 'Person', :foreign_key => :parent_id
|
11
|
+
has_many :articles
|
12
|
+
has_many :articles_with_condition, :class_name => 'Article', :conditions => {:title => 'Condition'}
|
13
|
+
has_many :comments
|
14
|
+
has_many :condition_article_comments, :through => :articles_with_condition, :source => :comments
|
15
|
+
has_many :authored_article_comments, :through => :articles,
|
16
|
+
:source => :comments
|
17
|
+
has_many :notes, :as => :notable
|
18
|
+
end
|
19
|
+
|
20
|
+
class Article < ActiveRecord::Base
|
21
|
+
belongs_to :person
|
22
|
+
has_many :comments
|
23
|
+
has_and_belongs_to_many :tags
|
24
|
+
has_many :notes, :as => :notable
|
25
|
+
has_many :commenters, :through => :comments, :source => :person
|
26
|
+
end
|
27
|
+
|
28
|
+
class Comment < ActiveRecord::Base
|
29
|
+
belongs_to :article
|
30
|
+
belongs_to :person
|
31
|
+
end
|
32
|
+
|
33
|
+
class Tag < ActiveRecord::Base
|
34
|
+
has_and_belongs_to_many :articles
|
35
|
+
end
|
36
|
+
|
37
|
+
class Note < ActiveRecord::Base
|
38
|
+
belongs_to :notable, :polymorphic => true
|
39
|
+
end
|
40
|
+
|
41
|
+
module Schema
|
42
|
+
def self.create
|
43
|
+
ActiveRecord::Base.silence do
|
44
|
+
ActiveRecord::Migration.verbose = false
|
45
|
+
|
46
|
+
ActiveRecord::Schema.define do
|
47
|
+
create_table :people, :force => true do |t|
|
48
|
+
t.integer :parent_id
|
49
|
+
t.string :name
|
50
|
+
t.integer :salary
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :articles, :force => true do |t|
|
54
|
+
t.integer :person_id
|
55
|
+
t.string :title
|
56
|
+
t.text :body
|
57
|
+
end
|
58
|
+
|
59
|
+
create_table :comments, :force => true do |t|
|
60
|
+
t.integer :article_id
|
61
|
+
t.integer :person_id
|
62
|
+
t.text :body
|
63
|
+
end
|
64
|
+
|
65
|
+
create_table :tags, :force => true do |t|
|
66
|
+
t.string :name
|
67
|
+
end
|
68
|
+
|
69
|
+
create_table :articles_tags, :force => true, :id => false do |t|
|
70
|
+
t.integer :article_id
|
71
|
+
t.integer :tag_id
|
72
|
+
end
|
73
|
+
|
74
|
+
create_table :notes, :force => true do |t|
|
75
|
+
t.integer :notable_id
|
76
|
+
t.string :notable_type
|
77
|
+
t.string :note
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
10.times do
|
84
|
+
person = Person.make
|
85
|
+
Note.make(:notable => person)
|
86
|
+
3.times do
|
87
|
+
article = Article.make(:person => person)
|
88
|
+
3.times do
|
89
|
+
article.tags = [Tag.make, Tag.make, Tag.make]
|
90
|
+
end
|
91
|
+
Note.make(:notable => article)
|
92
|
+
10.times do
|
93
|
+
Comment.make(:article => article)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
2.times do
|
97
|
+
Comment.make(:person => person)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
Comment.make(:body => 'First post!', :article => Article.make(:title => 'Hello, world!'))
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/squeel.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "squeel/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "squeel_rbg"
|
7
|
+
s.version = Squeel::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Russen Guggemos"]
|
10
|
+
s.email = ["rguggemos@berklee.edu"]
|
11
|
+
s.homepage = "http://metautonomo.us/projects/squeel"
|
12
|
+
s.summary = %q{ActiveRecord 3, improved.}
|
13
|
+
s.description = %q{
|
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.
|
18
|
+
|
19
|
+
I'm trying to push a version of this gem, so that bundler doesn't screw up with the :git included versions.
|
20
|
+
}
|
21
|
+
s.post_install_message = %q{
|
22
|
+
*** Thanks for installing Squeel! ***
|
23
|
+
Be sure to check out http://metautonomo.us/projects/squeel/ for a
|
24
|
+
walkthrough of Squeel's features, and click the donate link if
|
25
|
+
you're feeling especially appreciative. It'd help me justify this
|
26
|
+
"open source" stuff to my lovely wife. :)
|
27
|
+
|
28
|
+
}
|
29
|
+
|
30
|
+
s.rubyforge_project = "squeel_rbg"
|
31
|
+
|
32
|
+
s.add_dependency 'activerecord', '~> 3.0'
|
33
|
+
s.add_dependency 'activesupport', '~> 3.0'
|
34
|
+
s.add_development_dependency 'rspec', '~> 2.5.0'
|
35
|
+
s.add_development_dependency 'machinist', '~> 1.0.6'
|
36
|
+
s.add_development_dependency 'faker', '~> 0.9.5'
|
37
|
+
s.add_development_dependency 'sqlite3', '~> 1.3.3'
|
38
|
+
|
39
|
+
s.files = `git ls-files`.split("\n")
|
40
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
41
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
end
|