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