cequel 0.5.6 → 1.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cequel.rb +5 -8
  3. data/lib/cequel/errors.rb +1 -0
  4. data/lib/cequel/metal.rb +17 -0
  5. data/lib/cequel/metal/batch.rb +62 -0
  6. data/lib/cequel/metal/cql_row_specification.rb +26 -0
  7. data/lib/cequel/metal/data_set.rb +461 -0
  8. data/lib/cequel/metal/deleter.rb +47 -0
  9. data/lib/cequel/metal/incrementer.rb +35 -0
  10. data/lib/cequel/metal/inserter.rb +53 -0
  11. data/lib/cequel/metal/keyspace.rb +213 -0
  12. data/lib/cequel/metal/row.rb +48 -0
  13. data/lib/cequel/metal/row_specification.rb +37 -0
  14. data/lib/cequel/metal/statement.rb +30 -0
  15. data/lib/cequel/metal/updater.rb +65 -0
  16. data/lib/cequel/metal/writer.rb +73 -0
  17. data/lib/cequel/model.rb +12 -84
  18. data/lib/cequel/model/association_collection.rb +23 -0
  19. data/lib/cequel/model/associations.rb +84 -80
  20. data/lib/cequel/model/base.rb +74 -0
  21. data/lib/cequel/model/belongs_to_association.rb +31 -0
  22. data/lib/cequel/model/callbacks.rb +14 -10
  23. data/lib/cequel/model/collection.rb +255 -0
  24. data/lib/cequel/model/errors.rb +6 -6
  25. data/lib/cequel/model/has_many_association.rb +26 -0
  26. data/lib/cequel/model/mass_assignment.rb +31 -0
  27. data/lib/cequel/model/persistence.rb +119 -115
  28. data/lib/cequel/model/properties.rb +89 -87
  29. data/lib/cequel/model/railtie.rb +21 -14
  30. data/lib/cequel/model/record_set.rb +285 -0
  31. data/lib/cequel/model/schema.rb +33 -0
  32. data/lib/cequel/model/scoped.rb +5 -48
  33. data/lib/cequel/model/validations.rb +18 -18
  34. data/lib/cequel/schema.rb +15 -0
  35. data/lib/cequel/schema/column.rb +135 -0
  36. data/lib/cequel/schema/create_table_dsl.rb +56 -0
  37. data/lib/cequel/schema/keyspace.rb +50 -0
  38. data/lib/cequel/schema/table.rb +120 -0
  39. data/lib/cequel/schema/table_property.rb +67 -0
  40. data/lib/cequel/schema/table_reader.rb +139 -0
  41. data/lib/cequel/schema/table_synchronizer.rb +114 -0
  42. data/lib/cequel/schema/table_updater.rb +83 -0
  43. data/lib/cequel/schema/table_writer.rb +80 -0
  44. data/lib/cequel/schema/update_table_dsl.rb +60 -0
  45. data/lib/cequel/type.rb +232 -0
  46. data/lib/cequel/version.rb +1 -1
  47. data/spec/environment.rb +5 -1
  48. data/spec/examples/metal/data_set_spec.rb +608 -0
  49. data/spec/examples/model/associations_spec.rb +84 -74
  50. data/spec/examples/model/callbacks_spec.rb +66 -59
  51. data/spec/examples/model/list_spec.rb +393 -0
  52. data/spec/examples/model/map_spec.rb +229 -0
  53. data/spec/examples/model/mass_assignment_spec.rb +55 -0
  54. data/spec/examples/model/naming_spec.rb +11 -4
  55. data/spec/examples/model/persistence_spec.rb +140 -150
  56. data/spec/examples/model/properties_spec.rb +122 -75
  57. data/spec/examples/model/record_set_spec.rb +285 -0
  58. data/spec/examples/model/schema_spec.rb +44 -0
  59. data/spec/examples/model/serialization_spec.rb +20 -14
  60. data/spec/examples/model/set_spec.rb +133 -0
  61. data/spec/examples/model/spec_helper.rb +0 -10
  62. data/spec/examples/model/validations_spec.rb +51 -38
  63. data/spec/examples/schema/table_reader_spec.rb +328 -0
  64. data/spec/examples/schema/table_synchronizer_spec.rb +172 -0
  65. data/spec/examples/schema/table_updater_spec.rb +157 -0
  66. data/spec/examples/schema/table_writer_spec.rb +225 -0
  67. data/spec/examples/spec_helper.rb +29 -0
  68. data/spec/examples/type_spec.rb +204 -0
  69. data/spec/support/helpers.rb +67 -8
  70. metadata +121 -152
  71. data/lib/cequel/batch.rb +0 -58
  72. data/lib/cequel/cql_row_specification.rb +0 -22
  73. data/lib/cequel/data_set.rb +0 -371
  74. data/lib/cequel/keyspace.rb +0 -205
  75. data/lib/cequel/model/class_internals.rb +0 -49
  76. data/lib/cequel/model/column.rb +0 -20
  77. data/lib/cequel/model/counter.rb +0 -35
  78. data/lib/cequel/model/dictionary.rb +0 -126
  79. data/lib/cequel/model/dirty.rb +0 -53
  80. data/lib/cequel/model/dynamic.rb +0 -31
  81. data/lib/cequel/model/inheritable.rb +0 -48
  82. data/lib/cequel/model/instance_internals.rb +0 -23
  83. data/lib/cequel/model/local_association.rb +0 -42
  84. data/lib/cequel/model/magic.rb +0 -79
  85. data/lib/cequel/model/mass_assignment_security.rb +0 -21
  86. data/lib/cequel/model/naming.rb +0 -17
  87. data/lib/cequel/model/observer.rb +0 -42
  88. data/lib/cequel/model/readable_dictionary.rb +0 -182
  89. data/lib/cequel/model/remote_association.rb +0 -40
  90. data/lib/cequel/model/scope.rb +0 -362
  91. data/lib/cequel/model/subclass_internals.rb +0 -45
  92. data/lib/cequel/model/timestamps.rb +0 -52
  93. data/lib/cequel/model/translation.rb +0 -17
  94. data/lib/cequel/row_specification.rb +0 -63
  95. data/lib/cequel/statement.rb +0 -23
  96. data/spec/examples/data_set_spec.rb +0 -444
  97. data/spec/examples/keyspace_spec.rb +0 -84
  98. data/spec/examples/model/counter_spec.rb +0 -94
  99. data/spec/examples/model/dictionary_spec.rb +0 -301
  100. data/spec/examples/model/dirty_spec.rb +0 -39
  101. data/spec/examples/model/dynamic_spec.rb +0 -41
  102. data/spec/examples/model/inheritable_spec.rb +0 -45
  103. data/spec/examples/model/magic_spec.rb +0 -199
  104. data/spec/examples/model/mass_assignment_security_spec.rb +0 -13
  105. data/spec/examples/model/observer_spec.rb +0 -86
  106. data/spec/examples/model/scope_spec.rb +0 -677
  107. data/spec/examples/model/timestamps_spec.rb +0 -52
  108. data/spec/examples/model/translation_spec.rb +0 -23
@@ -1,17 +0,0 @@
1
- module Cequel
2
-
3
- module Model
4
-
5
- module Translation
6
-
7
- extend ActiveModel::Translation
8
-
9
- def i18n_scope
10
- 'cequel'
11
- end
12
-
13
- end
14
-
15
- end
16
-
17
- end
@@ -1,63 +0,0 @@
1
- module Cequel
2
-
3
- #
4
- # @private
5
- #
6
- class RowSpecification
7
-
8
- def self.build(column_values)
9
- column_values.map { |column, value| new(column, value) }
10
- end
11
-
12
- attr_reader :column, :value
13
-
14
- def initialize(column, value)
15
- @column, @value = column, value
16
- end
17
-
18
- def cql
19
- case @value
20
- when DataSet
21
- subquery_cql
22
- when Array
23
- if @value.length == 1
24
- ["? = ?", @column, @value.first]
25
- else
26
- [
27
- "? IN (?)",
28
- @column, @value
29
- ]
30
- end
31
- else
32
- ["? = ?", @column, @value]
33
- end
34
- end
35
-
36
- private
37
-
38
- def subquery_cql
39
- values = values_from_subquery
40
- case values.length
41
- when 0
42
- raise EmptySubquery,
43
- "Unable to generate CQL row specification: subquery (#{@value.cql}) returned no results."
44
- when 1
45
- RowSpecification.new(@column, values.first).cql
46
- else
47
- RowSpecification.new(@column, values).cql
48
- end
49
- end
50
-
51
- def values_from_subquery
52
- results = @value.map do |row|
53
- if row.length > 1
54
- raise ArgumentError,
55
- "Subqueries must return a single row per column"
56
- end
57
- row.values.first
58
- end
59
- end
60
-
61
- end
62
-
63
- end
@@ -1,23 +0,0 @@
1
- module Cequel
2
- class Statement
3
- attr_reader :bind_vars
4
-
5
- def initialize
6
- @cql, @bind_vars = StringIO.new, []
7
- end
8
-
9
- def cql
10
- @cql.string
11
- end
12
-
13
- def append(cql, *bind_vars)
14
- @cql << cql
15
- @bind_vars.concat(bind_vars)
16
- self
17
- end
18
-
19
- def args
20
- [cql, *bind_vars]
21
- end
22
- end
23
- end
@@ -1,444 +0,0 @@
1
- require File.expand_path('../spec_helper', __FILE__)
2
-
3
- describe Cequel::DataSet do
4
- describe '#insert' do
5
- it 'should insert a row' do
6
- connection.should_receive(:execute).
7
- with "INSERT INTO posts (?) VALUES (?)", [:id, :title], [1, 'Fun times']
8
-
9
- cequel[:posts].insert(:id => 1, :title => 'Fun times')
10
- end
11
-
12
- it 'should include consistency argument' do
13
- connection.should_receive(:execute).
14
- with "INSERT INTO posts (?) VALUES (?) USING CONSISTENCY QUORUM", [:id, :title], [1, 'Fun times']
15
-
16
- cequel[:posts].insert(
17
- {:id => 1, :title => 'Fun times'},
18
- :consistency => :quorum
19
- )
20
- end
21
-
22
- it 'should respect with_consistency block' do
23
- connection.should_receive(:execute).
24
- with "INSERT INTO posts (?) VALUES (?) USING CONSISTENCY QUORUM", [:id, :title], [1, 'Fun times']
25
-
26
- cequel.with_consistency(:quorum) do
27
- cequel[:posts].insert(:id => 1, :title => 'Fun times')
28
- end
29
- end
30
-
31
- it 'should include ttl argument' do
32
- connection.should_receive(:execute).
33
- with "INSERT INTO posts (?) VALUES (?) USING TTL 600", [:id, :title], [1, 'Fun times']
34
-
35
- cequel[:posts].insert(
36
- {:id => 1, :title => 'Fun times'},
37
- :ttl => 10.minutes
38
- )
39
- end
40
-
41
- it 'should include timestamp argument' do
42
- time = Time.now - 10.minutes
43
- connection.should_receive(:execute).
44
- with "INSERT INTO posts (?) VALUES (?) USING TIMESTAMP #{time.to_i}", [:id, :title], [1, 'Fun times']
45
-
46
- cequel[:posts].insert(
47
- {:id => 1, :title => 'Fun times'},
48
- :timestamp => time
49
- )
50
- end
51
-
52
- it 'should include multiple arguments joined by AND' do
53
- time = Time.now - 10.minutes
54
- connection.should_receive(:execute).
55
- with "INSERT INTO posts (?) VALUES (?) USING CONSISTENCY QUORUM AND TTL 600 AND TIMESTAMP #{time.to_i}",
56
- [:id, :title], [1, 'Fun times']
57
-
58
- cequel[:posts].insert(
59
- {:id => 1, :title => 'Fun times'},
60
- :consistency => :quorum,
61
- :ttl => 600,
62
- :timestamp => time
63
- )
64
- end
65
- end
66
-
67
- describe '#update' do
68
- it 'should send basic update statement' do
69
- connection.should_receive(:execute).
70
- with "UPDATE posts SET ? = ?, ? = ?", :title, 'Fun times', :body, 'Fun'
71
-
72
- cequel[:posts].update(:title => 'Fun times', :body => 'Fun')
73
- end
74
-
75
- it 'should send update statement with options' do
76
- time = Time.now - 10.minutes
77
-
78
- connection.should_receive(:execute).
79
- with "UPDATE posts USING CONSISTENCY QUORUM AND TTL 600 AND TIMESTAMP #{time.to_i} SET ? = ?, ? = ?", :title, 'Fun times', :body, 'Fun'
80
-
81
- cequel[:posts].update(
82
- {:title => 'Fun times', :body => 'Fun'},
83
- :consistency => :quorum, :ttl => 600, :timestamp => time
84
- )
85
- end
86
-
87
- it 'should respect default consistency' do
88
- connection.should_receive(:execute).
89
- with "UPDATE posts USING CONSISTENCY QUORUM SET ? = ?, ? = ?", :title, 'Fun times', :body, 'Fun'
90
-
91
- cequel.with_consistency(:quorum) do
92
- cequel[:posts].update(:title => 'Fun times', :body => 'Fun')
93
- end
94
- end
95
-
96
- it 'should send update statement scoped to current row specifications' do
97
- connection.should_receive(:execute).
98
- with "UPDATE posts SET ? = ? WHERE ? = ?", :title, 'Fun', :id, 4
99
-
100
- cequel[:posts].where(:id => 4).update(:title => 'Fun')
101
- end
102
-
103
- it 'should do nothing if row specification contains empty subquery' do
104
- connection.stub(:execute).with("SELECT ? FROM posts", [:blog_id]).
105
- and_return result_stub
106
-
107
- expect do
108
- cequel[:blogs].where(:id => cequel[:posts].select(:blog_id)).
109
- update(:title => 'Fun')
110
- end.to_not raise_error
111
- end
112
- end
113
-
114
- describe '#increment' do
115
- it 'should increment counter columns' do
116
- connection.should_receive(:execute).with(
117
- 'UPDATE comment_counts SET ? = ? + ?, ? = ? + ? WHERE ? = ?',
118
- 'somepost', 'somepost', 1,
119
- 'anotherpost', 'anotherpost', 2,
120
- 'blog_id', 'myblog'
121
- )
122
- cequel[:comment_counts].where('blog_id' => 'myblog').
123
- increment('somepost' => 1, 'anotherpost' => 2)
124
- end
125
- end
126
-
127
- describe '#decrement' do
128
- it 'should decrement counter columns' do
129
- connection.should_receive(:execute).with(
130
- 'UPDATE comment_counts SET ? = ? - ?, ? = ? - ? WHERE ? = ?',
131
- 'somepost', 'somepost', 1,
132
- 'anotherpost', 'anotherpost', 2,
133
- 'blog_id', 'myblog'
134
- )
135
- cequel[:comment_counts].where('blog_id' => 'myblog').
136
- decrement('somepost' => 1, 'anotherpost' => 2)
137
- end
138
- end
139
-
140
- describe '#delete' do
141
- it 'should send basic delete statement' do
142
- connection.should_receive(:execute).
143
- with 'DELETE FROM posts'
144
-
145
- cequel[:posts].delete
146
- end
147
-
148
- it 'should send delete statement for specified columns' do
149
- connection.should_receive(:execute).
150
- with 'DELETE ? FROM posts', [:title, :body]
151
-
152
- cequel[:posts].delete(:title, :body)
153
- end
154
-
155
- it 'should send delete statement with persistence options' do
156
- time = Time.now - 10.minutes
157
-
158
- connection.should_receive(:execute).
159
- with "DELETE ? FROM posts USING CONSISTENCY QUORUM AND TIMESTAMP #{time.to_i}", [:title, :body]
160
-
161
- cequel[:posts].delete(
162
- :title, :body,
163
- :consistency => :quorum, :timestamp => time
164
- )
165
- end
166
-
167
- it 'should respect default consistency' do
168
- connection.should_receive(:execute).
169
- with "DELETE ? FROM posts USING CONSISTENCY QUORUM", [:title, :body]
170
-
171
- cequel.with_consistency(:quorum) do
172
- cequel[:posts].delete(:title, :body)
173
- end
174
- end
175
-
176
- it 'should send delete statement with scoped row specifications' do
177
- connection.should_receive(:execute).
178
- with "DELETE FROM posts WHERE ? = ?", :id, 4
179
-
180
- cequel[:posts].where(:id => 4).delete
181
- end
182
-
183
- it 'should not do anything if scoped to empty subquery' do
184
- connection.stub(:execute).with("SELECT ? FROM posts", [:blog_id]).
185
- and_return result_stub
186
-
187
- expect do
188
- cequel[:blogs].where(:id => cequel[:posts].select(:blog_id)).
189
- delete
190
- end.to_not raise_error
191
- end
192
- end
193
-
194
- describe '#truncate' do
195
- it 'should send a TRUNCATE statement' do
196
- connection.should_receive(:execute).with("TRUNCATE posts")
197
-
198
- cequel[:posts].truncate
199
- end
200
- end
201
-
202
- describe '#cql' do
203
- it 'should generate select statement with all columns' do
204
- cequel[:posts].cql.should == ['SELECT * FROM posts']
205
- end
206
- end
207
-
208
- describe '#select' do
209
- it 'should generate select statement with given columns' do
210
- cequel[:posts].select(:id, :title).cql.
211
- should == ['SELECT ? FROM posts', [:id, :title]]
212
- end
213
-
214
- it 'should accept array argument' do
215
- cequel[:posts].select([:id, :title]).cql.
216
- should == ['SELECT ? FROM posts', [:id, :title]]
217
- end
218
-
219
- it 'should combine multiple selects' do
220
- cequel[:posts].select(:id).select(:title).cql.
221
- should == ['SELECT ? FROM posts', [:id, :title]]
222
- end
223
-
224
- it 'should accept :first option' do
225
- cequel[:posts].select(:first => 100).cql.
226
- should == ['SELECT FIRST 100 * FROM posts']
227
- end
228
-
229
- it 'should accept :last option' do
230
- cequel[:posts].select(:last => 100).cql.
231
- should == ['SELECT FIRST 100 REVERSED * FROM posts']
232
- end
233
-
234
- it 'should accept column range' do
235
- cequel[:posts].select(1..10).cql.
236
- should == ['SELECT ?..? FROM posts', 1, 10]
237
- end
238
-
239
- it 'should accept :from option' do
240
- cequel[:posts].select(:from => 10).cql.
241
- should == ['SELECT ?..? FROM posts', 10, '']
242
- end
243
-
244
- it 'should combine range and column limit options' do
245
- cequel[:posts].select(:first => 100, :from => 10).cql.
246
- should == ['SELECT FIRST 100 ?..? FROM posts', 10, '']
247
- end
248
-
249
- it 'should chain select options' do
250
- cequel[:posts].select(:first => 100).select(:from => 10).cql.
251
- should == ['SELECT FIRST 100 ?..? FROM posts', 10, '']
252
- end
253
- end
254
-
255
- describe '#select!' do
256
- it 'should generate select statement with given columns' do
257
- cequel[:posts].select(:id, :title).select!(:published).cql.
258
- should == ['SELECT ? FROM posts', [:published]]
259
- end
260
- end
261
-
262
- describe '#where' do
263
- it 'should build WHERE statement from hash' do
264
- cequel[:posts].where(:title => 'Hey').cql.
265
- should == ["SELECT * FROM posts WHERE ? = ?", :title, 'Hey']
266
- end
267
-
268
- it 'should build WHERE statement from multi-element hash' do
269
- cequel[:posts].where(:title => 'Hey', :body => 'Guy').cql.
270
- should == ["SELECT * FROM posts WHERE ? = ? AND ? = ?", :title, 'Hey', :body, 'Guy']
271
- end
272
-
273
- it 'should build WHERE statement with IN' do
274
- cequel[:posts].where(:id => [1, 2, 3, 4]).cql.
275
- should == ['SELECT * FROM posts WHERE ? IN (?)', :id, [1, 2, 3, 4]]
276
- end
277
-
278
- it 'should use = if provided one-element array' do
279
- cequel[:posts].where(:id => [1]).cql.
280
- should == ['SELECT * FROM posts WHERE ? = ?', :id, 1]
281
- end
282
-
283
- it 'should build WHERE statement from CQL string' do
284
- cequel[:posts].where("title = ?", 'Hey').cql.
285
- should == ["SELECT * FROM posts WHERE title = ?", 'Hey']
286
- end
287
-
288
- it 'should build WHERE statement from CQL string with bind variables' do
289
- cequel[:posts].where("title = ?", 'Hey').cql.
290
- should == ["SELECT * FROM posts WHERE title = ?", 'Hey']
291
- end
292
-
293
- it 'should aggregate multiple WHERE statements' do
294
- cequel[:posts].where(:title => 'Hey').where('body = ?', 'Sup').cql.
295
- should == ["SELECT * FROM posts WHERE ? = ? AND body = ?", :title, 'Hey', 'Sup']
296
- end
297
-
298
- it 'should take a data set as a condition and perform an IN statement' do
299
- connection.stub(:execute).
300
- with("SELECT ? FROM posts WHERE ? = ?", [:blog_id], :title, 'Blog').
301
- and_return result_stub(
302
- {:blog_id => 1},
303
- {:blog_id => 3}
304
- )
305
-
306
- cequel[:blogs].where(
307
- :id => cequel[:posts].select(:blog_id).where(:title => 'Blog')
308
- ).cql.
309
- should == ['SELECT * FROM blogs WHERE ? IN (?)', :id, [1, 3]]
310
- end
311
-
312
- it 'should raise EmptySubquery if inner data set has no results' do
313
- connection.stub(:execute).
314
- with("SELECT ? FROM posts WHERE ? = ?", [:blog_id], :title, 'Blog').
315
- and_return result_stub
316
-
317
- expect do
318
- cequel[:blogs].where(
319
- :id => cequel[:posts].select(:blog_id).where(:title => 'Blog')
320
- ).cql
321
- end.to raise_error(Cequel::EmptySubquery)
322
- end
323
-
324
- end
325
-
326
- describe '#where!' do
327
- it 'should override chained conditions' do
328
- cequel[:posts].where(:title => 'Hey').where!(:title => 'Cequel').cql.
329
- should == ["SELECT * FROM posts WHERE ? = ?", :title, 'Cequel']
330
- end
331
- end
332
-
333
- describe '#consistency' do
334
- it 'should add USING CONSISTENCY to select' do
335
- cequel[:posts].consistency(:quorum).cql.
336
- should == ["SELECT * FROM posts USING CONSISTENCY QUORUM"]
337
- end
338
- end
339
-
340
- describe 'in with_consistency block' do
341
- it 'should use default consistency' do
342
- cequel.with_consistency(:quorum) do
343
- cequel[:posts].cql.
344
- should == ["SELECT * FROM posts USING CONSISTENCY QUORUM"]
345
- end
346
- end
347
- end
348
-
349
- describe '#limit' do
350
- it 'should add LIMIT' do
351
- cequel[:posts].limit(2).cql.
352
- should == ['SELECT * FROM posts LIMIT 2']
353
- end
354
- end
355
-
356
- describe 'chaining scopes' do
357
- it 'should aggregate all scope options' do
358
- cequel[:posts].
359
- select(:id, :title).
360
- consistency(:quorum).
361
- where(:title => 'Hey').
362
- limit(3).cql.
363
- should == ["SELECT ? FROM posts USING CONSISTENCY QUORUM WHERE ? = ? LIMIT 3", [:id, :title], :title, 'Hey']
364
- end
365
- end
366
-
367
- describe 'result enumeration' do
368
- it 'should enumerate over results' do
369
- connection.stub(:execute).with("SELECT * FROM posts").
370
- and_return result_stub('id' => 1, 'title' => 'Hey')
371
-
372
- cequel[:posts].to_a.should == [{'id' => 1, 'title' => 'Hey'}]
373
- end
374
-
375
- it 'should provide results with indifferent access' do
376
- connection.stub(:execute).with("SELECT * FROM posts").
377
- and_return result_stub('id' => 1, 'title' => 'Hey')
378
-
379
- cequel[:posts].to_a.first[:id].should == 1
380
- end
381
-
382
- it 'should not run query if no block given to #each' do
383
- expect { cequel[:posts].each }.to_not raise_error
384
- end
385
-
386
- it 'should return Enumerator if no block given to #each' do
387
- connection.stub(:execute).with("SELECT * FROM posts").
388
- and_return result_stub('id' => 1, 'title' => 'Hey')
389
-
390
- cequel[:posts].each.each_with_index.map { |row, i| [row[:id], i] }.
391
- should == [[1, 0]]
392
- end
393
-
394
- it 'should return no results if subquery is empty' do
395
- connection.stub(:execute).with("SELECT ? FROM posts", [:blog_id]).
396
- and_return result_stub
397
-
398
- cequel[:blogs].where(:id => cequel[:posts].select(:blog_id)).to_a.
399
- should == []
400
- end
401
- end
402
-
403
- describe '#first' do
404
- it 'should run a query with LIMIT 1 and return first row' do
405
- connection.stub(:execute).with("SELECT * FROM posts LIMIT 1").
406
- and_return result_stub('id' => 1, 'title' => 'Hey')
407
-
408
- cequel[:posts].first.should == {'id' => 1, 'title' => 'Hey'}
409
- end
410
-
411
- it 'should return nil if subquery returns empty results' do
412
- connection.stub(:execute).with("SELECT ? FROM posts", [:blog_id]).
413
- and_return result_stub
414
-
415
- cequel[:blogs].where(:id => cequel[:posts].select(:blog_id)).first.
416
- should be_nil
417
- end
418
- end
419
-
420
- describe '#count' do
421
- it 'should run a count query and return count' do
422
- connection.stub(:execute).with("SELECT COUNT(*) FROM posts").
423
- and_return result_stub('count' => 4)
424
-
425
- cequel[:posts].count.should == 4
426
- end
427
-
428
- it 'should return 0 if subquery returns no results' do
429
- connection.stub(:execute).with("SELECT ? FROM posts", [:blog_id]).
430
- and_return result_stub
431
-
432
- cequel[:blogs].where(:id => cequel[:posts].select(:blog_id)).count.
433
- should == 0
434
- end
435
-
436
- it 'should use limit if specified' do
437
- connection.stub(:execute).with("SELECT COUNT(*) FROM posts LIMIT 100000").
438
- and_return result_stub('count' => 4)
439
-
440
- cequel[:posts].limit(100_000).count.should == 4
441
- end
442
- end
443
-
444
- end