pod4 0.10.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.bugs/bugs +2 -1
  3. data/.bugs/details/b5368c7ef19065fc597b5692314da71772660963.txt +53 -0
  4. data/.hgtags +1 -0
  5. data/Gemfile +5 -5
  6. data/README.md +157 -46
  7. data/lib/pod4/basic_model.rb +9 -22
  8. data/lib/pod4/connection.rb +67 -0
  9. data/lib/pod4/connection_pool.rb +154 -0
  10. data/lib/pod4/errors.rb +20 -0
  11. data/lib/pod4/interface.rb +34 -12
  12. data/lib/pod4/model.rb +32 -27
  13. data/lib/pod4/nebulous_interface.rb +25 -30
  14. data/lib/pod4/null_interface.rb +22 -16
  15. data/lib/pod4/pg_interface.rb +84 -104
  16. data/lib/pod4/sequel_interface.rb +138 -82
  17. data/lib/pod4/tds_interface.rb +83 -70
  18. data/lib/pod4/tweaking.rb +105 -0
  19. data/lib/pod4/version.rb +1 -1
  20. data/md/breaking_changes.md +80 -0
  21. data/spec/common/basic_model_spec.rb +67 -70
  22. data/spec/common/connection_pool_parallelism_spec.rb +154 -0
  23. data/spec/common/connection_pool_spec.rb +246 -0
  24. data/spec/common/connection_spec.rb +129 -0
  25. data/spec/common/model_ai_missing_id_spec.rb +256 -0
  26. data/spec/common/model_plus_encrypting_spec.rb +16 -4
  27. data/spec/common/model_plus_tweaking_spec.rb +128 -0
  28. data/spec/common/model_plus_typecasting_spec.rb +10 -4
  29. data/spec/common/model_spec.rb +283 -363
  30. data/spec/common/nebulous_interface_spec.rb +159 -108
  31. data/spec/common/null_interface_spec.rb +88 -65
  32. data/spec/common/sequel_interface_pg_spec.rb +217 -161
  33. data/spec/common/shared_examples_for_interface.rb +50 -50
  34. data/spec/jruby/sequel_encrypting_jdbc_pg_spec.rb +1 -1
  35. data/spec/jruby/sequel_interface_jdbc_ms_spec.rb +3 -3
  36. data/spec/jruby/sequel_interface_jdbc_pg_spec.rb +3 -23
  37. data/spec/mri/pg_encrypting_spec.rb +1 -1
  38. data/spec/mri/pg_interface_spec.rb +311 -223
  39. data/spec/mri/sequel_encrypting_spec.rb +1 -1
  40. data/spec/mri/sequel_interface_spec.rb +177 -180
  41. data/spec/mri/tds_encrypting_spec.rb +1 -1
  42. data/spec/mri/tds_interface_spec.rb +296 -212
  43. data/tags +340 -174
  44. metadata +19 -11
  45. data/md/fixme.md +0 -3
  46. data/md/roadmap.md +0 -125
  47. data/md/typecasting.md +0 -80
  48. data/spec/common/model_new_validate_spec.rb +0 -204
@@ -63,7 +63,7 @@ describe "(writing encrypted data via tds_interface)" do
63
63
  include Pod4::Encrypting
64
64
 
65
65
  encrypted_columns :name, :ailment
66
- set_key "dflkasdgklajndgnalkghlgasdgasdghaalsdg"
66
+ set_key "dflkasdgklajndgn"
67
67
  set_iv_column :nonce
68
68
  end
69
69
  end
@@ -1,53 +1,14 @@
1
- require 'pod4/tds_interface'
1
+ require "pod4/tds_interface"
2
2
 
3
- require 'tiny_tds'
4
- require 'date'
3
+ require "tiny_tds"
4
+ require "date"
5
5
 
6
- require_relative '../common/shared_examples_for_interface'
7
- require_relative '../fixtures/database'
6
+ require_relative "../common/shared_examples_for_interface"
7
+ require_relative "../fixtures/database"
8
8
 
9
9
 
10
10
  describe "TdsInterface" do
11
11
 
12
- let(:tds_interface_class) do
13
- Class.new TdsInterface do
14
- set_db :pod4_test
15
- set_table :customer
16
- set_id_fld :id
17
- end
18
- end
19
-
20
- let(:schema_interface_class) do
21
- Class.new TdsInterface do
22
- set_db :pod4_test
23
- set_schema :public
24
- set_table :customer
25
- set_id_fld :id
26
- end
27
- end
28
-
29
- let(:bad_interface_class1) do
30
- Class.new TdsInterface do
31
- set_db :pod4_test
32
- set_table :customer
33
- end
34
- end
35
-
36
- let(:bad_interface_class2) do
37
- Class.new TdsInterface do
38
- set_db :pod4_test
39
- set_id_fld :id
40
- end
41
- end
42
-
43
- let(:prod_interface_class) do
44
- Class.new TdsInterface do
45
- set_db :pod4_test
46
- set_table :product
47
- set_id_fld :code
48
- end
49
- end
50
-
51
12
  def db_setup(connect)
52
13
  client = TinyTds::Client.new(connect)
53
14
  client.execute(%Q|use [pod4_test];|).do
@@ -82,7 +43,6 @@ describe "TdsInterface" do
82
43
  client.close if client
83
44
  end
84
45
 
85
-
86
46
  def fill_data(ifce)
87
47
  @data.each{|r| ifce.create(r) }
88
48
  end
@@ -91,185 +51,261 @@ describe "TdsInterface" do
91
51
  ifce.create( {code: "foo", name: "bar"} )
92
52
  end
93
53
 
54
+ def float_price(row)
55
+ row[:price] = row[:price].to_f
56
+ row
57
+ end
58
+
59
+ def list_contains(ifce, id)
60
+ ifce.list.find {|x| x[ifce.id_fld] == id }
61
+ end
62
+
63
+ let(:tds_interface_class) do
64
+ Class.new TdsInterface do
65
+ set_db :pod4_test
66
+ set_table :customer
67
+ set_id_fld :id
68
+ end
69
+ end
70
+
71
+ let(:schema_interface_class) do
72
+ Class.new TdsInterface do
73
+ set_db :pod4_test
74
+ set_schema :public
75
+ set_table :customer
76
+ set_id_fld :id, autoincrement: true
77
+ end
78
+ end
79
+
80
+ let(:bad_interface_class1) do
81
+ Class.new TdsInterface do
82
+ set_table :customer
83
+ end
84
+ end
85
+
86
+ let(:bad_interface_class2) do
87
+ Class.new TdsInterface do
88
+ set_db :pod4_test
89
+ set_id_fld :id
90
+ end
91
+ end
92
+
93
+ let(:prod_interface_class) do
94
+ Class.new TdsInterface do
95
+ set_db :pod4_test
96
+ set_table :product
97
+ set_id_fld :code, autoincrement: false
98
+ end
99
+ end
100
+
101
+ let(:interface) do
102
+ tds_interface_class.new(@connect_hash)
103
+ end
104
+
105
+ let(:prod_interface) do
106
+ prod_interface_class.new(@connect_hash)
107
+ end
94
108
 
95
109
  before(:all) do
96
110
  @connect_hash = DB[:tds]
97
111
  db_setup(@connect_hash)
98
112
 
99
113
  @data = []
100
- @data << { name: 'Barney',
114
+ @data << { name: "Barney",
101
115
  level: 1.23,
102
116
  day: Date.parse("2016-01-01"),
103
- timestamp: Time.parse('2015-01-01 12:11'),
117
+ timestamp: Time.parse("2015-01-01 12:11"),
104
118
  price: BigDecimal("1.24"),
105
119
  qty: BigDecimal("1.25") }
106
120
 
107
- @data << { name: 'Fred',
121
+ @data << { name: "Fred",
108
122
  level: 2.34,
109
123
  day: Date.parse("2016-02-02"),
110
- timestamp: Time.parse('2015-01-02 12:22'),
124
+ timestamp: Time.parse("2015-01-02 12:22"),
111
125
  price: BigDecimal("2.35"),
112
126
  qty: BigDecimal("2.36") }
113
127
 
114
- @data << { name: 'Betty',
128
+ @data << { name: "Betty",
115
129
  level: 3.45,
116
130
  day: Date.parse("2016-03-03"),
117
- timestamp: Time.parse('2015-01-03 12:33'),
131
+ timestamp: Time.parse("2015-01-03 12:33"),
118
132
  price: BigDecimal("3.46"),
119
133
  qty: BigDecimal("3.47") }
120
134
 
121
135
  end
122
136
 
123
-
124
- before do
137
+ before(:each) do
125
138
  # TRUNCATE TABLE also resets the identity counter
126
139
  interface.execute(%Q|truncate table customer;|)
127
140
  end
128
141
 
129
142
 
130
- let(:interface) do
131
- tds_interface_class.new(@connect_hash)
132
- end
133
-
134
- let(:prod_interface) do
135
- prod_interface_class.new(@connect_hash)
136
- end
137
-
138
- #####
139
-
140
-
141
- it_behaves_like 'an interface' do
142
143
 
144
+ it_behaves_like "an interface" do
143
145
  let(:interface) do
144
146
  tds_interface_class.new(@connect_hash)
145
147
  end
146
148
 
147
-
148
- let(:record) { {name: 'Barney'} }
149
+ let(:record) { {name: "Barney"} }
149
150
 
150
151
  end
151
- ##
152
152
 
153
153
 
154
- describe 'TdsInterface.set_db' do
155
- it 'takes one argument' do
154
+ describe "TdsInterface.set_db" do
155
+
156
+ it "takes one argument" do
156
157
  expect( TdsInterface ).to respond_to(:set_db).with(1).argument
157
158
  end
159
+
158
160
  end
159
- ##
160
161
 
161
162
 
162
- describe 'TdsInterface.db' do
163
- it 'returns the table' do
163
+ describe "TdsInterface.db" do
164
+
165
+ it "returns the table" do
164
166
  expect( tds_interface_class.db ).to eq :pod4_test
165
167
  end
168
+
166
169
  end
167
- ##
168
170
 
169
171
 
170
- describe 'TdsInterface.set_schema' do
171
- it 'takes one argument' do
172
+ describe "TdsInterface.set_schema" do
173
+
174
+ it "takes one argument" do
172
175
  expect( TdsInterface ).to respond_to(:set_schema).with(1).argument
173
176
  end
177
+
174
178
  end
175
- ##
176
179
 
177
180
 
178
- describe 'TdsInterface.schema' do
179
- it 'returns the schema' do
181
+ describe "TdsInterface.schema" do
182
+
183
+ it "returns the schema" do
180
184
  expect( schema_interface_class.schema ).to eq :public
181
185
  end
182
186
 
183
- it 'is optional' do
187
+ it "is optional" do
184
188
  expect{ tds_interface_class.schema }.not_to raise_exception
185
189
  expect( tds_interface_class.schema ).to eq nil
186
190
  end
191
+
187
192
  end
188
- ##
189
193
 
190
194
 
191
- describe 'TdsInterface.set_table' do
192
- it 'takes one argument' do
195
+ describe "TdsInterface.set_table" do
196
+
197
+ it "takes one argument" do
193
198
  expect( TdsInterface ).to respond_to(:set_table).with(1).argument
194
199
  end
200
+
195
201
  end
196
- ##
197
202
 
198
203
 
199
- describe 'TdsInterface.table' do
200
- it 'returns the table' do
204
+ describe "TdsInterface.table" do
205
+
206
+ it "returns the table" do
201
207
  expect( tds_interface_class.table ).to eq :customer
202
208
  end
209
+
203
210
  end
204
- ##
205
211
 
206
212
 
207
- describe 'TdsInterface.set_id_fld' do
208
- it 'takes one argument' do
213
+ describe "TdsInterface.set_id_fld" do
214
+
215
+ it "takes one argument" do
209
216
  expect( TdsInterface ).to respond_to(:set_id_fld).with(1).argument
210
217
  end
218
+
219
+ it "takes an optional second 'autoincrement' argument" do
220
+ expect{ TdsInterface.set_id_fld(:foo, autoincrement: false) }.not_to raise_error
221
+ end
222
+
211
223
  end
212
- ##
213
224
 
214
225
 
215
- describe 'TdsInterface.id_fld' do
216
- it 'returns the ID field name' do
226
+ describe "TdsInterface.id_ai" do
227
+
228
+ it "returns true if autoincrement is true" do
229
+ expect( schema_interface_class.id_ai ).to eq true
230
+ end
231
+
232
+ it "returns false if autoincrement is false" do
233
+ expect( prod_interface_class.id_ai ).to eq false
234
+ end
235
+
236
+ it "returns true if autoincrement is not specified" do
237
+ expect( tds_interface_class.id_ai ).to eq true
238
+ end
239
+
240
+ end # of PgInterface.id_ai
241
+
242
+
243
+ describe "TdsInterface.id_fld" do
244
+
245
+ it "returns the ID field name" do
217
246
  expect( tds_interface_class.id_fld ).to eq :id
218
247
  end
219
- end
220
- ##
221
248
 
249
+ end
222
250
 
223
- describe '#new' do
224
251
 
225
- it 'requires a TinyTds connection string' do
226
- expect{ tds_interface_class.new }.to raise_exception ArgumentError
227
- expect{ tds_interface_class.new(nil) }.to raise_exception ArgumentError
228
- expect{ tds_interface_class.new('foo') }.to raise_exception ArgumentError
252
+ describe "#new" do
229
253
 
230
- expect{ tds_interface_class.new(@connect_hash) }.not_to raise_exception
254
+ it "creates a ConnectionPool when passed a TDS connection hash" do
255
+ ifce = tds_interface_class.new(@connect_hash)
256
+ expect( ifce._connection ).to be_a ConnectionPool
231
257
  end
232
258
 
233
- it 'requires the table and id field to be defined in the class' do
234
- expect{ TdsInterface.new(@connect_hash) }.to raise_exception Pod4Error
259
+ it "uses the ConnectionPool when given one" do
260
+ pool = ConnectionPool.new(interface: tds_interface_class)
261
+ ifce = tds_interface_class.new(pool)
235
262
 
236
- expect{ bad_interface_class1.new(@connect_hash) }.
237
- to raise_exception Pod4Error
263
+ expect( ifce._connection ).to eq pool
264
+ end
238
265
 
239
- expect{ bad_interface_class2.new(@connect_hash) }.
240
- to raise_exception Pod4Error
266
+ it "raises ArgumentError when passed something else" do
267
+ expect{ tds_interface_class.new }.to raise_exception ArgumentError
268
+ expect{ tds_interface_class.new(nil) }.to raise_exception ArgumentError
269
+ expect{ tds_interface_class.new("foo") }.to raise_exception ArgumentError
270
+ end
241
271
 
272
+ it "requires the table and id field to be defined in the class" do
273
+ expect{ TdsInterface.new(@connect_hash) }.to raise_exception Pod4Error
274
+ expect{ bad_interface_class1.new(@connect_hash) }.to raise_exception Pod4Error
275
+ expect{ bad_interface_class2.new(@connect_hash) }.to raise_exception Pod4Error
242
276
  end
243
277
 
244
- end
245
- ##
278
+ end # of #new
246
279
 
247
280
 
248
- describe '#quoted_table' do
281
+ describe "#quoted_table" do
249
282
 
250
- it 'returns just the table when the schema is not set' do
283
+ it "returns just the table when the schema is not set" do
251
284
  expect( interface.quoted_table ).to eq( %Q|[customer]| )
252
285
  end
253
286
 
254
- it 'returns the schema plus table when the schema is set' do
287
+ it "returns the schema plus table when the schema is set" do
255
288
  ifce = schema_interface_class.new(@connect_hash)
256
289
  expect( ifce.quoted_table ).to eq( %|[public].[customer]| )
257
290
  end
258
291
 
259
- end
260
- ##
292
+ end # of #quoted_table
261
293
 
262
294
 
263
- describe '#create' do
295
+ describe "#create" do
296
+ let(:hash) { {name: "Bam-Bam", price: 4.44} }
297
+ let(:ot) { Octothorpe.new(name: "Wilma", price: 5.55) }
264
298
 
265
- let(:hash) { {name: 'Bam-Bam', price: 4.44} }
266
- let(:ot) { Octothorpe.new(name: 'Wilma', price: 5.55) }
299
+ it "raises a Pod4::DatabaseError if anything goes wrong" do
300
+ expect{ interface.create(one: "two") }.to raise_exception DatabaseError
301
+ end
267
302
 
268
- it 'raises a Pod4::DatabaseError if anything goes wrong' do
269
- expect{ interface.create(one: 'two') }.to raise_exception DatabaseError
303
+ it "raises an ArgumentError if ID field is missing in hash and not AI" do
304
+ hash = {name: "bar"}
305
+ expect{ prod_interface.create(Octothorpe.new hash) }.to raise_error ArgumentError
270
306
  end
271
307
 
272
- it 'creates the record when given a hash' do
308
+ it "creates the record when given a hash" do
273
309
  # kinda impossible to seperate these two tests
274
310
  id = interface.create(hash)
275
311
 
@@ -277,28 +313,28 @@ describe "TdsInterface" do
277
313
  expect( interface.read(id).to_h ).to include hash
278
314
  end
279
315
 
280
- it 'creates the record when given an Octothorpe' do
316
+ it "creates the record when given an Octothorpe" do
281
317
  id = interface.create(ot)
282
318
 
283
319
  expect{ interface.read(id) }.not_to raise_exception
284
320
  expect( interface.read(id).to_h ).to include ot.to_h
285
321
  end
286
322
 
287
- it 'shouldn\'t have a problem with record values of nil' do
288
- hash2 = {name: 'Ranger', price: nil}
323
+ it "has no problem with record values of nil" do
324
+ hash2 = {name: "Ranger", price: nil}
289
325
  expect{ interface.create(hash2) }.not_to raise_exception
290
326
  id = interface.create(hash2)
291
327
  expect( interface.read(id).to_h ).to include(hash2)
292
328
  end
293
329
 
294
- it 'shouldn\'t have a problem with strings containing special characters' do
330
+ it "has no problem with strings containing special characters" do
295
331
  hash2 = {name: "T'Challa[]", price: nil}
296
332
  expect{ interface.create(hash2) }.not_to raise_exception
297
333
  id = interface.create(hash2)
298
334
  expect( interface.read(id).to_h ).to include(hash2)
299
335
  end
300
336
 
301
- it 'shouldn\'t have a problem with non-integer keys' do
337
+ it "has no problem with non-integer keys" do
302
338
  hash = {code: "foo", name: "bar"}
303
339
  id = prod_interface.create( Octothorpe.new(hash) )
304
340
 
@@ -307,37 +343,51 @@ describe "TdsInterface" do
307
343
  expect( prod_interface.read("foo").to_h ).to include hash
308
344
  end
309
345
 
310
- end
311
- ##
346
+ it "calls ConnectionPool#client" do
347
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
348
+ interface.create(ot)
349
+ end
312
350
 
351
+ it "copes with an OT with the ID field in it when the ID field autoincrements" do
352
+ h = {id: nil, name: "Bam-Bam", qty: 4.44}
353
+ expect{ interface.create(h) }.not_to raise_error
313
354
 
314
- describe '#read' do
315
- before { fill_data(interface) }
355
+ id = interface.create(h)
356
+ expect( id ).not_to be_nil
357
+ expect{ interface.read(id) }.not_to raise_exception
358
+ expect( interface.read(id).to_h ).to include( {name: "Bam-Bam", qty: 4.44} )
359
+ end
316
360
 
317
- it 'returns the record for the id as an Octothorpe' do
361
+ end # of #create
362
+
363
+
364
+ describe "#read" do
365
+ before(:each) { fill_data(interface) }
366
+
367
+ it "returns the record for the id as an Octothorpe" do
318
368
  rec = interface.read(2)
319
369
  expect( rec ).to be_a_kind_of Octothorpe
320
- expect( rec.>>.name ).to eq 'Fred'
370
+ expect( rec.>>.name ).to eq "Fred"
321
371
  end
322
372
 
323
- it 'raises a Pod4::CantContinue if anything goes wrong with the ID' do
373
+ it "raises a Pod4::CantContinue if anything goes wrong with the ID" do
324
374
  expect{ interface.read(:foo) }.to raise_exception CantContinue
325
375
  end
326
376
 
327
- it 'returns an empty Octothorpe if no record matches the ID' do
377
+ it "returns an empty Octothorpe if no record matches the ID" do
328
378
  expect{ interface.read(99) }.not_to raise_exception
329
379
  expect( interface.read(99) ).to be_a_kind_of Octothorpe
330
380
  expect( interface.read(99) ).to be_empty
331
381
  end
332
382
 
333
- it 'returns real fields as Float' do
383
+ it "returns real fields as Float" do
334
384
  level = interface.read(1).>>.level
335
385
 
336
386
  expect( level ).to be_a_kind_of Float
337
387
  expect( level ).to be_within(0.001).of( @data.first[:level] )
338
388
  end
339
389
 
340
- it 'returns date fields as Date' do
390
+ it "returns date fields as Date" do
341
391
  skip "not supported by TinyTds ¬_¬ "
342
392
  date = interface.read(1).>>.day
343
393
 
@@ -345,28 +395,28 @@ describe "TdsInterface" do
345
395
  expect( date ).to eq @data.first[:day]
346
396
  end
347
397
 
348
- it 'returns datetime fields as Time' do
398
+ it "returns datetime fields as Time" do
349
399
  timestamp = interface.read(1).>>.timestamp
350
400
 
351
401
  expect( timestamp ).to be_a_kind_of Time
352
402
  expect( timestamp ).to eq @data.first[:timestamp]
353
403
  end
354
404
 
355
- it 'returns numeric fields as BigDecimal' do
405
+ it "returns numeric fields as BigDecimal" do
356
406
  qty = interface.read(1).>>.qty
357
407
 
358
408
  expect( qty ).to be_a_kind_of BigDecimal
359
409
  expect( qty ).to eq @data.first[:qty]
360
410
  end
361
411
 
362
- it 'returns money fields as BigDecimal' do
412
+ it "returns money fields as BigDecimal" do
363
413
  price = interface.read(1).>>.price
364
414
 
365
415
  expect( price ).to be_a_kind_of BigDecimal
366
416
  expect( price ).to eq @data.first[:price]
367
417
  end
368
418
 
369
- it 'shouldn\'t have a problem with non-integer keys' do
419
+ it "has no problem with non-integer keys" do
370
420
  # this is a 100% overlap with the create test above...
371
421
  fill_product_data(prod_interface)
372
422
 
@@ -374,57 +424,60 @@ describe "TdsInterface" do
374
424
  expect( prod_interface.read("foo").to_h ).to include(code: "foo", name: "bar")
375
425
  end
376
426
 
377
- end
378
- ##
427
+ it "calls ConnectionPool#client" do
428
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
429
+ interface.read(2)
430
+ end
379
431
 
432
+ end # of #read
380
433
 
381
- describe '#list' do
382
- before { fill_data(interface) }
383
434
 
384
- it 'has an optional selection parameter, a hash' do
435
+ describe "#list" do
436
+ before(:each) { fill_data(interface) }
437
+
438
+ it "has an optional selection parameter, a hash" do
385
439
  # Actually it does not have to be a hash, but FTTB we only support that.
386
- expect{ interface.list(name: 'Barney') }.not_to raise_exception
440
+ expect{ interface.list(name: "Barney") }.not_to raise_exception
387
441
  end
388
442
 
389
- it 'returns an array of Octothorpes that match the records' do
443
+ it "returns an array of Octothorpes that match the records" do
390
444
  list = interface.list
391
445
 
392
446
  expect( list.first ).to be_a_kind_of Octothorpe
393
447
  expect( list.map{|x| x.>>.name} ).to match_array @data.map{|y| y[:name]}
394
448
  end
395
449
 
396
- it 'returns a subset of records based on the selection parameter' do
397
- expect( interface.list(name: 'Fred').size ).to eq 1
450
+ it "returns a subset of records based on the selection parameter" do
451
+ expect( interface.list(name: "Fred").size ).to eq 1
398
452
 
399
- expect( interface.list(name: 'Betty').first.to_h ).
400
- to include(name: 'Betty', price: 3.46)
453
+ expect( interface.list(name: "Betty").first.to_h ).
454
+ to include(name: "Betty", price: 3.46)
401
455
 
402
456
  end
403
457
 
404
- it 'returns an empty Array if nothing matches' do
405
- expect( interface.list(name: 'Yogi') ).to eq([])
458
+ it "returns an empty Array if nothing matches" do
459
+ expect( interface.list(name: "Yogi") ).to eq([])
406
460
  end
407
461
 
408
- it 'raises DatabaseError if the selection criteria is nonsensical' do
409
- expect{ interface.list('foo') }.to raise_exception Pod4::DatabaseError
462
+ it "raises DatabaseError if the selection criteria is nonsensical" do
463
+ expect{ interface.list("foo") }.to raise_exception Pod4::DatabaseError
410
464
  end
411
465
 
412
- end
413
- ##
466
+ it "calls ConnectionPool#client" do
467
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
468
+ interface.list
469
+ end
470
+
471
+ end # of #list
414
472
 
415
473
 
416
- describe '#update' do
417
- before { fill_data(interface) }
474
+ describe "#update" do
475
+ before(:each) { fill_data(interface) }
418
476
 
419
477
  let(:id) { interface.list.first[:id] }
420
478
 
421
- def float_price(row)
422
- row[:price] = row[:price].to_f
423
- row
424
- end
425
-
426
- it 'updates the record at ID with record parameter' do
427
- record = {name: 'Booboo', price: 99.99}
479
+ it "updates the record at ID with record parameter" do
480
+ record = {name: "Booboo", price: 99.99}
428
481
  interface.update(id, record)
429
482
 
430
483
  # It so happens that TinyTds returns money as BigDecimal --
@@ -432,138 +485,148 @@ describe "TdsInterface" do
432
485
  expect( float_price( interface.read(id).to_h ) ).to include(record)
433
486
  end
434
487
 
435
- it 'raises a CantContinue if anything weird happens with the ID' do
436
- expect{ interface.update(99, name: 'Booboo') }.
488
+ it "raises a CantContinue if anything weird happens with the ID" do
489
+ expect{ interface.update(99, name: "Booboo") }.
437
490
  to raise_exception CantContinue
438
491
 
439
492
  end
440
493
 
441
- it 'raises a DatabaseError if anything weird happens with the record' do
442
- expect{ interface.update(id, smarts: 'more') }.
494
+ it "raises a DatabaseError if anything weird happens with the record" do
495
+ expect{ interface.update(id, smarts: "more") }.
443
496
  to raise_exception DatabaseError
444
497
 
445
498
  end
446
499
 
447
- it 'shouldn\'t have a problem with record values of nil' do
448
- record = {name: 'Ranger', price: nil}
500
+ it "has no problem with record values of nil" do
501
+ record = {name: "Ranger", price: nil}
449
502
  expect{ interface.update(id, record) }.not_to raise_exception
450
503
  expect( interface.read(id).to_h ).to include(record)
451
504
  end
452
505
 
453
- it 'shouldn\'t have a problem with strings containing special characters' do
506
+ it "has no problem with strings containing special characters" do
454
507
  record = {name: "T'Challa[]", price: nil}
455
508
  expect{ interface.update(id, record) }.not_to raise_exception
456
509
  expect( interface.read(id).to_h ).to include(record)
457
510
  end
458
511
 
459
- it 'shouldn\'t have a problem with non-integer keys' do
512
+ it "has no problem with non-integer keys" do
460
513
  fill_product_data(prod_interface)
461
514
  expect{ prod_interface.update("foo", name: "baz") }.not_to raise_error
462
515
  expect( prod_interface.read("foo").to_h[:name] ).to eq "baz"
463
516
  end
464
517
 
465
- end
466
- ##
467
-
518
+ it "calls ConnectionPool#client" do
519
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
520
+ record = {name: "Booboo", price: 99.99}
521
+ interface.update(id, record)
522
+ end
468
523
 
469
- describe '#delete' do
524
+ end # of #update
470
525
 
471
- def list_contains(ifce, id)
472
- ifce.list.find {|x| x[ifce.id_fld] == id }
473
- end
474
526
 
527
+ describe "#delete" do
475
528
  let(:id) { interface.list.first[:id] }
476
529
 
477
- before { fill_data(interface) }
530
+ before(:each) { fill_data(interface) }
478
531
 
479
- it 'raises CantContinue if anything hinky happens with the ID' do
532
+ it "raises CantContinue if anything hinky happens with the ID" do
480
533
  expect{ interface.delete(:foo) }.to raise_exception CantContinue
481
534
  expect{ interface.delete(99) }.to raise_exception CantContinue
482
535
  end
483
536
 
484
- it 'makes the record at ID go away' do
537
+ it "makes the record at ID go away" do
485
538
  expect( list_contains(interface, id) ).to be_truthy
486
539
  interface.delete(id)
487
540
  expect( list_contains(interface, id) ).to be_falsy
488
541
  end
489
542
 
490
- it 'shouldn\'t have a problem with non-integer keys' do
543
+ it "has no problem with non-integer keys" do
491
544
  fill_product_data(prod_interface)
492
545
  expect( list_contains(prod_interface, "foo") ).to be_truthy
493
546
  prod_interface.delete("foo")
494
547
  expect( list_contains(prod_interface, "foo") ).to be_falsy
495
548
  end
496
549
 
497
- end
498
- ##
550
+ it "calls ConnectionPool#client" do
551
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
552
+ interface.delete(id)
553
+ end
499
554
 
555
+ end # of #delete
500
556
 
501
- describe '#execute' do
502
557
 
503
- let(:sql) { 'delete from customer where price < 2.0;' }
558
+ describe "#execute" do
559
+ let(:sql) { "delete from customer where price < 2.0;" }
504
560
 
505
- before { fill_data(interface) }
561
+ before(:each) { fill_data(interface) }
506
562
 
507
- it 'requires an SQL string' do
563
+ it "requires an SQL string" do
508
564
  expect{ interface.execute }.to raise_exception ArgumentError
509
565
  expect{ interface.execute(nil) }.to raise_exception ArgumentError
510
566
  expect{ interface.execute(14) }.to raise_exception ArgumentError
511
567
  end
512
568
 
513
- it 'raises some sort of Pod4 error if it runs into problems' do
514
- expect{ interface.execute('delete from not_a_table') }.
569
+ it "raises some sort of Pod4 error if it runs into problems" do
570
+ expect{ interface.execute("delete from not_a_table") }.
515
571
  to raise_exception Pod4Error
516
572
 
517
573
  end
518
574
 
519
- it 'executes the string' do
575
+ it "executes the string" do
520
576
  expect{ interface.execute(sql) }.not_to raise_exception
521
577
  expect( interface.list.size ).to eq(@data.size - 1)
522
- expect( interface.list.map{|r| r[:name] } ).not_to include 'Barney'
578
+ expect( interface.list.map{|r| r[:name] } ).not_to include "Barney"
523
579
  end
524
580
 
525
- end
526
- ##
581
+ it "calls ConnectionPool#client" do
582
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
583
+ interface.execute(sql)
584
+ end
527
585
 
586
+ end # of #execute
528
587
 
529
- describe '#select' do
530
588
 
531
- before { fill_data(interface) }
589
+ describe "#select" do
590
+ before(:each) { fill_data(interface) }
532
591
 
533
- it 'requires an SQL string' do
592
+ it "requires an SQL string" do
534
593
  expect{ interface.select }.to raise_exception ArgumentError
535
594
  expect{ interface.select(nil) }.to raise_exception ArgumentError
536
595
  expect{ interface.select(14) }.to raise_exception ArgumentError
537
596
  end
538
597
 
539
- it 'raises some sort of Pod4 error if it runs into problems' do
540
- expect{ interface.select('select * from not_a_table') }.
598
+ it "raises some sort of Pod4 error if it runs into problems" do
599
+ expect{ interface.select("select * from not_a_table") }.
541
600
  to raise_exception Pod4Error
542
601
 
543
602
  end
544
603
 
545
- it 'returns the result of the sql' do
546
- sql1 = 'select name from customer where price < 2.0;'
547
- sql2 = 'select name from customer where price < 0.0;'
604
+ it "returns the result of the sql" do
605
+ sql1 = "select name from customer where price < 2.0;"
606
+ sql2 = "select name from customer where price < 0.0;"
548
607
 
549
608
  expect{ interface.select(sql1) }.not_to raise_exception
550
- expect( interface.select(sql1) ).to eq( [{name: 'Barney'}] )
609
+ expect( interface.select(sql1) ).to eq( [{name: "Barney"}] )
551
610
  expect( interface.select(sql2) ).to eq( [] )
552
611
  end
553
612
 
554
- it 'works if you pass a non-select' do
613
+ it "works if you pass a non-select" do
555
614
  # By which I mean: still executes the SQL; returns []
556
- sql = 'delete from customer where price < 2.0;'
615
+ sql = "delete from customer where price < 2.0;"
557
616
  ret = interface.select(sql)
558
617
 
559
618
  expect( interface.list.size ).to eq(@data.size - 1)
560
- expect( interface.list.map{|r| r[:name] } ).not_to include 'Barney'
619
+ expect( interface.list.map{|r| r[:name] } ).not_to include "Barney"
561
620
  expect( ret ).to eq( [] )
562
621
  end
563
622
 
623
+ it "calls ConnectionPool#client" do
624
+ expect( interface._connection ).to receive(:client).at_least(:once).and_call_original
625
+ sql = "delete from customer where price < 2.0;"
626
+ interface.select(sql)
627
+ end
564
628
 
565
- end
566
- ##
629
+ end # of #select
567
630
 
568
631
 
569
632
  describe "#escape" do
@@ -579,9 +642,30 @@ describe "TdsInterface" do
579
642
  expect( interface.escape "G'Kar" ).to eq %Q|G''Kar|
580
643
  end
581
644
 
582
- end
583
- ##
645
+ end # of #escape
646
+
647
+
648
+ describe "#new_connection" do
649
+
650
+ it "returns a PG Client object" do
651
+ expect( interface.new_connection @connect_hash ).to be_a TinyTds::Client
652
+ end
653
+
654
+ end # of #new_connection
655
+
656
+
657
+ describe "#close_connection" do
658
+
659
+ it "closes the given PG Client object" do
660
+ client = interface.new_connection(@connect_hash)
661
+
662
+ expect( client ).to receive(:close)
663
+
664
+ interface.close_connection(client)
665
+ end
666
+
667
+ end # of #close_connection
668
+
584
669
 
585
-
586
670
  end
587
671