cequel 0.5.6 → 1.0.0.pre.1

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 (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