quote-sql 0.0.6 → 0.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e308b3aef586983a61155c9ba3be6c39c2397fa5fbae069ab45522e51681caa
4
- data.tar.gz: 6a3945e1a4cfc16fed91c46216d1a10c5a69e85a6b3a0df10db45a9f162c07eb
3
+ metadata.gz: cfe070af9a81f751ed10ef8ace30bf5e44a3efb54cff04f2eb5cc137b7fbc0f1
4
+ data.tar.gz: 8c8ec59ca80a8c72ceee6567da4beb5f79c96a63e16d945694fed26ea695feca
5
5
  SHA512:
6
- metadata.gz: 3ce751f52d51a6b7b989062673f9c849b5a8b44e5e4227f0f453290d41b20856b45f0d0bbddd6cea6f5256405b313d82367a27fdd2381dd2b37f27c3ac3442e6
7
- data.tar.gz: 2656c2cbacc7375fd22f2148d4a929fbba1822c97b61467bdf5794c7bcf78b75d5ba4a9bfb90a6f01b282479bad95c77d354ca2211a6f3561a6eaa60e9d90db4
6
+ metadata.gz: 03d69b9b3256cd22762844dc98c31ce2223c673079488d7175078dd82406d8031673368871a2a920ecda17ea68beb79c87f3208d56b1e770c4ba15583fafc648
7
+ data.tar.gz: b6d9f335cdcaf0e597f3118090451059220ebd9e540eda483f546301ad148bfebc35150a73a72c6dc54a39f537e8aa9b854970a975218226a26af3ed6add75c0
data/README.md CHANGED
@@ -26,7 +26,7 @@ Best Martin
26
26
  `QuoteSql.new("SELECT %field").quote(field: "abc").to_sql`
27
27
  => SELECT 'abc'
28
28
 
29
- `QuoteSql.new("SELECT %field__text").quote(field__text: 9).to_sql`
29
+ `QuoteSql.new("SELECT %field::TEXT").quote(field: 9).to_sql`
30
30
  => SELECT 9::TEXT
31
31
 
32
32
  ### Rails models
@@ -58,11 +58,8 @@ Values are be ordered in sequence of columns. Missing value entries are substitu
58
58
  ON CONFLICT ("id") DO NOTHING
59
59
 
60
60
  ### Columns from a list
61
- `QuoteSql.new("SELECT %columns").quote(columns: [:a, "b.c", d: {e: field}]).to_sql`
62
- => SELECT "a","b"."c",jsonb_build_object('e', field) AS d
63
-
64
- `QuoteSql.new("SELECT %columns").quote(columns: [:a, "b.c", d: {e: field, nil: false}]).to_sql`
65
- => SELECT "a","b"."c",jsonb_strip_nulls(jsonb_build_object('e', 1)) AS d
61
+ `QuoteSql.new("SELECT %columns FROM %table").quote(table: "foo", columns: [:a, "b", "foo.c", {d: :e}]).to_sql`
62
+ => SELECT "foo"."a","b"."foo"."c", "foo"."e" AS d
66
63
 
67
64
  ## Executing
68
65
  ### Getting the results
@@ -72,6 +69,7 @@ Values are be ordered in sequence of columns. Missing value entries are substitu
72
69
  ### Binds
73
70
  You can use binds ($1, $2, ...) in the SQL and add arguments to the result call
74
71
  `QuoteSql.new('SELECT $1 AS a').result(1)`
72
+ => [{:a=>1}]
75
73
 
76
74
  #### using JSON
77
75
 
@@ -111,10 +109,8 @@ All can be preceded by additional letters and underscore e.g. `%foo_bar_column`
111
109
  A database typecast is added to fields ending with double underscore and a valid db data type
112
110
  with optional array dimension
113
111
 
114
- - `%field__jsonb` => adds a `::JSONB` typecast to the field
115
- - `%number_to__text` => adds a `::TEXT` typecast to the field
116
- - `%array__text1` => adds a `::TEXT[]` (TO BE IMPLEMENTED)
117
- - `%array__text2` => adds a `::TEXT[][]` (TO BE IMPLEMENTED)
112
+ - `%field::jsonb` => treats the field as jsonb when casted
113
+ - `%array::text[]` => treats an array like a text array, default is JSONB
118
114
 
119
115
  ### Quoting
120
116
  - Any value of the standard mixins are quoted with these exceptions
@@ -1,3 +1,4 @@
1
+ require 'niceql'
1
2
  class QuoteSql
2
3
  module Formater
3
4
  PG_FORMAT_BIN = `which pg_format`.chomp.presence
@@ -9,15 +10,14 @@ class QuoteSql
9
10
 
10
11
  def to_formatted_sql
11
12
  sql = respond_to?(:to_sql) ? to_sql : to_s
12
- Niceql::Prettifier.prettify_sql(sql)
13
+ Niceql::Prettifier.prettify_sql(sql.gsub(/(?<=[^%])%(?=\S)/, "%%"))
13
14
 
14
15
  # IO.popen(PG_FORMAT_BIN, "r+", err: "/dev/null") do |f|
15
16
  # f.write(sql)
16
17
  # f.close_write
17
18
  # f.read
18
19
  # end
19
- rescue
20
- sql
20
+
21
21
  end
22
22
 
23
23
  alias to_sqf to_formatted_sql
@@ -1,12 +1,12 @@
1
1
  class QuoteSql
2
2
  class Quoter
3
- def initialize(qsql, key, quotable)
3
+ def initialize(qsql, key, cast, quotable)
4
4
  @qsql = qsql
5
- @key, @quotable = key, quotable
5
+ @key, @cast, @quotable = key, cast, quotable
6
6
  @name = key.sub(/_[^_]+$/, '') if key["_"]
7
7
  end
8
8
 
9
- attr_reader :key, :quotable, :name
9
+ attr_reader :key, :quotable, :name, :cast
10
10
 
11
11
  def quotes
12
12
  @qsql.quotes
@@ -227,42 +227,65 @@ class QuoteSql
227
227
  end
228
228
  end
229
229
 
230
- def cast
231
- if m = key.to_s[CASTS]
232
- m[2..].sub(CASTS) { _1.tr("_", " ") }
233
- end
234
- end
235
-
236
- def json?
237
- !!key[/(^|_)(jsonb?)$/]
230
+ def json?(cast = self.cast)
231
+ cast.to_s[/jsonb?$/i]
238
232
  end
239
233
 
240
- private def _quote(item = @quotable, cast = self.cast)
241
- rv = QuoteSql.quote(item)
242
- if cast
243
- rv << "::#{cast.upcase}"
244
- rv << "[]" * rv.depth if rv[/^ARRAY/]
245
- end
246
- Raw.sql rv
234
+ private def _quote(item = @quotable)
235
+ Raw.sql QuoteSql.quote(item)
247
236
  end
248
237
 
249
238
  private def _quote_column_name(name)
250
239
  Raw.sql name.scan(/(?:^|")?([^."]+)/).map { QuoteSql.quote_column_name _1 }.join(".")
251
240
  end
252
241
 
253
- def quote(item = @quotable)
254
- case item.class.to_s
255
- when "Arel::Nodes::SqlLiteral", "QuoteSql::Raw"
256
- return Raw.sql(item)
257
- when "Array"
258
- return _quote(item.to_json) if json?
259
- _quote(item)
260
- when "Hash"
261
- _quote(item.to_json, :jsonb)
262
- else
263
- return Raw.sql item.to_sql if item.respond_to? :to_sql
264
- _quote(item)
242
+ private def _quote_array(items)
243
+ rv = items.map do |i|
244
+ if i.is_a?(Array)
245
+ _quote_array(i)
246
+ elsif self.cast[/jsonb?/i]
247
+ _quote(i.to_json)
248
+ else
249
+ quote(i)
250
+ end
265
251
  end
252
+ "[#{rv.join(",")}]"
253
+ end
254
+
255
+ def quote_hash(item)
256
+ item.compact! if item.delete(nil) == false
257
+ case self.cast
258
+ when /hstore/i
259
+ _quote(item.map { "#{_1}=>#{_2.nil? ? 'NULL' : _2}"}.join(","))
260
+ when NilClass,""
261
+ "#{_quote(item.to_json)}::JSONB"
262
+ when /jsonb?/i
263
+ _quote(item.to_json)
264
+ end
265
+ end
266
+
267
+ def quote(item = @quotable, cast = nil)
268
+ Raw.sql case item.class.to_s
269
+ when "Arel::Nodes::SqlLiteral", "QuoteSql::Raw"
270
+ item
271
+ when "Array"
272
+ if json? or self.cast.blank?
273
+ rv = _quote(item.to_json)
274
+ self.cast.present? ? rv : "#{rv}::JSONB"
275
+ else
276
+ "ARRAY#{_quote_array(item)}"
277
+ end
278
+ when "Hash"
279
+ quote_hash(item)
280
+ else
281
+ if item.respond_to? :to_sql
282
+ item.to_sql
283
+ elsif json?
284
+ _quote(item.to_json)
285
+ else
286
+ _quote(item)
287
+ end
288
+ end
266
289
  end
267
290
 
268
291
  def column_names(item = @quotable)
@@ -1,5 +1,6 @@
1
1
  class QuoteSql::Test
2
2
  private
3
+
3
4
  def test_columns
4
5
  expected <<~SQL
5
6
  SELECT x, "a", "b", "c", "d"
@@ -124,29 +125,59 @@ class QuoteSql::Test
124
125
  expected <<~SQL
125
126
  SELECT * FROM json_to_recordset('[{"a":1,"b":"foo"},{"a":"2"}]') as "x" ("a" int, "b" text)
126
127
  SQL
127
- "SELECT * FROM %x_json".quote_sql(x_casts: {a: "int", b: "text"}, x_json: [{ a: 1, b: 'foo'}, {a: '2', c: 'bar'}])
128
+ "SELECT * FROM %x_json".quote_sql(x_casts: { a: "int", b: "text" }, x_json: [{ a: 1, b: 'foo' }, { a: '2', c: 'bar' }])
128
129
  end
129
130
 
130
131
  def test_json_insert
131
132
  expected <<~SQL
132
- INSERT INTO users (name, color) SELECT * from json_to_recordset('[{"name":"auge","color":"#611333"}]') AS "x"("name" text,"color" text)
133
+ INSERT INTO users (name, color) SELECT * from json_to_recordset('[{"name":"auge","color":"#611333"}]') AS "x"("name" text,"color" text)
133
134
  SQL
134
- x_json = {"first_name"=>nil, "last_name"=>nil, "stripe_id"=>nil, "credits"=>nil, "avatar"=>nil, "name"=>"auge", "color"=>"#611333", "founder"=>nil, "language"=>nil, "country"=>nil, "data"=>{}, "created_at"=>"2020-11-19T09:30:18.670Z", "updated_at"=>"2020-11-19T09:40:00.063Z"}
135
- "INSERT INTO users (name, color) SELECT * from %x_json".quote_sql(x_casts: {name: "text", color: "text"}, x_json:)
135
+ x_json = { "first_name" => nil, "last_name" => nil, "stripe_id" => nil, "credits" => nil, "avatar" => nil, "name" => "auge", "color" => "#611333", "founder" => nil, "language" => nil, "country" => nil, "data" => {}, "created_at" => "2020-11-19T09:30:18.670Z", "updated_at" => "2020-11-19T09:40:00.063Z" }
136
+ "INSERT INTO users (name, color) SELECT * from %x_json".quote_sql(x_casts: { name: "text", color: "text" }, x_json:)
136
137
  end
137
138
 
138
139
  def test_from_json_bind
139
140
  expected <<~SQL
140
- Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean)
141
+ Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean)
141
142
  SQL
142
- QuoteSQL("Select * From %x_json", x_json: 1, x_casts: {a: "int", b: "text", c: "boolean"})
143
+ QuoteSQL("Select * From %x_json", x_json: 1, x_casts: { a: "int", b: "text", c: "boolean" })
143
144
  end
144
145
 
145
146
  def test_insert_json_bind
146
147
  expected <<~SQL
147
- INSERT INTO table ("a","b","c") Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean)
148
+ INSERT INTO table ("a","b","c") Select * From json_to_recordset($1) AS "x"("a" int,"b" text,"c" boolean)
149
+ SQL
150
+ QuoteSQL("INSERT INTO table (%x_columns) Select * From %x_json", x_json: 1, x_casts: { a: "int", b: "text", c: "boolean" })
151
+ end
152
+
153
+ def test_cast_values
154
+ expected <<~SQL
155
+ SELECT
156
+ 'abc'::TEXT,
157
+ '"abc"'::JSON,
158
+ '["cde",null,"fgh"]'::JSONB,
159
+ ARRAY['cde', NULL, 'fgh']::TEXT[],
160
+ ARRAY['"cde"', 'null', '"fgh"']::JSON[],
161
+ '{"foo":"bar","go":1,"strip_null":null}'::JSONB not_compact,
162
+ '{"foo":"bar","go":1}'::JSON compact,
163
+ 'foo=>bar,go=>1,strip_null=>NULL'::HSTORE,
164
+ ARRAY[[1,2,3],[1,2,3]]::INT[][]
165
+ SQL
166
+ array1 = array2 = array3 = ["cde", nil, "fgh"]
167
+ array4 = [[1,2,3], [1,2,3]]
168
+ hash = { foo: "bar", "go": 1, strip_null: nil }
169
+ QuoteSQL(<<~SQL, field1: 'abc', array1:, array2:, array3:, array4:, hash: ,not_compact: hash, compact: hash.merge(nil => false))
170
+ SELECT
171
+ %field1::TEXT,
172
+ %field1::JSON,
173
+ %array1,
174
+ %array2::TEXT[],
175
+ %array3::JSON[],
176
+ %not_compact not_compact,
177
+ %compact::JSON compact,
178
+ %hash::HSTORE,
179
+ %array4::INT[][]
148
180
  SQL
149
- QuoteSQL("INSERT INTO table (%x_columns) Select * From %x_json", x_json: 1, x_casts: {a: "int", b: "text", c: "boolean"})
150
181
  end
151
182
 
152
183
  # def test_q3
@@ -172,7 +203,6 @@ class QuoteSql::Test
172
203
  # )
173
204
  # end
174
205
 
175
-
176
206
  public
177
207
 
178
208
  def all
@@ -193,10 +223,12 @@ class QuoteSql::Test
193
223
  tables = @test.tables.to_h { [[_1, "table"].compact.join("_"), _2] }
194
224
  columns = @test.instance_variable_get(:@columns).to_h { [[_1, "columns"].compact.join("_"), _2] }
195
225
  rv += [
196
- "QuoteSql.new(\"#{@test.original}\").quote(#{{**tables, **columns, **@test.quotes }.inspect}).to_sql", "🎯 #{expected}", "✅ #{sql}"]
226
+ "QuoteSql.new(\"#{@test.original}\").quote(#{{ **tables, **columns, **@test.quotes }.inspect}).to_sql", "🎯 #{expected}", "✅ #{sql}"]
197
227
  @success << rv if @success
198
228
  else
199
229
  rv += [@test.inspect, "🎯 #{expected}", "❌ #{sql}"]
230
+ rv << sql.gsub(/\s+/, "")&.downcase&.strip
231
+ rv << expected&.gsub(/\s+/, "")&.downcase&.strip
200
232
  @fail << rv if @fail
201
233
  end
202
234
  rescue => exc
@@ -228,4 +260,111 @@ class QuoteSql::Test
228
260
  end
229
261
  end
230
262
 
231
- end
263
+ def datatype
264
+ errors = {}
265
+ success = []
266
+ spaces = ->(*) { " " * (rand(4) + 1) }
267
+
268
+ DATATYPES.each_line(chomp: true) do |line|
269
+
270
+ l = line.gsub(/\s+/, &spaces).gsub(/(?<=\()\d+|\d+(?=\))/) { "#{spaces.call}#{rand(10) + 1}#{spaces.call}" }.gsub(/\(/) { "#{spaces.call}(" }
271
+
272
+ m = "jgj hsgjhsgfjh ag %field::#{l} asldfalskjdfl".match(QuoteSql::CASTS)
273
+ if m.present? and l == m[1]
274
+ success << line
275
+ else
276
+ errors[line] = m&.to_a
277
+ end
278
+ line = line + "[]"*(rand(3) + 1)
279
+ m = "jgj hsgjhsgfjh ag %field::#{line} asldfalskjdfl".match(QuoteSql::CASTS)
280
+ if m.present? and line == m[1] + m[2]
281
+ success << line
282
+ else
283
+ errors[line] = m&.to_a
284
+ end
285
+ end
286
+ puts success.sort.inspect
287
+ ap errors
288
+ end
289
+
290
+ DATATYPES = <<-DATATYPES
291
+ bigint
292
+ int8
293
+ bigserial
294
+ serial8
295
+ bit
296
+ bit (1)
297
+ bit varying
298
+ varbit
299
+ bit varying (2)
300
+ varbit (2)
301
+ boolean
302
+ bool
303
+ box
304
+ bytea
305
+ character
306
+ char
307
+ character (1)
308
+ char (1)
309
+ character varying
310
+ varchar
311
+ character varying (1)
312
+ varchar (1)
313
+ cidr
314
+ circle
315
+ date
316
+ double precision
317
+ float8
318
+ inet
319
+ integer
320
+ int
321
+ int4
322
+ interval
323
+ interval (1)
324
+ json
325
+ jsonb
326
+ line
327
+ lseg
328
+ macaddr
329
+ macaddr8
330
+ money
331
+ numeric
332
+ numeric(10,3)
333
+ decimal
334
+ decimal(10,3)
335
+ path
336
+ pg_lsn
337
+ pg_snapshot
338
+ point
339
+ polygon
340
+ real
341
+ float4
342
+ smallint
343
+ int2
344
+ smallserial
345
+ serial
346
+ serial2
347
+ serial4
348
+ text
349
+ time
350
+ time(1)
351
+ time without time zone
352
+ time(1) without time zone
353
+ time with time zone
354
+ time(2) with time zone
355
+ timetz
356
+ timestamp
357
+ timestamp(1)
358
+ timestamp without time zone
359
+ timestamp(1) without time zone
360
+ timestamp with time zone
361
+ timestamp(1) with time zone
362
+ timestamptz
363
+ tsquery
364
+ tsvector
365
+ txid_snapshot
366
+ uuid
367
+ xml
368
+ DATATYPES
369
+
370
+ end
@@ -1,3 +1,3 @@
1
1
  class QuoteSql
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
data/lib/quote_sql.rb CHANGED
@@ -3,25 +3,30 @@ Dir.glob(__FILE__.sub(/\.rb$/, "/*.rb")).each { require(_1) unless _1[/(deprecat
3
3
  # Tool to build and run SQL queries easier
4
4
  class QuoteSql
5
5
 
6
+
6
7
  DATA_TYPES_RE = %w(
7
- (?:small|big)(?:int|serial)
8
- bit bool(?:ean)? box bytea cidr circle date
8
+ (?>character\\s+varying|bit\\s+varying|character|varbit|varchar|char|bit|interval)(?>\\s*\\(\\s*\\d+\\s*\\))?
9
+ (?>numeric|decimal)(?>\\s*\\(\\s*\\d+\\s*,\\s*\\d+\\s*\\))?
10
+ timestamptz timetz
11
+ time(?>stamp)?(?>\\s*\\(\\s*\\d+\\s*\\))?(?>\\s+with(?>out)?\\s+time\\s+zone)?
12
+ integer
13
+ (?>small|big)(?>int|serial)
14
+ bool(?>ean)? box bytea cidr circle date
9
15
  (?:date|int[48]|num|ts(?:tz)?)(?:multi)?range
10
16
  macaddr8?
11
- jsonb?
12
- ts(?:query|vector)
13
- float[48] (?:int|serial)[248]?
14
- double_precision inet
15
- integer line lseg money path pg_lsn
16
- pg_snapshot point polygon real text timestamptz timetz
17
- txid_snapshot uuid xml
18
- (bit_varying|varbit|character|char|character varying|varchar)(_\\(\\d+\\))?
19
- (numeric|decimal)(_\\(\d+_\d+\\))?
20
- interval(_(YEAR|MONTH|DAY|HOUR|MINUTE|SECOND|YEAR_TO_MONTH|DAY_TO_HOUR|DAY_TO_MINUTE|DAY_TO_SECOND|HOUR_TO_MINUTE|HOUR_TO_SECOND|MINUTE_TO_SECOND))?(_\\(\d+\\))?
21
- time(stamp)?(_\\(\d+\\))?(_with(out)?_time_zone)?
17
+ ts(?>query|vector)
18
+ float[48]
19
+ (?:int|serial)[248]?
20
+ double\\s+precision
21
+ jsonb json
22
+ inet
23
+ line lseg money path
24
+ pg_lsn pg_snapshot txid_snapshot
25
+ point polygon real text
26
+ uuid xml hstore
22
27
  ).join("|")
23
28
 
24
- CASTS = Regexp.new("__(#{DATA_TYPES_RE})$", "i")
29
+ CASTS = Regexp.new("::(#{DATA_TYPES_RE})((?:\\s*\\[\\s*\\d?\\s*\\])*)", "i")
25
30
 
26
31
  def self.conn
27
32
  raise ArgumentError, "You need to define a database connection function"
@@ -152,11 +157,8 @@ time(stamp)?(_\\(\d+\\))?(_with(out)?_time_zone)?
152
157
  def key_matches
153
158
  @sql.scan(MIXIN_RE).map do |full, *key|
154
159
  key = key.compact[0]
155
- if m = key.match(/^(.+)#{CASTS}/i)
156
- _, key, cast = m.to_a
157
- end
158
160
  has_quote = @quotes.key?(key.to_sym) || key.match?(/(table|columns)$/)
159
- [full, key, cast, has_quote]
161
+ [full, key, has_quote]
160
162
  end
161
163
  end
162
164
 
@@ -166,27 +168,28 @@ time(stamp)?(_\\(\d+\\))?(_with(out)?_time_zone)?
166
168
  loop do
167
169
  s = StringScanner.new(@sql)
168
170
  sql = ""
169
- key_matches.each do |key_match, key, cast, has_quote|
170
- s.scan_until(/(.*?)#{key_match}([a-z0-9_]*)/im)
171
- matched, pre, post = s.matched, s[1], s[2]
172
- if m = key.match(/^bind(\d+)?/im)
173
- if m[1].present?
174
- bind_num = m[1].to_i
175
- @binds[bind_num - 1] ||= cast
176
- raise "bind #{bind_num} already set to #{@binds[bind_num - 1]}" unless @binds[bind_num - 1] == cast
177
- else
178
- @binds << cast
179
- bind_num = @binds.length
180
- end
181
-
182
- matched = "#{pre}$#{bind_num}#{"::#{cast}" if cast.present?}#{post}"
183
- elsif has_quote
184
- quoted = quoter(key)
171
+ key_matches.each do |key_match, key, has_quote|
172
+ s.scan_until(/(.*?)#{key_match}(#{CASTS}?)/im)
173
+ matched, pre, cast = s.matched, s[1], s[2]
174
+ # if m = key.match(/^bind(\d+)?/im)
175
+ # if m[1].present?
176
+ # bind_num = m[1].to_i
177
+ # @binds[bind_num - 1] ||= cast
178
+ # raise "bind #{bind_num} already set to #{@binds[bind_num - 1]}" unless @binds[bind_num - 1] == cast
179
+ # else
180
+ # @binds << cast
181
+ # bind_num = @binds.length
182
+ # end
183
+ #
184
+ # matched = "#{pre}$#{bind_num}#{"::#{cast}" if cast.present?}#{post}"
185
+ # els
186
+ if has_quote
187
+ quoted = quoter(key, cast)
185
188
  unresolved.delete key
186
189
  if (i = quoted.scan MIXIN_RE).present?
187
190
  unresolved += i.map(&:last)
188
191
  end
189
- matched = "#{pre}#{quoted}#{post}"
192
+ matched = "#{pre}#{quoted}#{cast}"
190
193
  end
191
194
  rescue TypeError
192
195
  ensure
@@ -200,8 +203,8 @@ time(stamp)?(_\\(\d+\\))?(_with(out)?_time_zone)?
200
203
  self
201
204
  end
202
205
 
203
- def quoter(key)
204
- quoter = @resolved[key.to_sym] = Quoter.new(self, key, @quotes[key.to_sym])
206
+ def quoter(key, cast)
207
+ quoter = @resolved[key.to_sym] = Quoter.new(self, key, cast, @quotes[key.to_sym])
205
208
  quoter.to_sql
206
209
  rescue TypeError => exc
207
210
  @resolved[key.to_sym] = exc
@@ -224,8 +227,11 @@ time(stamp)?(_\\(\d+\\))?(_with(out)?_time_zone)?
224
227
 
225
228
  def self.test(which = :all)
226
229
  require __dir__ + "/quote_sql/test.rb"
227
- if which == :all
230
+ case which
231
+ when :all
228
232
  Test.new.all
233
+ when :datatype
234
+ Test.new.datatype
229
235
  else
230
236
  Test.new.run(which)
231
237
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quote-sql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Kufner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-27 00:00:00.000000000 Z
11
+ date: 2024-02-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: niceql