veritas-do-adapter 0.0.5
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.
- data/.document +5 -0
- data/.gemtest +0 -0
- data/.rvmrc +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +46 -0
- data/Guardfile +18 -0
- data/LICENSE +20 -0
- data/README.md +21 -0
- data/Rakefile +27 -0
- data/TODO +0 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/roodi.yml +16 -0
- data/config/site.reek +96 -0
- data/config/yardstick.yml +2 -0
- data/lib/veritas/adapter/data_objects/statement.rb +107 -0
- data/lib/veritas/adapter/data_objects/version.rb +9 -0
- data/lib/veritas/adapter/data_objects.rb +55 -0
- data/lib/veritas/relation/gateway.rb +363 -0
- data/lib/veritas-do-adapter.rb +4 -0
- data/spec/rcov.opts +6 -0
- data/spec/shared/binary_relation_method_behaviour.rb +51 -0
- data/spec/shared/command_method_behavior.rb +7 -0
- data/spec/shared/each_method_behaviour.rb +15 -0
- data/spec/shared/idempotent_method_behaviour.rb +7 -0
- data/spec/shared/unary_relation_method_behaviour.rb +21 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/unit/veritas/adapter/data_objects/class_methods/new_spec.rb +15 -0
- data/spec/unit/veritas/adapter/data_objects/read_spec.rb +70 -0
- data/spec/unit/veritas/adapter/data_objects/statement/class_methods/new_spec.rb +28 -0
- data/spec/unit/veritas/adapter/data_objects/statement/each_spec.rb +63 -0
- data/spec/unit/veritas/adapter/data_objects/statement/to_s_spec.rb +53 -0
- data/spec/unit/veritas/relation/gateway/class_methods/new_spec.rb +16 -0
- data/spec/unit/veritas/relation/gateway/difference_spec.rb +17 -0
- data/spec/unit/veritas/relation/gateway/drop_spec.rb +21 -0
- data/spec/unit/veritas/relation/gateway/each_spec.rb +84 -0
- data/spec/unit/veritas/relation/gateway/extend_spec.rb +27 -0
- data/spec/unit/veritas/relation/gateway/intersect_spec.rb +17 -0
- data/spec/unit/veritas/relation/gateway/join_spec.rb +44 -0
- data/spec/unit/veritas/relation/gateway/materialize_spec.rb +27 -0
- data/spec/unit/veritas/relation/gateway/optimize_spec.rb +23 -0
- data/spec/unit/veritas/relation/gateway/product_spec.rb +17 -0
- data/spec/unit/veritas/relation/gateway/project_spec.rb +21 -0
- data/spec/unit/veritas/relation/gateway/remove_spec.rb +21 -0
- data/spec/unit/veritas/relation/gateway/rename_spec.rb +21 -0
- data/spec/unit/veritas/relation/gateway/respond_to_spec.rb +29 -0
- data/spec/unit/veritas/relation/gateway/restrict_spec.rb +27 -0
- data/spec/unit/veritas/relation/gateway/reverse_spec.rb +21 -0
- data/spec/unit/veritas/relation/gateway/sort_by_spec.rb +27 -0
- data/spec/unit/veritas/relation/gateway/summarize_spec.rb +148 -0
- data/spec/unit/veritas/relation/gateway/take_spec.rb +21 -0
- data/spec/unit/veritas/relation/gateway/union_spec.rb +17 -0
- data/tasks/metrics/ci.rake +7 -0
- data/tasks/metrics/flay.rake +41 -0
- data/tasks/metrics/flog.rake +43 -0
- data/tasks/metrics/heckle.rake +209 -0
- data/tasks/metrics/metric_fu.rake +29 -0
- data/tasks/metrics/reek.rake +9 -0
- data/tasks/metrics/roodi.rake +15 -0
- data/tasks/metrics/yardstick.rake +23 -0
- data/tasks/spec.rake +39 -0
- data/tasks/yard.rake +9 -0
- data/veritas-do-adapter.gemspec +124 -0
- metadata +257 -0
@@ -0,0 +1,363 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Veritas
|
4
|
+
class Relation
|
5
|
+
|
6
|
+
# A relation backed by an adapter
|
7
|
+
class Gateway < Relation
|
8
|
+
|
9
|
+
DECORATED_CLASS = superclass
|
10
|
+
|
11
|
+
# remove methods so they can be proxied
|
12
|
+
undef_method *DECORATED_CLASS.public_instance_methods(false).map(&:to_s) - %w[ materialize ]
|
13
|
+
undef_method :project, :remove, :extend, :rename, :restrict, :sort_by, :reverse, :drop, :take
|
14
|
+
|
15
|
+
# The adapter the gateway will use to fetch results
|
16
|
+
#
|
17
|
+
# @return [Adapter::DataObjects]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
attr_reader :adapter
|
21
|
+
protected :adapter
|
22
|
+
|
23
|
+
# The relation the gateway will use to generate SQL
|
24
|
+
#
|
25
|
+
# @return [Relation]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
attr_reader :relation
|
29
|
+
protected :relation
|
30
|
+
|
31
|
+
# Initialize a Gateway
|
32
|
+
#
|
33
|
+
# @param [Adapter::DataObjects] adapter
|
34
|
+
#
|
35
|
+
# @param [Relation] relation
|
36
|
+
#
|
37
|
+
# @return [undefined]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
def initialize(adapter, relation)
|
41
|
+
@adapter = adapter
|
42
|
+
@relation = relation
|
43
|
+
end
|
44
|
+
|
45
|
+
# Iterate over each row in the results
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# gateway = Gateway.new(adapter, relation)
|
49
|
+
# gateway.each { |tuple| ... }
|
50
|
+
#
|
51
|
+
# @yield [tuple]
|
52
|
+
#
|
53
|
+
# @yieldparam [Tuple] tuple
|
54
|
+
# each tuple in the results
|
55
|
+
#
|
56
|
+
# @return [self]
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
def each
|
60
|
+
return to_enum unless block_given?
|
61
|
+
tuples.each { |tuple| yield tuple }
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return a relation that is the join of two relations
|
66
|
+
#
|
67
|
+
# @example natural join
|
68
|
+
# join = relation.join(other)
|
69
|
+
#
|
70
|
+
# @example theta-join using a block
|
71
|
+
# join = relation.join(other) { |r| r.a.gte(r.b) }
|
72
|
+
#
|
73
|
+
# @param [Relation] other
|
74
|
+
# the other relation to join
|
75
|
+
#
|
76
|
+
# @yield [relation]
|
77
|
+
# optional block to restrict the tuples with
|
78
|
+
#
|
79
|
+
# @yieldparam [Relation] relation
|
80
|
+
# the context to evaluate the restriction with
|
81
|
+
#
|
82
|
+
# @yieldreturn [Function, #call]
|
83
|
+
# predicate to restrict the tuples with
|
84
|
+
#
|
85
|
+
# @return [Gateway]
|
86
|
+
# return a gateway if the adapters are equal
|
87
|
+
# @return [Algebra::Join]
|
88
|
+
# return a normal join when the adapters are not equal
|
89
|
+
# @return [Algebra::Restriction]
|
90
|
+
# return a normal restriction when the adapters are not equal
|
91
|
+
# for a theta-join
|
92
|
+
#
|
93
|
+
# @api public
|
94
|
+
def join(other)
|
95
|
+
if block_given?
|
96
|
+
super
|
97
|
+
else
|
98
|
+
binary_operation(__method__, other, Algebra::Join)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Return a relation that is the cartesian product of two relations
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# product = gateway.product(other)
|
106
|
+
#
|
107
|
+
# @param [Relation] other
|
108
|
+
# the other relation to find the product with
|
109
|
+
#
|
110
|
+
# @return [Gateway]
|
111
|
+
# return a gateway if the adapters are equal
|
112
|
+
# @return [Algebra::Product]
|
113
|
+
# return a normal product when the adapters are not equal
|
114
|
+
#
|
115
|
+
# @api public
|
116
|
+
def product(other)
|
117
|
+
binary_operation(__method__, other, Algebra::Product)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return the union between relations
|
121
|
+
#
|
122
|
+
# @example
|
123
|
+
# union = gateway.union(other)
|
124
|
+
#
|
125
|
+
# @param [Relation] other
|
126
|
+
# the other relation to find the union with
|
127
|
+
#
|
128
|
+
# @return [Gateway]
|
129
|
+
# return a gateway if the adapters are equal
|
130
|
+
# @return [Algebra::Union]
|
131
|
+
# return a normal union when the adapters are not equal
|
132
|
+
#
|
133
|
+
# @api public
|
134
|
+
def union(other)
|
135
|
+
binary_operation(__method__, other, Algebra::Union)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Return the intersection between relations
|
139
|
+
#
|
140
|
+
# @example
|
141
|
+
# intersect = gateway.intersect(other)
|
142
|
+
#
|
143
|
+
# @param [Relation] other
|
144
|
+
# the other relation to find the intersect with
|
145
|
+
#
|
146
|
+
# @return [Gateway]
|
147
|
+
# return a gateway if the adapters are equal
|
148
|
+
# @return [Algebra::Intersection]
|
149
|
+
# return a normal intersection when the adapters are not equal
|
150
|
+
#
|
151
|
+
# @api public
|
152
|
+
def intersect(other)
|
153
|
+
binary_operation(__method__, other, Algebra::Intersection)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Return the diferrence between relations
|
157
|
+
#
|
158
|
+
# @example
|
159
|
+
# difference = gateway.difference(other)
|
160
|
+
#
|
161
|
+
# @param [Relation] other
|
162
|
+
# the other relation to find the difference with
|
163
|
+
#
|
164
|
+
# @return [Gateway]
|
165
|
+
# return a gateway if the adapters are equal
|
166
|
+
# @return [Algebra::Difference]
|
167
|
+
# return a normal dfference when the adapters are not equal
|
168
|
+
#
|
169
|
+
# @api public
|
170
|
+
def difference(other)
|
171
|
+
binary_operation(__method__, other, Algebra::Difference)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Return a summarized relation
|
175
|
+
#
|
176
|
+
# @example with no arguments
|
177
|
+
# summarization = gateway.summarize do |context|
|
178
|
+
# context.add(:count, context[:id].count)
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# @example with a relation
|
182
|
+
# summarization = gateway.summarize(relation) do |context|
|
183
|
+
# context.add(:count, context[:id].count)
|
184
|
+
# end
|
185
|
+
#
|
186
|
+
# @example with a header
|
187
|
+
# summarization = gateway.summarize([ :name ]) do |context|
|
188
|
+
# context.add(:count, context[:id].count)
|
189
|
+
# end
|
190
|
+
#
|
191
|
+
# @example with another gateway
|
192
|
+
# summarization = gateway.summarize(other_gateway) do |context|
|
193
|
+
# context.add(:count, context[:id].count)
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# @param [Gateway, Relation, Header, #to_ary] summarize_with
|
197
|
+
#
|
198
|
+
# @yield [function]
|
199
|
+
# Evaluate a summarization function
|
200
|
+
#
|
201
|
+
# @yieldparam [Evaluator::Context] context
|
202
|
+
# the context to evaluate the function within
|
203
|
+
#
|
204
|
+
# @return [Gateway]
|
205
|
+
# return a gateway if the adapters are equal, or there is no adapter
|
206
|
+
# @return [Algebra::Summarization]
|
207
|
+
# return a normal summarization when the adapters are not equal
|
208
|
+
#
|
209
|
+
# @api public
|
210
|
+
def summarize(summarize_with = TABLE_DEE, &block)
|
211
|
+
if summarize_merge?(summarize_with)
|
212
|
+
summarize_merge(summarize_with, &block)
|
213
|
+
else
|
214
|
+
summarize_split(summarize_with, &block)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Test if the method is supported on this object
|
219
|
+
#
|
220
|
+
# @param [Symbol] method
|
221
|
+
#
|
222
|
+
# @return [Boolean]
|
223
|
+
#
|
224
|
+
# @api private
|
225
|
+
def respond_to?(method, *)
|
226
|
+
super || forwardable?(method)
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# Proxy the message to the relation
|
232
|
+
#
|
233
|
+
# @param [Symbol] method
|
234
|
+
#
|
235
|
+
# @param [Array] *args
|
236
|
+
#
|
237
|
+
# @return [self]
|
238
|
+
# return self for all command methods
|
239
|
+
# @return [Object]
|
240
|
+
# return response from all query methods
|
241
|
+
#
|
242
|
+
# @api private
|
243
|
+
def method_missing(method, *args, &block)
|
244
|
+
forwardable?(method) ? forward(method, *args, &block) : super
|
245
|
+
end
|
246
|
+
|
247
|
+
# Test if the method can be forwarded to the relation
|
248
|
+
#
|
249
|
+
# @param [Symbol] method
|
250
|
+
#
|
251
|
+
# @return [Boolean]
|
252
|
+
#
|
253
|
+
# @api private
|
254
|
+
def forwardable?(method)
|
255
|
+
relation.respond_to?(method)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Forward the message to the relation
|
259
|
+
#
|
260
|
+
# @param [Array] *args
|
261
|
+
#
|
262
|
+
# @return [self]
|
263
|
+
# return self for all command methods
|
264
|
+
# @return [Object]
|
265
|
+
# return response from all query methods
|
266
|
+
#
|
267
|
+
# @api private
|
268
|
+
def forward(*args, &block)
|
269
|
+
relation = self.relation
|
270
|
+
response = relation.public_send(*args, &block)
|
271
|
+
if response.equal?(relation)
|
272
|
+
self
|
273
|
+
elsif response.kind_of?(DECORATED_CLASS)
|
274
|
+
self.class.new(adapter, response)
|
275
|
+
else
|
276
|
+
response
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# Return a list of tuples to iterate over
|
281
|
+
#
|
282
|
+
# @return [#each]
|
283
|
+
#
|
284
|
+
# @api private
|
285
|
+
def tuples
|
286
|
+
relation = self.relation
|
287
|
+
if materialized?
|
288
|
+
relation
|
289
|
+
else
|
290
|
+
DECORATED_CLASS.new(header, adapter.read(relation))
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Return a binary relation
|
295
|
+
#
|
296
|
+
# @param [Relation] other
|
297
|
+
#
|
298
|
+
# @return [Gateway]
|
299
|
+
# return a gateway if the adapters are equal
|
300
|
+
# @return [Relation]
|
301
|
+
# return a binary relation when the adapters are not equal
|
302
|
+
#
|
303
|
+
# @api private
|
304
|
+
def binary_operation(method, other, factory)
|
305
|
+
if same_adapter?(other)
|
306
|
+
forward(method, other.relation)
|
307
|
+
else
|
308
|
+
factory.new(self, other)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Test if the other object uses the same adapter
|
313
|
+
#
|
314
|
+
# @param [Gateway, Relation] other
|
315
|
+
#
|
316
|
+
# @return [Boolean]
|
317
|
+
#
|
318
|
+
# @api private
|
319
|
+
def same_adapter?(other)
|
320
|
+
other.respond_to?(:adapter) && adapter.eql?(other.adapter)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Test if the summarize_with object can be merged into the summarization
|
324
|
+
#
|
325
|
+
# @param [Gateway, Relation, Header] summarize_with
|
326
|
+
#
|
327
|
+
# @return [Boolean]
|
328
|
+
#
|
329
|
+
# @api private
|
330
|
+
def summarize_merge?(summarize_with)
|
331
|
+
!summarize_with.respond_to?(:header) ||
|
332
|
+
summarize_with.equal?(TABLE_DEE) ||
|
333
|
+
same_adapter?(summarize_with)
|
334
|
+
end
|
335
|
+
|
336
|
+
# Merge the summarize_with into the summarization
|
337
|
+
#
|
338
|
+
# @param [Gateway, Relation, Header] summarize_with
|
339
|
+
#
|
340
|
+
# @return [Gateway]
|
341
|
+
#
|
342
|
+
# @api private
|
343
|
+
def summarize_merge(summarize_with, &block)
|
344
|
+
summarize_with = summarize_with.relation if summarize_with.respond_to?(:relation)
|
345
|
+
forward(:summarize, summarize_with, &block)
|
346
|
+
end
|
347
|
+
|
348
|
+
# Split the summarize_with into a separate relation, wrapped in a summarization
|
349
|
+
#
|
350
|
+
# @param [Gateway, Relation, Header] summarize_with
|
351
|
+
#
|
352
|
+
# @return [Algebra::Summarization]
|
353
|
+
#
|
354
|
+
# @api private
|
355
|
+
def summarize_split(summarize_with, &block)
|
356
|
+
# evaluate the gateway, then summarize with the provided relation
|
357
|
+
context = Evaluator::Context.new(header - summarize_with.header, &block)
|
358
|
+
Algebra::Summarization.new(self, summarize_with, context.functions)
|
359
|
+
end
|
360
|
+
|
361
|
+
end # class Gateway
|
362
|
+
end # class Relation
|
363
|
+
end # module Veritas
|
data/spec/rcov.opts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'a binary relation method' do
|
4
|
+
describe 'when other has the same adapter' do
|
5
|
+
let(:other_relation) { mock('Other Relation') }
|
6
|
+
let(:other) { described_class.new(adapter, other_relation) }
|
7
|
+
let(:gateway) { mock('Other Gateway') }
|
8
|
+
|
9
|
+
before do
|
10
|
+
relation.stub!(operation).and_return(gateway)
|
11
|
+
end
|
12
|
+
|
13
|
+
it { should equal(gateway) }
|
14
|
+
|
15
|
+
it 'passes the other relation to the binary operation' do
|
16
|
+
relation.should_receive(operation).with(other_relation)
|
17
|
+
subject
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'when other has a different adapter' do
|
22
|
+
let(:other_adapter) { mock('Other Adapter') }
|
23
|
+
let(:other) { described_class.new(other_adapter, stub) }
|
24
|
+
|
25
|
+
before do
|
26
|
+
factory.stub!(:new).and_return(binary_relation)
|
27
|
+
end
|
28
|
+
|
29
|
+
it { should equal(binary_relation) }
|
30
|
+
|
31
|
+
it 'initializes the binary operation with the gateways' do
|
32
|
+
factory.should_receive(:new).with(object, other)
|
33
|
+
subject
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'when other has no adapter' do
|
38
|
+
let(:other) { mock('Other Relation') }
|
39
|
+
|
40
|
+
before do
|
41
|
+
factory.stub!(:new).and_return(binary_relation)
|
42
|
+
end
|
43
|
+
|
44
|
+
it { should equal(binary_relation) }
|
45
|
+
|
46
|
+
it 'initializes the binary operation with the gateway and other relation' do
|
47
|
+
factory.should_receive(:new).with(object, other)
|
48
|
+
subject
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'an #each method' do
|
4
|
+
it_should_behave_like 'a command method'
|
5
|
+
|
6
|
+
context 'with no block' do
|
7
|
+
subject { object.each }
|
8
|
+
|
9
|
+
it { should be_instance_of(to_enum.class) }
|
10
|
+
|
11
|
+
it 'yields the expected values' do
|
12
|
+
subject.to_a.should eql(object.to_a)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'a unary relation method' do
|
4
|
+
let(:gateway) { mock('New Gateway') }
|
5
|
+
|
6
|
+
before do
|
7
|
+
described_class.stub!(:new).and_return(gateway)
|
8
|
+
end
|
9
|
+
|
10
|
+
it { should equal(gateway) }
|
11
|
+
|
12
|
+
it 'tests the response is a relation' do
|
13
|
+
response.should_receive(:kind_of?).with(Relation)
|
14
|
+
subject
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'initializes the new gateway with the adapter and response' do
|
18
|
+
described_class.should_receive(:new).with(adapter, response)
|
19
|
+
subject
|
20
|
+
end
|
21
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'backports'
|
5
|
+
require 'backports/basic_object'
|
6
|
+
require 'spec'
|
7
|
+
require 'spec/autorun'
|
8
|
+
require 'veritas'
|
9
|
+
require 'veritas-sql-generator'
|
10
|
+
|
11
|
+
include Veritas
|
12
|
+
|
13
|
+
# require spec support files and shared behavior
|
14
|
+
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
|
15
|
+
|
16
|
+
Spec::Runner.configure do |config|
|
17
|
+
|
18
|
+
# Record the original Attribute descendants
|
19
|
+
config.before do
|
20
|
+
@original_descendants = Attribute.descendants.dup
|
21
|
+
end
|
22
|
+
|
23
|
+
# Reset the Attribute descendants
|
24
|
+
config.after do
|
25
|
+
Attribute.descendants.replace(@original_descendants)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'veritas/adapter/data_objects'
|
5
|
+
|
6
|
+
describe Adapter::DataObjects, '.new' do
|
7
|
+
subject { object.new(uri) }
|
8
|
+
|
9
|
+
let(:uri) { stub }
|
10
|
+
let(:object) { described_class }
|
11
|
+
|
12
|
+
it { should be_instance_of(described_class) }
|
13
|
+
|
14
|
+
it { should be_frozen }
|
15
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'veritas/adapter/data_objects'
|
5
|
+
|
6
|
+
shared_examples_for 'it uses the data_objects driver' do
|
7
|
+
let(:connection) { mock('Connection', :close => nil) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
DataObjects::Connection.stub!(:new).and_return(connection)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'opens a connection' do
|
14
|
+
DataObjects::Connection.should_receive(:new).with(uri).and_return(connection)
|
15
|
+
subject
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'closes a connection' do
|
19
|
+
connection.should_receive(:close).with(no_args)
|
20
|
+
subject
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'does not close a connection if the constructor throws an exception' do
|
24
|
+
mock_exception = Class.new(Exception)
|
25
|
+
DataObjects::Connection.should_receive(:new).and_raise(mock_exception)
|
26
|
+
connection.should_not_receive(:close)
|
27
|
+
expect { subject }.to raise_error(mock_exception)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Adapter::DataObjects, '#read' do
|
32
|
+
let(:uri) { stub }
|
33
|
+
let(:object) { described_class.new(uri) }
|
34
|
+
let(:relation) { mock('Relation') }
|
35
|
+
let(:statement) { mock('Statement') }
|
36
|
+
let(:rows) { [ [ 1 ], [ 2 ], [ 3 ] ] }
|
37
|
+
let(:yields) { [] }
|
38
|
+
|
39
|
+
before do
|
40
|
+
expectation = statement.stub(:each)
|
41
|
+
rows.each { |row| expectation.and_yield(row) }
|
42
|
+
|
43
|
+
described_class::Statement.stub!(:new).and_return(statement)
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with a block' do
|
47
|
+
subject { object.read(relation) { |row| yields << row } }
|
48
|
+
|
49
|
+
|
50
|
+
it_should_behave_like 'it uses the data_objects driver'
|
51
|
+
it_should_behave_like 'a command method'
|
52
|
+
|
53
|
+
it 'yields each row' do
|
54
|
+
expect { subject }.to change { yields.dup }.
|
55
|
+
from([]).
|
56
|
+
to(rows)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'initializes a statement' do
|
60
|
+
described_class::Statement.should_receive(:new).with(connection, relation).and_return(statement)
|
61
|
+
subject
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'without a block' do
|
66
|
+
subject { object.read(relation) }
|
67
|
+
|
68
|
+
it { should be_instance_of(to_enum.class) }
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'veritas/adapter/data_objects/statement'
|
5
|
+
|
6
|
+
describe Adapter::DataObjects::Statement, '.new' do
|
7
|
+
let(:connection) { stub }
|
8
|
+
let(:relation) { stub }
|
9
|
+
let(:object) { described_class }
|
10
|
+
|
11
|
+
context 'without a visitor' do
|
12
|
+
subject { object.new(connection, relation) }
|
13
|
+
|
14
|
+
it { should be_instance_of(described_class) }
|
15
|
+
|
16
|
+
it { should be_frozen }
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with a visitor' do
|
20
|
+
subject { object.new(connection, relation, visitor) }
|
21
|
+
|
22
|
+
let(:visitor) { stub }
|
23
|
+
|
24
|
+
it { should be_instance_of(described_class) }
|
25
|
+
|
26
|
+
it { should be_frozen }
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'veritas/adapter/data_objects/statement'
|
5
|
+
|
6
|
+
describe Adapter::DataObjects::Statement, '#each' do
|
7
|
+
let(:reader) { mock('Reader', :next! => false).as_null_object }
|
8
|
+
let(:command) { mock('Command', :execute_reader => reader).as_null_object }
|
9
|
+
let(:connection) { mock('Connection', :create_command => command) }
|
10
|
+
let(:attribute) { stub }
|
11
|
+
let(:primitive) { stub }
|
12
|
+
let(:relation) { mock('Relation', :header => [ attribute ]) }
|
13
|
+
let(:generator) { mock('Generator').as_null_object }
|
14
|
+
let(:rows) { [ stub, stub ] }
|
15
|
+
let(:object) { described_class.new(connection, relation, generator) }
|
16
|
+
let(:yields) { [] }
|
17
|
+
|
18
|
+
before do
|
19
|
+
command.stub!(:dup => command, :freeze => command)
|
20
|
+
attribute.stub_chain(:class, :primitive).and_return(primitive)
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with no block' do
|
24
|
+
subject { object.each }
|
25
|
+
|
26
|
+
it { should be_instance_of(to_enum.class) }
|
27
|
+
|
28
|
+
it 'yields the expected attributes' do
|
29
|
+
subject.to_a.should eql(object.to_a)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a block' do
|
34
|
+
subject { object.each { |row| yields << row } }
|
35
|
+
|
36
|
+
before do
|
37
|
+
connection.should_receive(:create_command).with(object.to_s)
|
38
|
+
|
39
|
+
command.should_receive(:set_types).with([ primitive ]).ordered
|
40
|
+
command.should_receive(:execute_reader).with(no_args).ordered
|
41
|
+
|
42
|
+
rows.each do |values|
|
43
|
+
reader.should_receive(:next!).with(no_args).ordered.and_return(true)
|
44
|
+
reader.should_receive(:values).with(no_args).ordered.and_return(values)
|
45
|
+
end
|
46
|
+
|
47
|
+
reader.should_receive(:next!).with(no_args).ordered.and_return(false)
|
48
|
+
reader.should_receive(:close).with(no_args).ordered
|
49
|
+
end
|
50
|
+
|
51
|
+
before do
|
52
|
+
relation.should_receive(:header)
|
53
|
+
end
|
54
|
+
|
55
|
+
it_should_behave_like 'a command method'
|
56
|
+
|
57
|
+
it 'yields each row' do
|
58
|
+
expect { subject }.to change { yields.dup }.
|
59
|
+
from([]).
|
60
|
+
to(rows)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|