pod4 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.hgignore +1 -0
- data/.hgtags +1 -0
- data/Gemfile +3 -1
- data/Rakefile +17 -5
- data/lib/pod4/pg_interface.rb +81 -57
- data/lib/pod4/sequel_interface.rb +61 -6
- data/lib/pod4/sql_helper.rb +229 -0
- data/lib/pod4/tds_interface.rb +65 -50
- data/lib/pod4/version.rb +1 -1
- data/md/roadmap.md +81 -25
- data/spec/common/basic_model_spec.rb +5 -0
- data/spec/common/model_spec.rb +49 -7
- data/spec/common/nebulous_interface_spec.rb +2 -0
- data/spec/common/sequel_interface_pg_spec.rb +511 -0
- data/spec/common/sql_helper_spec.rb +299 -0
- data/spec/jruby/sequel_interface_jdbc_ms_spec.rb +525 -0
- data/spec/jruby/sequel_interface_jdbc_pg_spec.rb +520 -0
- data/spec/mri/pg_interface_spec.rb +140 -16
- data/spec/mri/sequel_interface_spec.rb +146 -13
- data/spec/mri/tds_interface_spec.rb +82 -12
- metadata +11 -4
- data/spec/jruby/pg_interface_spec.rb +0 -469
@@ -0,0 +1,299 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'pod4/sql_helper'
|
5
|
+
|
6
|
+
class SQLHelperTester1
|
7
|
+
include SQLHelper
|
8
|
+
|
9
|
+
def schema; "marco"; end
|
10
|
+
def table; "polo"; end
|
11
|
+
def id_fld; "foo"; end
|
12
|
+
end
|
13
|
+
|
14
|
+
class SQLHelperTester2
|
15
|
+
include SQLHelper
|
16
|
+
|
17
|
+
def table; "polo"; end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe "SQLHelper" do
|
22
|
+
|
23
|
+
let(:tester1) {SQLHelperTester1.new}
|
24
|
+
let(:tester2) {SQLHelperTester2.new}
|
25
|
+
|
26
|
+
|
27
|
+
describe "quoted_table" do
|
28
|
+
|
29
|
+
it "will be quoted with double quotes" do
|
30
|
+
expect( tester2.quoted_table ).to eq %Q|"polo"|
|
31
|
+
end
|
32
|
+
|
33
|
+
it "will the schema plus the table if the schema is set" do
|
34
|
+
expect( tester1.quoted_table ).to eq %Q|"marco"."polo"|
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
describe "placeholder" do
|
41
|
+
|
42
|
+
it "will be the ruby sprintf string subst string" do
|
43
|
+
expect( tester1.send :placeholder ).to eq "%s"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
describe "quote_field" do
|
50
|
+
|
51
|
+
it "will wrap the field in double quotes" do
|
52
|
+
expect( tester1.send :quote_field, "thing" ).to eq %Q|"thing"|
|
53
|
+
end
|
54
|
+
|
55
|
+
it "will raise an error for a non-string" do
|
56
|
+
expect{ tester1.send :quote_field, 12 }.to raise_error ArgumentError
|
57
|
+
expect{ tester1.send :quote_field }.to raise_error ArgumentError
|
58
|
+
end
|
59
|
+
|
60
|
+
it "will wrap the field in some other character if you pass that" do
|
61
|
+
expect( tester1.send :quote_field, "thing", nil ).to eq %Q|thing|
|
62
|
+
expect( tester1.send :quote_field, "thing", "x" ).to eq %Q|xthingx|
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
describe "quote" do
|
69
|
+
let(:datetime) { "2055-12-31 11:23:36+04" }
|
70
|
+
let(:dtmatch) { /'2055.12.31[T ]11.23.36 ?\+04:?00'/ }
|
71
|
+
|
72
|
+
it "returns a String wrapped in single quotes" do
|
73
|
+
expect( tester1.send :quote, "foo" ).to eq %Q|'foo'|
|
74
|
+
end
|
75
|
+
|
76
|
+
it "turns a single quote into a doubled single quote" do
|
77
|
+
expect( tester1.send :quote, "G'Kar" ).to eq %Q|'G''Kar'|
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns date wrapped in a single quote" do
|
81
|
+
dt = Date.parse("2055-12-31")
|
82
|
+
expect( tester1.send :quote, dt ).to eq %Q|'2055-12-31'|
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns datetime wrapped in a single quote" do
|
86
|
+
dtm = DateTime.parse(datetime)
|
87
|
+
expect( tester1.send :quote, dtm ).to match dtmatch
|
88
|
+
end
|
89
|
+
|
90
|
+
it "returns time wrapped in a single quote" do
|
91
|
+
tm = Time.parse(datetime)
|
92
|
+
expect( tester1.send :quote, tm ).to match dtmatch
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns a BigDecimal as a float" do
|
96
|
+
bd = BigDecimal.new("14.98")
|
97
|
+
expect( tester1.send :quote, bd ).to eq 14.98
|
98
|
+
end
|
99
|
+
|
100
|
+
it "returns nil as 'NULL'" do
|
101
|
+
expect( tester1.send :quote, nil ).to eq %Q|NULL|
|
102
|
+
end
|
103
|
+
|
104
|
+
it "will wrap the value in some other character if you pass that" do
|
105
|
+
bd = BigDecimal.new("14.98")
|
106
|
+
expect( tester1.send :quote, "thing", nil ).to eq %Q|thing|
|
107
|
+
expect( tester1.send :quote, "thing", "x" ).to eq %Q|xthingx|
|
108
|
+
expect( tester1.send :quote, bd ).to eq 14.98
|
109
|
+
expect( tester1.send :quote, "G'Kar", "a" ).to eq %Q|aG'Kaara|
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
describe "sql_where(selection)" do
|
116
|
+
|
117
|
+
it "returns an empty string and empty array for an empty selection hash" do
|
118
|
+
expect( tester1.send :sql_where, {} ).to eq( [ "", [] ] )
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
it "returns valid SQL and unchanged array of values for the selection hash" do
|
123
|
+
sql, vals = tester1.send :sql_where, {lambs: "baah", pigs: "moo"}
|
124
|
+
|
125
|
+
expect( sql ).to match %r|where\s+"lambs"\s*=\s*%s\s+and\s+"pigs"\s*=\s*%s|i
|
126
|
+
expect( vals ).to eq( [%q|baah|, %q|moo|] )
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
describe "sql_select" do
|
133
|
+
|
134
|
+
it "returns sql plus an array of values" do
|
135
|
+
sql, vals = tester1.send( :sql_select, %W|foo bar|, {one: 12} )
|
136
|
+
smatch = %r|select\s+"foo",\s*"bar"\s+from\s+"marco"\."polo"\s+where\s+"one"\s*=\s*%s\s*;|i
|
137
|
+
|
138
|
+
expect(sql).to match(smatch)
|
139
|
+
expect(vals).to eq( [12] )
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
it "copes with nil for fields to select *" do
|
144
|
+
sql, vals = tester1.send( :sql_select, nil, {one: 12} )
|
145
|
+
smatch = %r|select\s+\*\s*from\s+"marco"\."polo"\s*where\s+"one"\s*=\s*%s\s*;|
|
146
|
+
|
147
|
+
expect(sql).to match(smatch)
|
148
|
+
expect(vals).to eq( [12] )
|
149
|
+
end
|
150
|
+
|
151
|
+
it "copes with one field" do
|
152
|
+
sql, vals = tester1.send( :sql_select, "foo", {one: 12} )
|
153
|
+
smatch = %r|select\s+"foo"\s+from\s+"marco"\."polo"\s+where\s+"one"\s*=\s*%s\s*;|i
|
154
|
+
|
155
|
+
expect(sql).to match(smatch)
|
156
|
+
expect(vals).to eq( [12] )
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
it "copes with a selection list" do
|
161
|
+
sql, vals = tester1.send( :sql_select, nil, {one: 12, two: 23} )
|
162
|
+
smatch = %r|select\s+\*\s*from\s+"marco"\."polo"
|
163
|
+
\s+where\s+"one"\s*=\s*%s\s+and\s+"two"\s*=\s*%s\s*;|ix
|
164
|
+
|
165
|
+
expect(sql).to match(smatch)
|
166
|
+
expect(vals).to eq( [12,23] )
|
167
|
+
end
|
168
|
+
|
169
|
+
it "copes with no selection list" do
|
170
|
+
sql, vals = tester1.send( :sql_select, nil, nil )
|
171
|
+
smatch = %r|select\s+\*\s*from\s+"marco"\."polo"\s*;|i
|
172
|
+
|
173
|
+
expect(sql).to match(smatch)
|
174
|
+
expect(vals).to eq( [] )
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
describe "sql_insert" do
|
181
|
+
|
182
|
+
it "raises an exception if there is no column:value hash" do
|
183
|
+
expect{ tester1.send :sql_insert, {} }.to raise_error ArgumentError
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns the correct sql plus an array of values" do
|
187
|
+
sel = {bada: "bing", bar: "foop"}
|
188
|
+
smatch = %r|insert\s+into\s+"marco"\."polo"
|
189
|
+
\s+\(\s*"bada",\s*"bar"\s*\)
|
190
|
+
\s+values\(\s*%s,\s*%s\s*\)
|
191
|
+
\s+returning\s+"foo"\s*;|xi
|
192
|
+
|
193
|
+
sql, vals = tester1.send :sql_insert, sel
|
194
|
+
|
195
|
+
expect(sql).to match smatch
|
196
|
+
expect(vals).to eq( ['bing', 'foop'] )
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
describe "sql_update" do
|
203
|
+
|
204
|
+
it "raises an exception if there is no column:value hash" do
|
205
|
+
expect{ tester1.send :sql_update, {}, {} }.to raise_error ArgumentError
|
206
|
+
end
|
207
|
+
|
208
|
+
it "returns the correct SQL and values without a selection hash" do
|
209
|
+
fv = {mouse: 14, rat: "meow"}
|
210
|
+
|
211
|
+
smatch = %r|update\s+"marco"\."polo"\s+set
|
212
|
+
\s+"mouse"\s*=\s*%s\s*,
|
213
|
+
\s+"rat"\s*=\s*%s\s*;|xi
|
214
|
+
|
215
|
+
sql, vals = tester1.send :sql_update, fv, {}
|
216
|
+
|
217
|
+
expect(sql).to match smatch
|
218
|
+
expect(vals).to eq( [14, 'meow'] )
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
it "returns the correct SQL and values if there is a selection hash" do
|
223
|
+
fv = {mouse: 14, rat: "meow"}
|
224
|
+
sel = {row: 5, column: true}
|
225
|
+
|
226
|
+
smatch = %r|update\s+"marco"\."polo"\s+set
|
227
|
+
\s+"mouse"\s*=\s*%s\s*,
|
228
|
+
\s+"rat"\s*=\s*%s
|
229
|
+
\s+where\s+"row"\s*=\s*%s\s+and\s+"column"\s*=\s*%s\s*;|xi
|
230
|
+
|
231
|
+
sql, vals = tester1.send :sql_update, fv, sel
|
232
|
+
|
233
|
+
expect(sql).to match smatch
|
234
|
+
expect(vals).to eq( [14, 'meow', 5, true] )
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
describe "sql_delete(selection)" do
|
241
|
+
|
242
|
+
it "returns the correct SQL and values without a selection hash" do
|
243
|
+
sql, vals = tester1.send :sql_delete, {}
|
244
|
+
|
245
|
+
expect(sql).to match %r|delete\s+from\s+"marco"\."polo"\s*;|i
|
246
|
+
expect(vals).to eq( [] )
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
it "returns the correct SQL and values if there is a selection hash" do
|
251
|
+
sql, vals = tester1.send :sql_delete, {alice: 14, ted: "moo"}
|
252
|
+
smatch = %r|delete\s+from\s+"marco"\."polo"
|
253
|
+
\s+where\s+"alice"\s*=\s*%s\s+and\s+"ted"\s*=\s*%s\s*;|ix
|
254
|
+
|
255
|
+
expect(sql).to match smatch
|
256
|
+
expect(vals).to eq( [14, 'moo'] )
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
describe "sql_subst" do
|
263
|
+
|
264
|
+
it "raises ArgumentError unless it receives an SQL string" do
|
265
|
+
expect{ tester1.send :sql_subst, 19, "foo" }.to raise_error ArgumentError
|
266
|
+
end
|
267
|
+
|
268
|
+
it "returns the sql untouched when there are no values" do
|
269
|
+
expect( tester1.send :sql_subst, "foo" ).to eq "foo"
|
270
|
+
end
|
271
|
+
|
272
|
+
it "raises ArgumentError if the sql is blank" do
|
273
|
+
expect{ tester1.send :sql_subst, "", 'foo' }.to raise_error ArgumentError
|
274
|
+
end
|
275
|
+
|
276
|
+
it "raises ArgumentError if the # of sql markers and the # of values don't match" do
|
277
|
+
# (unless we only pass one value, see below)
|
278
|
+
expect{ tester1.send :sql_subst, %q|foo %s %s bar %s|, 1, 2 }.to raise_error ArgumentError
|
279
|
+
expect{ tester1.send :sql_subst, %q|foo %s bar %s|, 1, 2, 3 }.to raise_error ArgumentError
|
280
|
+
end
|
281
|
+
|
282
|
+
it "returns complete SQL for sql with markers and a single value" do
|
283
|
+
sql = %q|select * from "foo" where "bar" = %s and "baz" = %s;|
|
284
|
+
seq = %q|select * from "foo" where "bar" = 'boing' and "baz" = 'boing';|
|
285
|
+
|
286
|
+
expect( tester1.send :sql_subst, sql, %q|'boing'| ).to eq seq
|
287
|
+
end
|
288
|
+
|
289
|
+
it "returns complete SQL for sql with markers and the right number of values in the array" do
|
290
|
+
sql = %q|select * from "foo" where "bar" = %s and "baz" = %s;|
|
291
|
+
seq = %q|select * from "foo" where "bar" = 'boing' and "baz" = 'bop';|
|
292
|
+
|
293
|
+
expect( tester1.send :sql_subst, sql, %q|'boing'|, %q|'bop'| ).to eq seq
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
|