pod4 0.7.1 → 0.7.2
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.
- checksums.yaml +4 -4
- data/.hgtags +1 -0
- data/Gemfile +10 -12
- data/lib/pod4/alert.rb +13 -16
- data/lib/pod4/basic_model.rb +15 -19
- data/lib/pod4/errors.rb +3 -4
- data/lib/pod4/interface.rb +25 -32
- data/lib/pod4/metaxing.rb +12 -15
- data/lib/pod4/model.rb +56 -81
- data/lib/pod4/nebulous_interface.rb +59 -74
- data/lib/pod4/null_interface.rb +8 -13
- data/lib/pod4/param.rb +2 -2
- data/lib/pod4/pg_interface.rb +42 -46
- data/lib/pod4/sequel_interface.rb +24 -36
- data/lib/pod4/tds_interface.rb +29 -37
- data/lib/pod4/typecasting.rb +7 -10
- data/lib/pod4/version.rb +1 -1
- data/lib/pod4.rb +8 -9
- data/md/fixme.md +0 -19
- data/pod4.gemspec +1 -1
- data/spec/jruby/pg_interface_spec.rb +16 -0
- data/spec/mri/pg_interface_spec.rb +13 -0
- data/spec/{common → mri}/sequel_interface_spec.rb +14 -1
- data/spec/mri/tds_interface_spec.rb +13 -0
- metadata +6 -7
data/lib/pod4/tds_interface.rb
CHANGED
@@ -13,8 +13,7 @@ module Pod4
|
|
13
13
|
##
|
14
14
|
# Pod4 Interface for requests on a SQL table via TinyTds.
|
15
15
|
#
|
16
|
-
# If your DB table is one-one with your model, you shouldn't need to override
|
17
|
-
# anything.
|
16
|
+
# If your DB table is one-one with your model, you shouldn't need to override anything.
|
18
17
|
#
|
19
18
|
# Example:
|
20
19
|
# class CustomerInterface < SwingShift::TdsInterface
|
@@ -30,9 +29,8 @@ module Pod4
|
|
30
29
|
|
31
30
|
class << self
|
32
31
|
#--
|
33
|
-
# These are set in the class because it keeps the model code cleaner: the
|
34
|
-
#
|
35
|
-
# out into the model.
|
32
|
+
# These are set in the class because it keeps the model code cleaner: the definition of the
|
33
|
+
# interface stays in the interface, and doesn't leak out into the model.
|
36
34
|
#++
|
37
35
|
|
38
36
|
|
@@ -86,23 +84,15 @@ module Pod4
|
|
86
84
|
|
87
85
|
|
88
86
|
##
|
89
|
-
# Initialise the interface by passing it a TinyTds connection hash
|
90
|
-
#
|
91
|
-
#
|
87
|
+
# Initialise the interface by passing it a TinyTds connection hash.# For testing ONLY you can
|
88
|
+
# also pass an object which pretends to be a TinyTds client, in which case the hash is pretty
|
89
|
+
# much ignored.
|
92
90
|
#
|
93
91
|
def initialize(connectHash, testClient=nil)
|
94
|
-
|
95
|
-
raise(Pod4Error, 'no call to
|
96
|
-
|
97
|
-
|
98
|
-
raise(Pod4Error, 'no call to set_table in the interface definition') \
|
99
|
-
if self.class.table.nil?
|
100
|
-
|
101
|
-
raise(Pod4Error, 'no call to set_id_fld in the interface definition') \
|
102
|
-
if self.class.id_fld.nil?
|
103
|
-
|
104
|
-
raise(ArgumentError, 'invalid connection hash') \
|
105
|
-
unless connectHash.kind_of?(Hash)
|
92
|
+
raise(Pod4Error, 'no call to set_db in the interface definition') if self.class.db.nil?
|
93
|
+
raise(Pod4Error, 'no call to set_table in the interface definition') if self.class.table.nil?
|
94
|
+
raise(Pod4Error, 'no call to set_id_fld in the interface definition') if self.class.id_fld.nil?
|
95
|
+
raise(ArgumentError, 'invalid connection hash') unless connectHash.kind_of?(Hash)
|
106
96
|
|
107
97
|
@connect_hash = connectHash.dup
|
108
98
|
@test_client = testClient
|
@@ -127,8 +117,8 @@ module Pod4
|
|
127
117
|
|
128
118
|
|
129
119
|
##
|
130
|
-
# Selection is a hash or something like it: keys should be field names. We
|
131
|
-
#
|
120
|
+
# Selection is a hash or something like it: keys should be field names. We return any records
|
121
|
+
# where the given fields equal the given values.
|
132
122
|
#
|
133
123
|
def list(selection=nil)
|
134
124
|
|
@@ -154,8 +144,9 @@ module Pod4
|
|
154
144
|
|
155
145
|
##
|
156
146
|
# Record is a hash of field: value
|
157
|
-
#
|
158
|
-
# which is just what we
|
147
|
+
#
|
148
|
+
# By a happy coincidence, insert returns the unique ID for the record, which is just what we
|
149
|
+
# want to do, too.
|
159
150
|
#
|
160
151
|
def create(record)
|
161
152
|
raise(ArgumentError, "Bad type for record parameter") \
|
@@ -190,9 +181,8 @@ module Pod4
|
|
190
181
|
Octothorpe.new( select(sql).first )
|
191
182
|
|
192
183
|
rescue => e
|
193
|
-
# select already wrapped any error in a Pod4::DatabaseError, but in this
|
194
|
-
#
|
195
|
-
# class structure is a bit poor...)
|
184
|
+
# select already wrapped any error in a Pod4::DatabaseError, but in this case we want to try
|
185
|
+
# to catch something. (Side note: TinyTds' error class structure is a bit poor...)
|
196
186
|
raise CantContinue, "Problem reading record. Is '#{id}' really an ID?" \
|
197
187
|
if e.cause.class == TinyTds::Error \
|
198
188
|
&& e.cause.message =~ /invalid column/i
|
@@ -202,8 +192,8 @@ module Pod4
|
|
202
192
|
|
203
193
|
|
204
194
|
##
|
205
|
-
# ID is whatever you set in the interface using set_id_fld
|
206
|
-
|
195
|
+
# ID is whatever you set in the interface using set_id_fld record should be a Hash or
|
196
|
+
# Octothorpe.
|
207
197
|
#
|
208
198
|
def update(id, record)
|
209
199
|
raise(ArgumentError, "Bad type for record parameter") \
|
@@ -242,15 +232,14 @@ module Pod4
|
|
242
232
|
##
|
243
233
|
# Run SQL code on the server. Return the results.
|
244
234
|
#
|
245
|
-
# Will return an array of records, or you can use it in block mode, like
|
246
|
-
# this:
|
235
|
+
# Will return an array of records, or you can use it in block mode, like this:
|
247
236
|
#
|
248
237
|
# select("select * from customer") do |r|
|
249
238
|
# # r is a single record
|
250
239
|
# end
|
251
240
|
#
|
252
|
-
# The returned results will be an array of hashes (or if you passed a
|
253
|
-
#
|
241
|
+
# The returned results will be an array of hashes (or if you passed a block, of whatever you
|
242
|
+
# returned from the block).
|
254
243
|
#
|
255
244
|
def select(sql)
|
256
245
|
raise(ArgumentError, "Bad sql parameter") unless sql.kind_of?(String)
|
@@ -323,8 +312,9 @@ module Pod4
|
|
323
312
|
|
324
313
|
##
|
325
314
|
# Close the connection to the database.
|
326
|
-
#
|
327
|
-
# caller will find it
|
315
|
+
#
|
316
|
+
# We don't actually use this, but it's here for completeness. Maybe a caller will find it
|
317
|
+
# useful.
|
328
318
|
#
|
329
319
|
def close
|
330
320
|
Pod4.logger.info(__FILE__){ "Closing connection to DB" }
|
@@ -369,8 +359,10 @@ module Pod4
|
|
369
359
|
case fld
|
370
360
|
when DateTime, Time
|
371
361
|
%Q|'#{fld.to_s[0..-7]}'|
|
372
|
-
when
|
362
|
+
when Date
|
373
363
|
%Q|'#{fld}'|
|
364
|
+
when String
|
365
|
+
%Q|'#{fld.gsub("'", "''")}'|
|
374
366
|
when BigDecimal
|
375
367
|
fld.to_f
|
376
368
|
when nil
|
@@ -386,8 +378,8 @@ module Pod4
|
|
386
378
|
raise CantContinue, "'No record found with ID '#{id}'" if read(id).empty?
|
387
379
|
end
|
388
380
|
|
389
|
-
|
390
381
|
end
|
391
382
|
|
392
383
|
|
393
384
|
end
|
385
|
+
|
data/lib/pod4/typecasting.rb
CHANGED
@@ -6,13 +6,11 @@ module Pod4
|
|
6
6
|
|
7
7
|
|
8
8
|
##
|
9
|
-
# A mixin to give you some more options to control how Pod4 maps the
|
10
|
-
# interface to the model.
|
9
|
+
# A mixin to give you some more options to control how Pod4 maps the interface to the model.
|
11
10
|
#
|
12
|
-
# Eventually we will actually have typecasting in here. For now all this
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# the code page poorly:
|
11
|
+
# Eventually we will actually have typecasting in here. For now all this allows you to do is
|
12
|
+
# enforce an encoding -- which will be of use if you are dealing with MSSQL, or with certain
|
13
|
+
# interfaces which appear to deal with the code page poorly:
|
16
14
|
#
|
17
15
|
# class FOo < Pod4::Model
|
18
16
|
# include Pod4::TypeCasting
|
@@ -27,10 +25,9 @@ module Pod4
|
|
27
25
|
##
|
28
26
|
# A little bit of magic, for which I apologise.
|
29
27
|
#
|
30
|
-
# When you include this module it actually adds the methods in ClassMethods
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# TypeCasting::InstanceMethods`.
|
28
|
+
# When you include this module it actually adds the methods in ClassMethods to the class as if
|
29
|
+
# you had called `extend TypeCasting:ClassMethds` *AND* adds the methods in InstanceMethods as
|
30
|
+
# if you had written `prepend TypeCasting::InstanceMethods`.
|
34
31
|
#
|
35
32
|
# In my defence: I didn't want to have to make you remember to do that...
|
36
33
|
#
|
data/lib/pod4/version.rb
CHANGED
data/lib/pod4.rb
CHANGED
@@ -11,22 +11,21 @@ require_relative 'pod4/alert'
|
|
11
11
|
##
|
12
12
|
# Pod4, which:
|
13
13
|
#
|
14
|
-
# * will gather data from absolutely anything. Nebulous, Sequel, Pg,
|
15
|
-
#
|
14
|
+
# * will gather data from absolutely anything. Nebulous, Sequel, Pg, TinyTds, whatever. Add your
|
15
|
+
# own on the fly.
|
16
16
|
#
|
17
|
-
# * will allow you to define models which are genuinely represent the data
|
18
|
-
#
|
17
|
+
# * will allow you to define models which are genuinely represent the data your way, not the way
|
18
|
+
# the data source sees it.
|
19
19
|
#
|
20
|
-
# * is hopefully simple and clean; just a very light helper layer with the
|
21
|
-
#
|
20
|
+
# * is hopefully simple and clean; just a very light helper layer with the absolute minimum of
|
21
|
+
# magic or surprises for the developer.
|
22
22
|
#
|
23
23
|
# For more information:
|
24
24
|
#
|
25
25
|
# * There is a short tutorial in the readme.
|
26
26
|
#
|
27
|
-
# * you should look at the contract Pod4 makes with its
|
28
|
-
#
|
29
|
-
# and Pod4::Model.
|
27
|
+
# * you should look at the contract Pod4 makes with its callers -- you should find all that you
|
28
|
+
# need in the classes Pod4::Interface and Pod4::Model.
|
30
29
|
#
|
31
30
|
# * Or, read the tests, of course.
|
32
31
|
#
|
data/md/fixme.md
CHANGED
@@ -1,22 +1,3 @@
|
|
1
1
|
Things I Wish I Could Do
|
2
2
|
========================
|
3
3
|
|
4
|
-
* TinyTds gem fails to cast date fields as date. Nothing we can do about that,
|
5
|
-
AFAICS.
|
6
|
-
|
7
|
-
|
8
|
-
Things To Do
|
9
|
-
============
|
10
|
-
|
11
|
-
* I had a note here on how SequelInterface does not support the table and
|
12
|
-
quoted_table variables. Well, these definitely aren't part of the contract:
|
13
|
-
how would NebulousInterface support them? But there might be an issue with
|
14
|
-
passing selection parameters to SequelInterface.list if the schema is set. We
|
15
|
-
need to tie down a test for that and fix it if it exists.
|
16
|
-
|
17
|
-
* TinyTDS just updated to 1.0 and ... fell over. We need to work out what's
|
18
|
-
going on there.
|
19
|
-
|
20
|
-
* Ideally interfaces should support parameterised insertion. Ideally in a
|
21
|
-
manner consistent for all interfaces...
|
22
|
-
|
data/pod4.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.extra_rdoc_files = spec.files.grep(%r{^md/})
|
26
26
|
|
27
27
|
spec.add_runtime_dependency "devnull", '~>0.1'
|
28
|
-
spec.add_runtime_dependency "octothorpe", '~>0.
|
28
|
+
spec.add_runtime_dependency "octothorpe", '~>0.3'
|
29
29
|
|
30
30
|
=begin
|
31
31
|
# for bundler, management, etc etc
|
@@ -1,3 +1,6 @@
|
|
1
|
+
# This is a copy of spec/mri/pg_interface_spec.rb; you can use it to judge
|
2
|
+
# whether pg_jruby is currently a good drop-in replacement for pg... :(
|
3
|
+
|
1
4
|
require 'pod4/pg_interface'
|
2
5
|
require 'pg'
|
3
6
|
|
@@ -219,6 +222,13 @@ describe TestPgInterface do
|
|
219
222
|
expect( interface.read(id).to_h ).to include(record)
|
220
223
|
end
|
221
224
|
|
225
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
226
|
+
record = {name: %Q|T'Challa""|, price: nil}
|
227
|
+
expect{ interface.create(record) }.not_to raise_exception
|
228
|
+
id = interface.create(record)
|
229
|
+
expect( interface.read(id).to_h ).to include(record)
|
230
|
+
end
|
231
|
+
|
222
232
|
end
|
223
233
|
##
|
224
234
|
|
@@ -353,6 +363,12 @@ describe TestPgInterface do
|
|
353
363
|
expect( interface.read(id).to_h ).to include(record)
|
354
364
|
end
|
355
365
|
|
366
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
367
|
+
record = {name: %Q|T'Challa""|, price: nil}
|
368
|
+
expect{ interface.update(id, record) }.not_to raise_exception
|
369
|
+
expect( interface.read(id).to_h ).to include(record)
|
370
|
+
end
|
371
|
+
|
356
372
|
end
|
357
373
|
##
|
358
374
|
|
@@ -219,6 +219,13 @@ describe TestPgInterface do
|
|
219
219
|
expect( interface.read(id).to_h ).to include(record)
|
220
220
|
end
|
221
221
|
|
222
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
223
|
+
record = {name: %Q|T'Challa""|, price: nil}
|
224
|
+
expect{ interface.create(record) }.not_to raise_exception
|
225
|
+
id = interface.create(record)
|
226
|
+
expect( interface.read(id).to_h ).to include(record)
|
227
|
+
end
|
228
|
+
|
222
229
|
end
|
223
230
|
##
|
224
231
|
|
@@ -353,6 +360,12 @@ describe TestPgInterface do
|
|
353
360
|
expect( interface.read(id).to_h ).to include(record)
|
354
361
|
end
|
355
362
|
|
363
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
364
|
+
record = {name: %Q|T'Challa""|, price: nil}
|
365
|
+
expect{ interface.update(id, record) }.not_to raise_exception
|
366
|
+
expect( interface.read(id).to_h ).to include(record)
|
367
|
+
end
|
368
|
+
|
356
369
|
end
|
357
370
|
##
|
358
371
|
|
@@ -5,7 +5,7 @@ require 'date'
|
|
5
5
|
require 'time'
|
6
6
|
require 'bigdecimal'
|
7
7
|
|
8
|
-
require_relative 'shared_examples_for_interface'
|
8
|
+
require_relative '../common/shared_examples_for_interface'
|
9
9
|
|
10
10
|
|
11
11
|
class TestSequelInterface < SequelInterface
|
@@ -238,6 +238,13 @@ describe TestSequelInterface do
|
|
238
238
|
expect( interface.read(id).to_h ).to include(record)
|
239
239
|
end
|
240
240
|
|
241
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
242
|
+
record = {name: "T'Challa[]", price: nil}
|
243
|
+
expect{ interface.create(record) }.not_to raise_exception
|
244
|
+
id = interface.create(record)
|
245
|
+
expect( interface.read(id).to_h ).to include(record)
|
246
|
+
end
|
247
|
+
|
241
248
|
end
|
242
249
|
##
|
243
250
|
|
@@ -372,6 +379,12 @@ describe TestSequelInterface do
|
|
372
379
|
expect( interface.read(id).to_h ).to include(record)
|
373
380
|
end
|
374
381
|
|
382
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
383
|
+
record = {name: "T'Challa[]", price: nil}
|
384
|
+
expect{ interface.update(id, record) }.not_to raise_exception
|
385
|
+
expect( interface.read(id).to_h ).to include(record)
|
386
|
+
end
|
387
|
+
|
375
388
|
end
|
376
389
|
##
|
377
390
|
|
@@ -259,6 +259,13 @@ describe TestTdsInterface do
|
|
259
259
|
expect( interface.read(id).to_h ).to include(hash2)
|
260
260
|
end
|
261
261
|
|
262
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
263
|
+
hash2 = {name: "T'Challa[]", price: nil}
|
264
|
+
expect{ interface.create(hash2) }.not_to raise_exception
|
265
|
+
id = interface.create(hash2)
|
266
|
+
expect( interface.read(id).to_h ).to include(hash2)
|
267
|
+
end
|
268
|
+
|
262
269
|
end
|
263
270
|
##
|
264
271
|
|
@@ -394,6 +401,12 @@ describe TestTdsInterface do
|
|
394
401
|
expect( interface.read(id).to_h ).to include(record)
|
395
402
|
end
|
396
403
|
|
404
|
+
it 'shouldnt have a problem with strings containing special characters' do
|
405
|
+
record = {name: "T'Challa[]", price: nil}
|
406
|
+
expect{ interface.update(id, record) }.not_to raise_exception
|
407
|
+
expect( interface.read(id).to_h ).to include(record)
|
408
|
+
end
|
409
|
+
|
397
410
|
end
|
398
411
|
##
|
399
412
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pod4
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Jones
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devnull
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
33
|
+
version: '0.3'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0.
|
40
|
+
version: '0.3'
|
41
41
|
description: |
|
42
42
|
Provides a simple, common framework to talk to a bunch of data sources,
|
43
43
|
using model classes which consist of a bare minimum of DSL plus vanilla Ruby
|
@@ -85,13 +85,13 @@ files:
|
|
85
85
|
- spec/common/null_interface_spec.rb
|
86
86
|
- spec/common/param_spec.rb
|
87
87
|
- spec/common/pod4_spec.rb
|
88
|
-
- spec/common/sequel_interface_spec.rb
|
89
88
|
- spec/common/shared_examples_for_interface.rb
|
90
89
|
- spec/common/spec_helper.rb
|
91
90
|
- spec/doc_no_pending.rb
|
92
91
|
- spec/fixtures/database.rb
|
93
92
|
- spec/jruby/pg_interface_spec.rb
|
94
93
|
- spec/mri/pg_interface_spec.rb
|
94
|
+
- spec/mri/sequel_interface_spec.rb
|
95
95
|
- spec/mri/tds_interface_spec.rb
|
96
96
|
- spec/spec_helper.rb
|
97
97
|
- tags
|
@@ -129,13 +129,12 @@ test_files:
|
|
129
129
|
- spec/common/null_interface_spec.rb
|
130
130
|
- spec/common/param_spec.rb
|
131
131
|
- spec/common/pod4_spec.rb
|
132
|
-
- spec/common/sequel_interface_spec.rb
|
133
132
|
- spec/common/shared_examples_for_interface.rb
|
134
133
|
- spec/common/spec_helper.rb
|
135
134
|
- spec/doc_no_pending.rb
|
136
135
|
- spec/fixtures/database.rb
|
137
136
|
- spec/jruby/pg_interface_spec.rb
|
138
137
|
- spec/mri/pg_interface_spec.rb
|
138
|
+
- spec/mri/sequel_interface_spec.rb
|
139
139
|
- spec/mri/tds_interface_spec.rb
|
140
140
|
- spec/spec_helper.rb
|
141
|
-
has_rdoc:
|