pod4 0.10.6 → 1.0.0

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 (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
@@ -1,152 +1,175 @@
1
- require 'pod4/null_interface'
1
+ require "pod4/null_interface"
2
2
 
3
- require_relative 'shared_examples_for_interface'
3
+ require_relative "shared_examples_for_interface"
4
4
 
5
5
 
6
6
  describe NullInterface do
7
7
 
8
+ def list_contains(id)
9
+ interface.list.find {|x| x[interface.id_fld] == id }
10
+ end
11
+
12
+ # An autoincrementing interface
8
13
  let(:data) do
9
- [ {name: 'Barney', price: 1.11},
10
- {name: 'Fred', price: 2.22},
11
- {name: 'Betty', price: 3.33} ]
14
+ [ {id: 1, name: "Barney", price: 1.11},
15
+ {id: 2, name: "Fred", price: 2.22},
16
+ {id: 3, name: "Betty", price: 3.33} ]
12
17
  end
18
+ let (:interface) { NullInterface.new(:id, :name, :price, data) }
13
19
 
14
- let (:interface) { NullInterface.new(:name, :price, data) }
20
+ # A non-autoincrementing interface
21
+ let(:data2) do
22
+ [ {code: "foo", level: 1},
23
+ {code: "bar", level: 2},
24
+ {code: "baz", level: 3} ]
25
+ end
15
26
 
16
- ##
27
+ let (:interface2) do
28
+ i = NullInterface.new(:code, :level, data2)
29
+ i.id_ai = false
30
+ i
31
+ end
17
32
 
18
33
 
19
34
  it_behaves_like "an interface" do
20
- let(:record) { {name: 'barney', price:1.11} }
21
- let(:interface) { NullInterface.new( :name, :price, [record] ) }
35
+ let(:record) { {name: "barney", price:1.11} }
36
+ let(:interface) { NullInterface.new( :id, :name, :price, [record]) }
22
37
  end
23
38
 
24
39
 
25
- describe '#new' do
40
+ describe "#new" do
26
41
 
27
- it 'requires a list of columns and an array of hashes' do
42
+ it "requires a list of columns and an array of hashes" do
28
43
  expect{ NullInterface.new }.to raise_exception ArgumentError
29
44
  expect{ NullInterface.new(nil) }.to raise_exception ArgumentError
30
- expect{ NullInterface.new('foo') }.to raise_exception ArgumentError
45
+ expect{ NullInterface.new("foo") }.to raise_exception ArgumentError
31
46
 
32
47
  expect{ NullInterface.new(:one, [{one:1}]) }.not_to raise_exception
33
48
  end
34
49
 
35
- end
36
- ##
50
+ it "defaults autoincrement to true" do
51
+ expect( interface.id_ai ).to eq true
52
+ end
37
53
 
54
+ it "allows you to set autoincrement to false" do
55
+ ni = NullInterface.new(:one, [{one:1}])
56
+ ni.id_ai = false
57
+ expect( ni.id_ai ).to eq false
58
+ end
38
59
 
39
- describe '#create' do
60
+ end # of #new
40
61
 
41
- let(:hash) { {name: 'Bam-Bam', price: 4.44} }
42
- let(:ot) { Octothorpe.new(name: 'Wilma', price: 5.55) }
43
62
 
44
- it 'creates the record when given a hash' do
63
+ describe "#create" do
64
+
65
+ let(:hash) { {name: "Bam-Bam", price: 4.44} }
66
+ let(:ot) { Octothorpe.new(name: "Wilma", price: 5.55) }
67
+
68
+ it "creates the record when given a hash" do
45
69
  id = interface.create(hash)
46
70
 
47
71
  expect{ interface.read(id) }.not_to raise_exception
48
72
  expect( interface.read(id).to_h ).to include hash
49
73
  end
50
74
 
51
- it 'creates the record when given an Octothorpe' do
75
+ it "creates the record when given an Octothorpe" do
52
76
  id = interface.create(ot)
53
77
 
54
78
  expect{ interface.read(id) }.not_to raise_exception
55
79
  expect( interface.read(id).to_h ).to include ot.to_h
56
80
  end
57
81
 
58
- end
59
- ##
82
+ it "raises an ArgumentError when the key is not AI and the record is missing the key" do
83
+ expect{ interface2.create(level: 55) }.to raise_error ArgumentError
84
+ end
60
85
 
86
+ it "sets the ID field to the correct integer when autoincrement is true" do
87
+ count = interface.list.size
88
+ id = interface.create(ot)
89
+ expect( id ).to eq(count + 1)
90
+ end
91
+
92
+ it "sets the ID field to whatever you set in the record when autoincrement is false" do
93
+ id = interface2.create Octothorpe.new(code: "flong", level: 9)
94
+ expect( id ).to eq "flong"
95
+ end
96
+
97
+ end # of #create
61
98
 
62
- describe '#read' do
63
99
 
64
- it 'returns the record for the id as an Octothorpe' do
65
- expect( interface.read('Barney') ).to be_a_kind_of Octothorpe
66
- expect( interface.read('Fred').to_h ).
67
- to include(name: 'Fred', price: 2.22)
100
+ describe "#read" do
68
101
 
102
+ it "returns the record for the id as an Octothorpe" do
103
+ expect( interface.read(1) ).to be_a_kind_of Octothorpe
104
+ expect( interface.read(2).to_h ).to include(name: "Fred", price: 2.22)
69
105
  end
70
106
 
71
- it 'returns an empty Octothorpe if no record matches the ID' do
107
+ it "returns an empty Octothorpe if no record matches the ID" do
72
108
  expect{ interface.read(:foo) }.not_to raise_exception
73
109
  expect( interface.read(:foo) ).to be_a_kind_of Octothorpe
74
110
  expect( interface.read(:foo) ).to be_empty
75
111
  end
76
112
 
77
- end
78
- ##
113
+ end # of #read
79
114
 
80
115
 
81
- describe '#list' do
116
+ describe "#list" do
82
117
 
83
- it 'has an optional selection parameter, a hash' do
118
+ it "has an optional selection parameter, a hash" do
84
119
  expect{ interface.list }.not_to raise_exception
85
- expect{ interface.list(name: 'Barney') }.not_to raise_exception
120
+ expect{ interface.list(name: "Barney") }.not_to raise_exception
86
121
  end
87
122
 
88
- it 'returns an array of Octothorpes that match the records' do
123
+ it "returns an array of Octothorpes that match the records" do
89
124
  arr = interface.list.map(&:to_h)
90
125
  expect( arr ).to match_array data
91
126
  end
92
127
 
93
- it 'returns a subset of records based on the selection parameter' do
94
- expect( interface.list(name: 'Fred').size ).to eq 1
128
+ it "returns a subset of records based on the selection parameter" do
129
+ expect( interface.list(name: "Fred").size ).to eq 1
95
130
 
96
- expect( interface.list(name: 'Betty').first.to_h ).
97
- to include(name: 'Betty', price: 3.33)
131
+ expect( interface.list(name: "Betty").first.to_h ).
132
+ to include(name: "Betty", price: 3.33)
98
133
 
99
134
  end
100
135
 
101
- it 'returns an empty Array if nothing matches' do
102
- expect( interface.list(name: 'Yogi') ).to eq([])
136
+ it "returns an empty Array if nothing matches" do
137
+ expect( interface.list(name: "Yogi") ).to eq([])
103
138
  end
104
139
 
105
- it 'returns an empty array if there is no data' do
140
+ it "returns an empty array if there is no data" do
106
141
  interface.list.each {|x| interface.delete(x[interface.id_fld]) }
107
142
  expect( interface.list ).to eq([])
108
143
  end
109
144
 
110
- end
111
- ##
145
+ end # of #list
112
146
 
113
147
 
114
- describe '#update' do
115
-
116
- let(:id) { interface.list.first[:name] }
148
+ describe "#update" do
117
149
 
118
- it 'updates the record at ID with record parameter' do
150
+ it "updates the record at ID with record parameter" do
119
151
  record = {price: 99.99}
120
- interface.update(id, record)
152
+ interface.update(1, record)
121
153
 
122
- expect( interface.read(id).to_h ).to include(record)
154
+ expect( interface.read(1).to_h ).to include(record)
123
155
  end
124
156
 
125
- end
126
- ##
127
-
128
-
129
- describe '#delete' do
130
-
131
- def list_contains(id)
132
- interface.list.find {|x| x[interface.id_fld] == id }
133
- end
157
+ end # of #update
134
158
 
135
- let(:id) { interface.list.first[:name] }
136
159
 
137
- it 'raises CantContinue if anything hinky happens with the ID' do
160
+ describe "#delete" do
161
+ it "raises CantContinue if anything hinky happens with the ID" do
138
162
  expect{ interface.delete(:foo) }.to raise_exception CantContinue
139
163
  expect{ interface.delete(99) }.to raise_exception CantContinue
140
164
  end
141
165
 
142
- it 'makes the record at ID go away' do
143
- expect( list_contains(id) ).to be_truthy
144
- interface.delete(id)
145
- expect( list_contains(id) ).to be_falsy
166
+ it "makes the record at ID go away" do
167
+ expect( list_contains(1) ).to be_truthy
168
+ interface.delete(1)
169
+ expect( list_contains(1) ).to be_falsy
146
170
  end
147
171
 
148
- end
149
- ##
172
+ end # of #delete
150
173
 
151
174
 
152
175
  end
@@ -2,16 +2,48 @@
2
2
  # Supplemental test for Sequel -- tests using PG gem in MRI, jeremyevans-postgres-pg under jruby?
3
3
  #
4
4
 
5
- require 'pod4/sequel_interface'
5
+ require "pod4/sequel_interface"
6
6
 
7
- require 'sequel'
8
- require 'date'
9
- require 'time'
10
- require 'bigdecimal'
7
+ require "sequel"
8
+ require "date"
9
+ require "time"
10
+ require "bigdecimal"
11
11
 
12
12
 
13
13
  describe "SequelInterface (Pg)" do
14
14
 
15
+ def fill_data(ifce, data)
16
+ data.each{|r| ifce.create(r) }
17
+ end
18
+
19
+ def fill_product_data(ifce)
20
+ ifce.create( {code: "foo", name: "bar"} )
21
+ end
22
+
23
+ def list_contains(ifce, id)
24
+ ifce.list.find {|x| x[ifce.id_fld] == id }
25
+ end
26
+
27
+ def db_setup(db)
28
+ db.run %Q|
29
+ drop table if exists customer;
30
+ drop table if exists product;
31
+
32
+ create table customer (
33
+ id serial primary key,
34
+ name text,
35
+ level real null,
36
+ day date null,
37
+ timestamp timestamp null,
38
+ price money null,
39
+ qty numeric null );
40
+
41
+ create table product (
42
+ code text,
43
+ name text );|
44
+
45
+ end
46
+
15
47
  let(:sequel_interface_class) do
16
48
  Class.new SequelInterface do
17
49
  set_table :customer
@@ -30,115 +62,139 @@ describe "SequelInterface (Pg)" do
30
62
  let(:prod_interface_class) do
31
63
  Class.new SequelInterface do
32
64
  set_table :product
33
- set_id_fld :code
65
+ set_id_fld :code, autoincrement: false
34
66
  end
35
67
  end
36
68
 
37
-
38
69
  let(:data) do
39
70
  d = []
40
- d << { name: 'Barney',
71
+ d << { name: "Barney",
41
72
  level: 1.23,
42
73
  day: Date.parse("2016-01-01"),
43
- timestamp: Time.parse('2015-01-01 12:11'),
74
+ timestamp: Time.parse("2015-01-01 12:11"),
44
75
  qty: BigDecimal("1.24"),
45
76
  price: BigDecimal("1.24") }
46
77
 
47
- d << { name: 'Fred',
78
+ d << { name: "Fred",
48
79
  level: 2.34,
49
80
  day: Date.parse("2016-02-02"),
50
- timestamp: Time.parse('2015-01-02 12:22'),
81
+ timestamp: Time.parse("2015-01-02 12:22"),
51
82
  qty: BigDecimal("2.35"),
52
83
  price: BigDecimal("2.35") }
53
84
 
54
- d << { name: 'Betty',
85
+ d << { name: "Betty",
55
86
  level: 3.45,
56
87
  day: Date.parse("2016-03-03"),
57
- timestamp: Time.parse('2015-01-03 12:33'),
88
+ timestamp: Time.parse("2015-01-03 12:33"),
58
89
  qty: BigDecimal("3.46"),
59
90
  price: BigDecimal("3.46") }
60
91
 
61
92
  d
62
93
  end
63
94
 
64
- def fill_data(ifce)
65
- data.each{|r| ifce.create(r) }
66
- end
67
-
68
- def fill_product_data(ifce)
69
- ifce.create( {code: "foo", name: "bar"} )
70
- end
71
-
72
-
73
- let (:db) do
74
- db = Sequel.connect('postgres://pod4test:pod4test@centos7andy/pod4_test?search_path=public')
75
-
76
- db.run %Q|
77
- drop table if exists customer;
78
- drop table if exists product;
79
-
80
- create table customer (
81
- id serial primary key,
82
- name text,
83
- level real null,
84
- day date null,
85
- timestamp timestamp null,
86
- price money null,
87
- qty numeric null );
88
-
89
- create table product (
90
- code text,
91
- name text );|
95
+ let(:db_url) { "postgres://pod4test:pod4test@centos7andy/pod4_test?search_path=public" }
92
96
 
97
+ let(:db) do
98
+ db = Sequel.connect(db_url)
99
+ db_setup(db)
93
100
  db
94
101
  end
95
102
 
96
103
  let(:interface) { sequel_interface_class.new(db) }
97
104
  let(:prod_interface) { prod_interface_class.new(db) }
98
105
 
99
-
100
-
101
106
  before do
102
107
  interface.execute %Q|
103
108
  truncate table customer restart identity;
104
109
  truncate table product;|
105
110
 
106
- fill_data(interface)
111
+ fill_data(interface, data)
107
112
  end
108
113
 
109
114
  after do
110
115
  db.disconnect
111
116
  end
112
117
 
113
- ##
114
118
 
119
+ describe "#new" do
120
+
121
+ context "when passed a Sequel DB object" do
122
+ let(:ifce) { sequel_interface_class.new(Sequel.connect db_url) }
123
+
124
+ it "uses it to create a connection" do
125
+ expect( ifce._connection ).to be_a Connection
126
+ expect( ifce._connection.interface_class ).to eq sequel_interface_class
127
+ end
128
+
129
+ it "calls Connection#client on first use" do
130
+ expect( ifce._connection ).to receive(:client).with(ifce).and_call_original
131
+ ifce.list
132
+ end
133
+ end
134
+
135
+ context "when passed a String" do
136
+ let(:ifce) { sequel_interface_class.new(db_url) }
137
+
138
+ it "uses it to create a connection" do
139
+ expect( ifce._connection ).to be_a Connection
140
+ expect( ifce._connection.interface_class ).to eq sequel_interface_class
141
+ end
142
+
143
+ # Normally we'd expect on _every_ use, but Sequel is different
144
+ it "calls Connection#client on first use" do
145
+ expect( ifce._connection ).to receive(:client).with(ifce).and_call_original
146
+ ifce.list
147
+ end
148
+ end
149
+
150
+ context "when passed a Connection object" do
151
+ let(:conn) { Connection.new(interface: sequel_interface_class) }
152
+ let(:ifce) { sequel_interface_class.new(conn) }
153
+
154
+ it "uses that as its connection object" do
155
+ expect( ifce._connection ).to be_a Connection
156
+ expect( ifce._connection ).to eq conn
157
+ expect( ifce._connection.interface_class ).to eq sequel_interface_class
158
+ end
159
+
160
+ # Normally we'd expect on _every_ use, but Sequel is different
161
+ it "calls Connection#client on first use" do
162
+ # When we pass a connection object we are expected to set the data layer option
163
+ conn.data_layer_options = Sequel.connect(db_url)
115
164
 
116
- describe '#quoted_table' do
165
+ expect( ifce._connection ).to receive(:client).with(ifce).and_call_original
117
166
 
118
- it 'returns just the table when the schema is not set' do
167
+ ifce.list
168
+ end
169
+ end
170
+
171
+ end # of #new
172
+
173
+ describe "#quoted_table" do
174
+
175
+ it "returns just the table when the schema is not set" do
119
176
  expect( interface.quoted_table.downcase ).to eq( %Q|"customer"| )
120
177
  end
121
178
 
122
- it 'returns the schema plus table when the schema is set' do
179
+ it "returns the schema plus table when the schema is set" do
123
180
  ifce = schema_interface_class.new(db)
124
181
  expect( ifce.quoted_table.downcase ).to eq( %|"public"."customer"| )
125
182
  end
126
183
 
127
- end
128
- ##
184
+ end # of #quoted_table
129
185
 
130
186
 
131
- describe '#create' do
187
+ describe "#create" do
132
188
 
133
- let(:hash) { {name: 'Bam-Bam', qty: 4.44} }
134
- let(:ot) { Octothorpe.new(name: 'Wilma', qty: 5.55) }
189
+ let(:hash) { {name: "Bam-Bam", qty: 4.44} }
190
+ let(:ot) { Octothorpe.new(name: "Wilma", qty: 5.55) }
135
191
 
136
192
 
137
- it 'raises a Pod4::DatabaseError if anything goes wrong' do
138
- expect{ interface.create(one: 'two') }.to raise_exception DatabaseError
193
+ it "raises a Pod4::DatabaseError if anything goes wrong" do
194
+ expect{ interface.create(one: "two") }.to raise_exception DatabaseError
139
195
  end
140
196
 
141
- it 'creates the record when given a hash' do
197
+ it "creates the record when given a hash" do
142
198
  # kinda impossible to seperate these two tests
143
199
  id = interface.create(hash)
144
200
 
@@ -147,26 +203,26 @@ describe "SequelInterface (Pg)" do
147
203
  expect( interface.read(id).to_h ).to include hash
148
204
  end
149
205
 
150
- it 'creates the record when given an Octothorpe' do
206
+ it "creates the record when given an Octothorpe" do
151
207
  id = interface.create(ot)
152
208
 
153
209
  expect{ interface.read(id) }.not_to raise_exception
154
210
  expect( interface.read(id).to_h ).to include ot.to_h
155
211
  end
156
212
 
157
- it 'does not freak out if the hash has symbol values' do
213
+ it "does not freak out if the hash has symbol values" do
158
214
  # Which, Sequel does
159
215
  expect{ interface.create(name: :Booboo) }.not_to raise_exception
160
216
  end
161
217
 
162
- it 'shouldnt have a problem with record values of nil' do
163
- record = {name: 'Ranger', price: nil}
218
+ it "has no problem with record values of nil" do
219
+ record = {name: "Ranger", price: nil}
164
220
  expect{ interface.create(record) }.not_to raise_exception
165
221
  id = interface.create(record)
166
222
  expect( interface.read(id).to_h ).to include(record)
167
223
  end
168
224
 
169
- it 'shouldnt have a problem with strings containing special characters' do
225
+ it "has no problem with strings containing special characters" do
170
226
  # Note that in passing we retest that create returns the ID for identity columns
171
227
 
172
228
  record = {name: "T'Challa[]", price: nil}
@@ -175,7 +231,7 @@ describe "SequelInterface (Pg)" do
175
231
  expect( interface.read(id).to_h ).to include(record)
176
232
  end
177
233
 
178
- it 'shouldn\'t have a problem with non-integer keys' do
234
+ it "has no problem with non-integer keys" do
179
235
  # Note that in passing we retest that create returns the ID for non-identity columns
180
236
 
181
237
  hash = {code: "foo", name: "bar"}
@@ -186,55 +242,64 @@ describe "SequelInterface (Pg)" do
186
242
  expect( prod_interface.read("foo").to_h ).to include hash
187
243
  end
188
244
 
189
- end
190
- ##
245
+ it "copes with an OT with the ID field in it when the ID field autoincrements" do
246
+ h = {id: nil, name: "Bam-Bam", qty: 4.44}
247
+ expect{ interface.create(h) }.not_to raise_error
191
248
 
249
+ id = interface.create(h)
250
+ expect( id ).not_to be_nil
251
+ expect{ interface.read(id) }.not_to raise_exception
252
+ expect( interface.read(id).to_h ).to include( {name: "Bam-Bam", qty: 4.44} )
253
+ end
192
254
 
193
- describe '#read' do
255
+ end # of #create
194
256
 
195
- it 'returns the record for the id as an Octothorpe' do
196
- expect( interface.read(2).to_h ).to include(name: 'Fred', qty: 2.35)
257
+
258
+ describe "#read" do
259
+
260
+ it "returns the record for the id as an Octothorpe" do
261
+ expect( interface.read(2).to_h ).to include(name: "Fred", qty: 2.35)
197
262
  end
198
263
 
199
- it 'raises a Pod4::CantContinue if the ID is bad' do
264
+ it "raises a Pod4::CantContinue if the ID is bad" do
200
265
  expect{ interface.read(:foo) }.to raise_exception CantContinue
201
266
  end
202
267
 
203
- it 'returns an empty Octothorpe if no record matches the ID' do
268
+ it "returns an empty Octothorpe if no record matches the ID" do
204
269
  expect{ interface.read(99) }.not_to raise_exception
205
270
  expect( interface.read(99) ).to be_a_kind_of Octothorpe
206
271
  expect( interface.read(99) ).to be_empty
207
272
  end
208
273
 
209
- it 'returns real fields as Float' do
274
+ it "returns real fields as Float" do
210
275
  level = interface.read(1).>>.level
211
276
 
212
277
  expect( level ).to be_a_kind_of Float
213
278
  expect( level ).to be_within(0.001).of( data.first[:level] )
214
279
  end
215
280
 
216
- it 'returns date fields as Date' do
281
+ it "returns date fields as Date" do
217
282
  date = interface.read(1).>>.day
218
283
 
219
284
  expect( date ).to be_a_kind_of Date
220
285
  expect( date ).to eq data.first[:day]
221
286
  end
222
287
 
223
- it 'returns datetime fields as Time' do
288
+ it "returns datetime fields as Time" do
224
289
  timestamp = interface.read(1).>>.timestamp
225
290
 
226
291
  expect( timestamp ).to be_a_kind_of Time
227
292
  expect( timestamp ).to eq data.first[:timestamp]
228
293
  end
229
294
 
230
- it 'returns numeric fields as BigDecimal' do
295
+ it "returns numeric fields as BigDecimal" do
231
296
  qty = interface.read(1).>>.qty
232
297
 
233
298
  expect( qty ).to be_a_kind_of BigDecimal
234
299
  expect( qty ).to eq data.first[:qty]
235
300
  end
236
301
 
237
- it 'returns money fields as bigdecimal' do
302
+ it "returns money fields as bigdecimal" do
238
303
  pending "Sequel/PG returns a string for Money type"
239
304
 
240
305
  price = interface.read(1).>>.price
@@ -243,7 +308,7 @@ describe "SequelInterface (Pg)" do
243
308
  expect( price ).to eq data.first[:price]
244
309
  end
245
310
 
246
- it 'shouldn\'t have a problem with non-integer keys' do
311
+ it "has no problem with non-integer keys" do
247
312
  # this is a 100% overlap with the create test above...
248
313
  fill_product_data(prod_interface)
249
314
 
@@ -251,14 +316,12 @@ describe "SequelInterface (Pg)" do
251
316
  expect( prod_interface.read("foo").to_h ).to include(code: "foo", name: "bar")
252
317
  end
253
318
 
254
- end
255
- ##
256
-
257
-
319
+ end # of #read
320
+
258
321
 
259
- describe '#list' do
322
+ describe "#list" do
260
323
 
261
- it 'returns an array of Octothorpes that match the records' do
324
+ it "returns an array of Octothorpes that match the records" do
262
325
  arr = interface.list.map {|ot| x = ot.to_h}
263
326
 
264
327
  expect( arr.size ).to eq(data.size)
@@ -274,43 +337,40 @@ describe "SequelInterface (Pg)" do
274
337
 
275
338
  end
276
339
 
277
- it 'returns a subset of records based on the selection parameter' do
278
- expect( interface.list(name: 'Fred').size ).to eq 1
340
+ it "returns a subset of records based on the selection parameter" do
341
+ expect( interface.list(name: "Fred").size ).to eq 1
279
342
 
280
- expect( interface.list(name: 'Betty').first.to_h ).
281
- to include(name: 'Betty', qty: 3.46)
343
+ expect( interface.list(name: "Betty").first.to_h ).
344
+ to include(name: "Betty", qty: 3.46)
282
345
 
283
346
  end
284
347
 
285
- it 'returns an empty Array if nothing matches' do
286
- expect( interface.list(name: 'Yogi') ).to eq([])
348
+ it "returns an empty Array if nothing matches" do
349
+ expect( interface.list(name: "Yogi") ).to eq([])
287
350
  end
288
351
 
289
- it 'raises DatabaseError if the selection criteria is nonsensical' do
290
- expect{ interface.list('foo') }.to raise_exception Pod4::DatabaseError
352
+ it "raises DatabaseError if the selection criteria is nonsensical" do
353
+ expect{ interface.list("foo") }.to raise_exception Pod4::DatabaseError
291
354
  end
292
355
 
293
- it 'returns an empty array if there is no data' do
356
+ it "returns an empty array if there is no data" do
294
357
  interface.list.each {|x| interface.delete(x[interface.id_fld]) }
295
358
  expect( interface.list ).to eq([])
296
359
  end
297
360
 
298
- it 'does not freak out if the hash has symbol values' do
361
+ it "doesn't freak out if the hash has symbol values" do
299
362
  # Which, Sequel does
300
363
  expect{ interface.list(name: :Barney) }.not_to raise_exception
301
364
  end
302
365
 
303
-
304
- end
305
- ##
366
+ end # of #list
306
367
 
307
368
 
308
- describe '#update' do
309
-
369
+ describe "#update" do
310
370
  let(:id) { interface.list.first[:id] }
311
371
 
312
- it 'updates the record at ID with record parameter' do
313
- record = {name: 'Booboo', qty: 99.99}
372
+ it "updates the record at ID with record parameter" do
373
+ record = {name: "Booboo", qty: 99.99}
314
374
  interface.update(id, record)
315
375
 
316
376
  booboo = interface.read(id)
@@ -318,203 +378,199 @@ describe "SequelInterface (Pg)" do
318
378
  expect( booboo.>>.qty.to_f ).to eq( record[:qty] )
319
379
  end
320
380
 
321
- it 'raises a CantContinue if anything weird happens with the ID' do
322
- expect{ interface.update(99, name: 'Booboo') }.
381
+ it "raises a CantContinue if anything weird happens with the ID" do
382
+ expect{ interface.update(99, name: "Booboo") }.
323
383
  to raise_exception CantContinue
324
384
 
325
385
  end
326
386
 
327
- it 'raises a DatabaseError if anything weird happensi with the record' do
328
- expect{ interface.update(id, smarts: 'more') }.
387
+ it "raises a DatabaseError if anything weird happensi with the record" do
388
+ expect{ interface.update(id, smarts: "more") }.
329
389
  to raise_exception DatabaseError
330
390
 
331
391
  end
332
392
 
333
- it 'does not freak out if the hash has symbol values' do
393
+ it "doesn't freak out if the hash has symbol values" do
334
394
  # Which, Sequel does
335
395
  expect{ interface.update(id, name: :Booboo) }.not_to raise_exception
336
396
  end
337
397
 
338
- it 'shouldn\'t have a problem with record values of nil' do
339
- record = {name: 'Ranger', qty: nil}
398
+ it "has no problem with record values of nil" do
399
+ record = {name: "Ranger", qty: nil}
340
400
  expect{ interface.update(id, record) }.not_to raise_exception
341
401
  expect( interface.read(id).to_h ).to include(record)
342
402
  end
343
403
 
344
- it 'shouldn\'t have a problem with strings containing special characters' do
404
+ it "has no problem with strings containing special characters" do
345
405
  record = {name: "T'Challa[]", qty: nil}
346
406
  expect{ interface.update(id, record) }.not_to raise_exception
347
407
  expect( interface.read(id).to_h ).to include(record)
348
408
  end
349
409
 
350
- it 'shouldn\'t have a problem with non-integer keys' do
410
+ it "has no problem with non-integer keys" do
351
411
  fill_product_data(prod_interface)
352
412
  expect{ prod_interface.update("foo", name: "baz") }.not_to raise_error
353
413
  expect( prod_interface.read("foo").to_h[:name] ).to eq "baz"
354
414
  end
355
415
 
356
- end
357
- ##
358
-
359
-
360
- describe '#delete' do
416
+ end # of #update
361
417
 
362
- def list_contains(ifce, id)
363
- ifce.list.find {|x| x[ifce.id_fld] == id }
364
- end
365
418
 
419
+ describe "#delete" do
366
420
  let(:id) { interface.list.first[:id] }
367
421
 
368
- it 'raises CantContinue if anything hinky happens with the ID' do
422
+ it "raises CantContinue if anything hinky happens with the ID" do
369
423
  expect{ interface.delete(:foo) }.to raise_exception CantContinue
370
424
  expect{ interface.delete(99) }.to raise_exception CantContinue
371
425
  end
372
426
 
373
- it 'makes the record at ID go away' do
427
+ it "makes the record at ID go away" do
374
428
  expect( list_contains(interface, id) ).to be_truthy
375
429
  interface.delete(id)
376
430
  expect( list_contains(interface, id) ).to be_falsy
377
431
  end
378
432
 
379
- it 'shouldn\'t have a problem with non-integer keys' do
433
+ it "has no problem with non-integer keys" do
380
434
  fill_product_data(prod_interface)
381
435
  expect( list_contains(prod_interface, "foo") ).to be_truthy
382
436
  prod_interface.delete("foo")
383
437
  expect( list_contains(prod_interface, "foo") ).to be_falsy
384
438
  end
385
439
 
386
- end
387
- ##
388
-
440
+ end # of #delete
389
441
 
390
- describe '#execute' do
391
442
 
392
- let(:sql) { 'delete from customer where qty < 2.0;' }
443
+ describe "#execute" do
444
+ let(:sql) { "delete from customer where qty < 2.0;" }
393
445
 
394
- it 'requires an SQL string' do
446
+ it "requires an SQL string" do
395
447
  expect{ interface.execute }.to raise_exception ArgumentError
396
448
  expect{ interface.execute(nil) }.to raise_exception ArgumentError
397
449
  expect{ interface.execute(14) }.to raise_exception ArgumentError
398
450
  end
399
451
 
400
- it 'raises some sort of Pod4 error if it runs into problems' do
401
- expect{ interface.execute('delete from not_a_table') }.
452
+ it "raises some sort of Pod4 error if it runs into problems" do
453
+ expect{ interface.execute("delete from not_a_table") }.
402
454
  to raise_exception Pod4Error
403
455
 
404
456
  end
405
457
 
406
- it 'executes the string' do
458
+ it "executes the string" do
407
459
  expect{ interface.execute(sql) }.not_to raise_exception
408
460
  expect( interface.list.size ).to eq(data.size - 1)
409
- expect( interface.list.map{|r| r[:name] } ).not_to include 'Barney'
461
+ expect( interface.list.map{|r| r[:name] } ).not_to include "Barney"
410
462
  end
411
463
 
412
- end
413
- ##
464
+ end # of #execute
414
465
 
415
466
 
416
- describe '#select' do
467
+ describe "#select" do
417
468
 
418
- it 'requires an SQL string' do
469
+ it "requires an SQL string" do
419
470
  expect{ interface.select }.to raise_exception ArgumentError
420
471
  expect{ interface.select(nil) }.to raise_exception ArgumentError
421
472
  expect{ interface.select(14) }.to raise_exception ArgumentError
422
473
  end
423
474
 
424
- it 'raises some sort of Pod4 error if it runs into problems' do
425
- expect{ interface.select('select * from not_a_table') }.
475
+ it "raises some sort of Pod4 error if it runs into problems" do
476
+ expect{ interface.select("select * from not_a_table") }.
426
477
  to raise_exception Pod4Error
427
478
 
428
479
  end
429
480
 
430
- it 'returns the result of the sql' do
431
- sql1 = 'select name from customer where qty < 2.0;'
432
- sql2 = 'select name from customer where qty < 0.0;'
481
+ it "returns the result of the sql" do
482
+ sql1 = "select name from customer where qty < 2.0;"
483
+ sql2 = "select name from customer where qty < 0.0;"
433
484
 
434
485
  expect{ interface.select(sql1) }.not_to raise_exception
435
- expect( interface.select(sql1) ).to eq( [{name: 'Barney'}] )
486
+ expect( interface.select(sql1) ).to eq( [{name: "Barney"}] )
436
487
  expect( interface.select(sql2) ).to eq( [] )
437
488
  end
438
489
 
439
- it 'works if you pass a non-select' do
490
+ it "works if you pass a non-select" do
440
491
  # By which I mean: still executes the SQL; returns []
441
- sql = 'delete from customer where qty < 2.0;'
492
+ sql = "delete from customer where qty < 2.0;"
442
493
  ret = interface.select(sql)
443
494
 
444
495
  expect( interface.list.size ).to eq(data.size - 1)
445
- expect( interface.list.map{|r| r[:name] } ).not_to include 'Barney'
496
+ expect( interface.list.map{|r| r[:name] } ).not_to include "Barney"
446
497
  expect( ret ).to eq( [] )
447
498
  end
448
499
 
449
- end
450
- ##
500
+ end # of #select
451
501
 
452
502
 
453
503
  describe "#executep" do
454
504
  # For the time being lets assume that Sequel does its job and the three modes we are calling
455
505
  # actually work
456
506
 
457
- let(:sql) { 'delete from customer where qty < ?;' }
507
+ let(:sql) { "delete from customer where qty < ?;" }
458
508
 
459
- it 'requires an SQL string and a mode' do
509
+ it "requires an SQL string and a mode" do
460
510
  expect{ interface.executep }.to raise_exception ArgumentError
461
511
  expect{ interface.executep(nil) }.to raise_exception ArgumentError
462
512
  expect{ interface.executep(14, :update) }.to raise_exception ArgumentError
463
513
  expect{ interface.executep(14, :update, 2) }.to raise_exception ArgumentError
464
514
  end
465
515
 
466
- it 'requires the mode to be valid' do
516
+ it "requires the mode to be valid" do
467
517
  expect{ interface.executep(sql, :foo, 2) }.to raise_exception ArgumentError
468
518
  end
469
519
 
470
- it 'raises some sort of Pod4 error if it runs into problems' do
471
- expect{ interface.executep('delete from not_a_table where thingy = ?', :delete, 14) }.
520
+ it "raises some sort of Pod4 error if it runs into problems" do
521
+ expect{ interface.executep("delete from not_a_table where thingy = ?", :delete, 14) }.
472
522
  to raise_exception Pod4Error
473
523
 
474
524
  end
475
525
 
476
- it 'executes the string' do
526
+ it "executes the string" do
477
527
  expect{ interface.executep(sql, :delete, 2.0) }.not_to raise_exception
478
528
  expect( interface.list.size ).to eq(data.size - 1)
479
- expect( interface.list.map{|r| r[:name] } ).not_to include 'Barney'
529
+ expect( interface.list.map{|r| r[:name] } ).not_to include "Barney"
480
530
  end
481
531
 
482
- end
532
+ end # of #executep
483
533
 
484
534
 
485
535
  describe "#selectp" do
486
536
 
487
- it 'requires an SQL string' do
537
+ it "requires an SQL string" do
488
538
  expect{ interface.selectp }.to raise_exception ArgumentError
489
539
  expect{ interface.selectp(nil) }.to raise_exception ArgumentError
490
540
  expect{ interface.selectp(14) }.to raise_exception ArgumentError
491
541
  end
492
542
 
493
- it 'raises some sort of Pod4 error if it runs into problems' do
494
- expect{ interface.selectp('select * from not_a_table where thingy = ?', 14) }.
543
+ it "raises some sort of Pod4 error if it runs into problems" do
544
+ expect{ interface.selectp("select * from not_a_table where thingy = ?", 14) }.
495
545
  to raise_exception Pod4Error
496
546
 
497
547
  end
498
548
 
499
- it 'returns the result of the sql' do
500
- sql = 'select name from customer where qty < ?;'
549
+ it "returns the result of the sql" do
550
+ sql = "select name from customer where qty < ?;"
501
551
 
502
552
  expect{ interface.selectp(sql, 2.0) }.not_to raise_exception
503
- expect( interface.selectp(sql, 2.0) ).to eq( [{name: 'Barney'}] )
553
+ expect( interface.selectp(sql, 2.0) ).to eq( [{name: "Barney"}] )
504
554
  expect( interface.selectp(sql, 0.0) ).to eq( [] )
505
555
  end
506
556
 
507
- it 'works if you pass a non-select' do
557
+ it "works if you pass a non-select" do
508
558
  # By which I mean: still executes the SQL; returns []
509
- sql = 'delete from customer where qty < ?;'
559
+ sql = "delete from customer where qty < ?;"
510
560
  ret = interface.selectp(sql, 2.0)
511
561
 
512
562
  expect( interface.list.size ).to eq(data.size - 1)
513
- expect( interface.list.map{|r| r[:name] } ).not_to include 'Barney'
563
+ expect( interface.list.map{|r| r[:name] } ).not_to include "Barney"
514
564
  expect( ret ).to eq( [] )
515
565
  end
516
566
 
517
- end
567
+ end # #selectp
568
+
569
+
570
+ #
571
+ # We'll not be testing #new_connection or #close_connection since for Sequel, they basically do
572
+ # nothing.
573
+ #
518
574
 
519
575
 
520
576
  end