foobara-postgresql-crud-driver 0.0.4 → 0.0.6
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/CHANGELOG.md +9 -0
- data/src/postgresql_crud_driver.rb +80 -37
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c70acc46afdd97ad49f99fab679f7e4ebc941b44d87602cf064d9b194ac3258
|
|
4
|
+
data.tar.gz: 802460242c1235c1f6633c6e59bce99a420ae0262bcf1caff537e772d4b9d66a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8581bb3c624df68dd3faa62bc761f668c8487015045053a2026b275aab255e0203c3eddb68df86fb62c03f863c3bb1e0f3114fa452019652b83da44d50952add
|
|
7
|
+
data.tar.gz: f2d6f26683f459db5680e2c0cda6d51bb22d5e9c0407a56ba15cdf4f91fb94060304266a0b6e6ef1c905c099e765b5b5a455c8e6c575cfdd4d36d8c8ccabb3b5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## [0.0.6] - 2025-11-10
|
|
2
|
+
|
|
3
|
+
- Include "_varchar" as a valid stringish pg type
|
|
4
|
+
|
|
5
|
+
## [0.0.5] - 2025-11-10
|
|
6
|
+
|
|
7
|
+
- Improve error messages for foobara type/pg column incompatibilities
|
|
8
|
+
- Validate strings used as integers represent valid integers
|
|
9
|
+
|
|
1
10
|
## [0.0.4] - 2025-11-09
|
|
2
11
|
|
|
3
12
|
- Support a few more column types
|
|
@@ -23,6 +23,23 @@ module Foobara
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
class ColumnTypeMismatchError < StandardError
|
|
27
|
+
attr_accessor :pg_type, :foobara_type, :entity_class, :attribute_name
|
|
28
|
+
|
|
29
|
+
def initialize(pg_type:, foobara_type:, entity_class:, attribute_name: nil)
|
|
30
|
+
# TODO: figure out a way to test this code path
|
|
31
|
+
# :nocov:
|
|
32
|
+
self.pg_type = pg_type
|
|
33
|
+
self.foobara_type = foobara_type
|
|
34
|
+
self.entity_class = entity_class
|
|
35
|
+
self.attribute_name = attribute_name
|
|
36
|
+
|
|
37
|
+
super("Column type mismatch between foobara #{foobara_type.type_symbol} " \
|
|
38
|
+
"and postgres #{pg_type} for #{entity_class.entity_name}.#{attribute_name}")
|
|
39
|
+
# :nocov:
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
26
43
|
class << self
|
|
27
44
|
def get_transaction_number
|
|
28
45
|
@get_transaction_number ||= 0
|
|
@@ -237,6 +254,7 @@ module Foobara
|
|
|
237
254
|
SQL
|
|
238
255
|
|
|
239
256
|
raw_connection.exec(sql)
|
|
257
|
+
|
|
240
258
|
find(record_id)
|
|
241
259
|
end
|
|
242
260
|
|
|
@@ -323,6 +341,7 @@ module Foobara
|
|
|
323
341
|
foobara_type = entity_class.model_type.element_types.element_types[attribute_name]
|
|
324
342
|
|
|
325
343
|
value = begin
|
|
344
|
+
check_type_compatibility!(foobara_type, info, attribute_name:)
|
|
326
345
|
pg_cast_value(value, foobara_type, info)
|
|
327
346
|
rescue UnsupportedPgColumnTypeError => e
|
|
328
347
|
# :nocov:
|
|
@@ -373,62 +392,86 @@ module Foobara
|
|
|
373
392
|
# :nocov:
|
|
374
393
|
end
|
|
375
394
|
elsif foobara_type.extends?(:number)
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
395
|
+
validate_intable!(value)
|
|
396
|
+
value.to_i
|
|
397
|
+
elsif foobara_type.extends?(:string) || foobara_type.extends?(:symbol)
|
|
398
|
+
"'#{PG::Connection.escape(value.to_s)}'"
|
|
399
|
+
elsif foobara_type.extends?(:datetime)
|
|
400
|
+
"'#{PG::Connection.escape(value.inspect)}'"
|
|
401
|
+
elsif foobara_type.extends?(:detached_entity)
|
|
402
|
+
pg_cast_value(value, foobara_type.target_class.primary_key_type, pg_info)
|
|
403
|
+
elsif foobara_type.extends?(:model) || foobara_type.extends?(:attributes) ||
|
|
404
|
+
foobara_type == BuiltinTypes[:duck]
|
|
405
|
+
"'#{PG::Connection.escape(JSON.fast_generate(value))}'"
|
|
406
|
+
elsif foobara_type.extends?(:array)
|
|
407
|
+
element_type = foobara_type.element_type
|
|
408
|
+
|
|
409
|
+
if element_type.extends?(:detached_entity)
|
|
410
|
+
if element_type.target_class.primary_key_type.extends?(:integer)
|
|
411
|
+
value.each { validate_intable!(it) }
|
|
412
|
+
end
|
|
413
|
+
elements_type = ARRAY_ELEMENT_ENCODERS[pg_info[:element_type]]
|
|
414
|
+
array_string = PG::TextEncoder::Array.new(elements_type:).encode(value)
|
|
415
|
+
escaped = PG::Connection.escape(array_string)
|
|
416
|
+
|
|
417
|
+
"'#{escaped}'"
|
|
379
418
|
else
|
|
380
419
|
# :nocov:
|
|
381
420
|
raise UnsupportedPgColumnTypeError.new(pg_type, entity_class)
|
|
382
421
|
# :nocov:
|
|
383
422
|
end
|
|
423
|
+
else
|
|
424
|
+
# :nocov:
|
|
425
|
+
raise UnsupportedPgColumnTypeError.new(pg_type, entity_class)
|
|
426
|
+
# :nocov:
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def validate_intable!(value)
|
|
431
|
+
if value.is_a?(::String) || value.is_a?(::Symbol)
|
|
432
|
+
unless value =~ /\A[+-]?\d+\z/
|
|
433
|
+
# :nocov:
|
|
434
|
+
raise "Expected something that could be cast to an integer but got #{value}"
|
|
435
|
+
# :nocov:
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def check_type_compatibility!(foobara_type, pg_info, pg_type: pg_info[:type], attribute_name: nil)
|
|
441
|
+
if foobara_type.extends?(:integer)
|
|
442
|
+
unless pg_type == "integer" || pg_type == "bigint" || pg_type == "_int4"
|
|
443
|
+
# :nocov:
|
|
444
|
+
raise ColumnTypeMismatchError.new(pg_type:, foobara_type:, attribute_name:, entity_class:)
|
|
445
|
+
# :nocov:
|
|
446
|
+
end
|
|
384
447
|
elsif foobara_type.extends?(:string) || foobara_type.extends?(:symbol)
|
|
385
|
-
|
|
386
|
-
when "text", "character varying"
|
|
387
|
-
"'#{PG::Connection.escape(value.to_s)}'"
|
|
388
|
-
else
|
|
448
|
+
unless pg_type == "text" || pg_type == "character varying" || pg_type == "_varchar"
|
|
389
449
|
# :nocov:
|
|
390
|
-
raise
|
|
450
|
+
raise ColumnTypeMismatchError.new(pg_type:, foobara_type:, attribute_name:, entity_class:)
|
|
391
451
|
# :nocov:
|
|
392
452
|
end
|
|
393
453
|
elsif foobara_type.extends?(:datetime)
|
|
394
|
-
|
|
395
|
-
when "timestamp without time zone"
|
|
396
|
-
"'#{PG::Connection.escape(value.inspect)}'"
|
|
397
|
-
else
|
|
454
|
+
unless pg_type == "timestamp without time zone"
|
|
398
455
|
# :nocov:
|
|
399
|
-
raise
|
|
456
|
+
raise ColumnTypeMismatchError.new(pg_type:, foobara_type:, attribute_name:, entity_class:)
|
|
400
457
|
# :nocov:
|
|
401
458
|
end
|
|
402
459
|
elsif foobara_type.extends?(:detached_entity)
|
|
403
|
-
|
|
404
|
-
elsif foobara_type.extends?(:model) || foobara_type.extends?(:attributes)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
"'#{PG::Connection.escape(JSON.fast_generate(value))}'"
|
|
408
|
-
else
|
|
460
|
+
check_type_compatibility!(foobara_type.target_class.primary_key_type, pg_info, pg_type:, attribute_name:)
|
|
461
|
+
elsif foobara_type.extends?(:model) || foobara_type.extends?(:attributes) ||
|
|
462
|
+
foobara_type == BuiltinTypes[:duck]
|
|
463
|
+
unless pg_type == "jsonb" || pg_type == "json"
|
|
409
464
|
# :nocov:
|
|
410
|
-
raise
|
|
465
|
+
raise ColumnTypeMismatchError.new(pg_type:, foobara_type:, attribute_name:, entity_class:)
|
|
411
466
|
# :nocov:
|
|
412
467
|
end
|
|
413
468
|
elsif foobara_type.extends?(:array)
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
case pg_type
|
|
418
|
-
when "ARRAY"
|
|
419
|
-
elements_type = ARRAY_ELEMENT_ENCODERS[pg_info[:element_type]]
|
|
420
|
-
array_string = PG::TextEncoder::Array.new(elements_type:).encode(value)
|
|
421
|
-
escaped = PG::Connection.escape(array_string)
|
|
422
|
-
|
|
423
|
-
"'#{escaped}'"
|
|
424
|
-
else
|
|
425
|
-
# :nocov:
|
|
426
|
-
raise UnsupportedPgColumnTypeError.new(pg_type, entity_class)
|
|
427
|
-
# :nocov:
|
|
428
|
-
end
|
|
429
|
-
else
|
|
469
|
+
if pg_type == "ARRAY"
|
|
470
|
+
element_type = foobara_type.element_type
|
|
471
|
+
check_type_compatibility!(element_type, pg_info, pg_type: pg_info[:element_type], attribute_name:)
|
|
430
472
|
# :nocov:
|
|
431
|
-
|
|
473
|
+
elsif pg_type != json && pg_type != jsonb
|
|
474
|
+
raise ColumnTypeMismatchError.new(pg_type:, foobara_type:, attribute_name:, entity_class:)
|
|
432
475
|
# :nocov:
|
|
433
476
|
end
|
|
434
477
|
else
|