rom-sql 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -12
  3. data/CHANGELOG.md +23 -0
  4. data/Gemfile +11 -3
  5. data/README.md +1 -7
  6. data/lib/rom/sql.rb +4 -7
  7. data/lib/rom/sql/association.rb +1 -1
  8. data/lib/rom/sql/association/one_to_many.rb +44 -1
  9. data/lib/rom/sql/association/one_to_one.rb +1 -38
  10. data/lib/rom/sql/commands.rb +0 -3
  11. data/lib/rom/sql/commands/error_wrapper.rb +1 -1
  12. data/lib/rom/sql/errors.rb +4 -1
  13. data/lib/rom/sql/extensions.rb +19 -0
  14. data/lib/rom/sql/{support → extensions}/active_support_notifications.rb +0 -0
  15. data/lib/rom/sql/extensions/postgres.rb +3 -0
  16. data/lib/rom/sql/{commands/postgres.rb → extensions/postgres/commands.rb} +38 -0
  17. data/lib/rom/sql/extensions/postgres/inferrer.rb +64 -0
  18. data/lib/rom/sql/extensions/postgres/types.rb +65 -0
  19. data/lib/rom/sql/{support → extensions}/rails_log_subscriber.rb +0 -0
  20. data/lib/rom/sql/gateway.rb +15 -4
  21. data/lib/rom/sql/relation.rb +6 -2
  22. data/lib/rom/sql/relation/reading.rb +18 -0
  23. data/lib/rom/sql/schema/dsl.rb +7 -4
  24. data/lib/rom/sql/schema/inferrer.rb +44 -31
  25. data/lib/rom/sql/types.rb +5 -1
  26. data/lib/rom/sql/version.rb +1 -1
  27. data/rom-sql.gemspec +14 -13
  28. data/spec/extensions/postgres/inferrer_spec.rb +40 -0
  29. data/spec/extensions/postgres/integration_spec.rb +38 -0
  30. data/spec/extensions/postgres/types_spec.rb +115 -0
  31. data/spec/integration/association/many_to_many_spec.rb +2 -1
  32. data/spec/integration/association/one_to_one_spec.rb +6 -4
  33. data/spec/integration/combine_spec.rb +1 -1
  34. data/spec/integration/commands/create_spec.rb +46 -21
  35. data/spec/integration/commands/delete_spec.rb +13 -38
  36. data/spec/integration/commands/update_spec.rb +19 -41
  37. data/spec/integration/commands/upsert_spec.rb +1 -1
  38. data/spec/integration/gateway_spec.rb +5 -9
  39. data/spec/integration/migration_spec.rb +6 -7
  40. data/spec/integration/read_spec.rb +30 -38
  41. data/spec/integration/schema_inference_spec.rb +211 -49
  42. data/spec/integration/setup_spec.rb +5 -5
  43. data/spec/integration/support/active_support_notifications_spec.rb +4 -3
  44. data/spec/integration/support/rails_log_subscriber_spec.rb +5 -4
  45. data/spec/shared/database_setup.rb +21 -6
  46. data/spec/spec_helper.rb +44 -35
  47. data/spec/unit/association/one_to_many_spec.rb +20 -0
  48. data/spec/unit/association/one_to_one_spec.rb +23 -2
  49. data/spec/unit/association_errors_spec.rb +1 -1
  50. data/spec/unit/gateway_spec.rb +9 -8
  51. data/spec/unit/logger_spec.rb +1 -1
  52. data/spec/unit/migration_tasks_spec.rb +3 -3
  53. data/spec/unit/migrator_spec.rb +3 -2
  54. data/spec/unit/plugin/assoc_macros/combined_associations_spec.rb +1 -1
  55. data/spec/unit/plugin/assoc_macros/many_to_many_spec.rb +1 -1
  56. data/spec/unit/plugin/assoc_macros/many_to_one_spec.rb +1 -1
  57. data/spec/unit/plugin/assoc_macros/one_to_many_spec.rb +1 -1
  58. data/spec/unit/relation/associations_spec.rb +27 -0
  59. data/spec/unit/relation/avg_spec.rb +11 -0
  60. data/spec/unit/relation/by_pk_spec.rb +15 -0
  61. data/spec/unit/relation/dataset_spec.rb +48 -0
  62. data/spec/unit/relation/distinct_spec.rb +14 -0
  63. data/spec/unit/relation/exclude_spec.rb +13 -0
  64. data/spec/unit/relation/fetch_spec.rb +21 -0
  65. data/spec/unit/relation/having_spec.rb +20 -0
  66. data/spec/unit/relation/inner_join_spec.rb +22 -0
  67. data/spec/unit/relation/inspect_spec.rb +11 -0
  68. data/spec/unit/relation/invert_spec.rb +12 -0
  69. data/spec/unit/relation/left_join_spec.rb +16 -0
  70. data/spec/unit/relation/map_spec.rb +16 -0
  71. data/spec/unit/relation/max_spec.rb +11 -0
  72. data/spec/unit/relation/min_spec.rb +11 -0
  73. data/spec/unit/relation/pluck_spec.rb +11 -0
  74. data/spec/unit/relation/prefix_spec.rb +27 -0
  75. data/spec/unit/relation/primary_key_spec.rb +27 -0
  76. data/spec/unit/relation/project_spec.rb +22 -0
  77. data/spec/unit/relation/qualified_columns_spec.rb +27 -0
  78. data/spec/unit/relation/rename_spec.rb +21 -0
  79. data/spec/unit/relation/sum_spec.rb +11 -0
  80. data/spec/unit/relation/union_spec.rb +19 -0
  81. data/spec/unit/relation/unique_predicate_spec.rb +18 -0
  82. data/spec/unit/schema_spec.rb +1 -1
  83. data/spec/unit/types_spec.rb +4 -21
  84. metadata +79 -11
  85. data/lib/rom/sql/commands_ext/postgres.rb +0 -45
  86. data/lib/rom/sql/types/pg.rb +0 -26
  87. data/spec/unit/relation_spec.rb +0 -272
@@ -0,0 +1,65 @@
1
+ require 'dry-types'
2
+ require 'sequel'
3
+
4
+ Sequel.extension(*%i(pg_array pg_array_ops pg_json pg_json_ops))
5
+
6
+ module ROM
7
+ module SQL
8
+ module Types
9
+ module PG
10
+ # UUID
11
+
12
+ UUID = Types::String
13
+
14
+ # Array
15
+
16
+ Array = Dry::Types::Definition
17
+ .new(Sequel::Postgres::PGArray)
18
+
19
+ def self.Array(db_type)
20
+ Array.constructor(-> (v) { Sequel.pg_array(v, db_type) }).meta(type: db_type)
21
+ end
22
+
23
+ # JSON
24
+
25
+ JSONArray = Dry::Types::Definition
26
+ .new(Sequel::Postgres::JSONArray)
27
+ .constructor(Sequel.method(:pg_json))
28
+
29
+ JSONHash = Dry::Types::Definition
30
+ .new(Sequel::Postgres::JSONHash)
31
+ .constructor(Sequel.method(:pg_json))
32
+
33
+ JSONOp = Dry::Types::Definition
34
+ .new(Sequel::Postgres::JSONOp)
35
+ .constructor(Sequel.method(:pg_json))
36
+
37
+ JSON = JSONArray | JSONHash | JSONOp
38
+
39
+ # JSONB
40
+
41
+ JSONBArray = Dry::Types::Definition
42
+ .new(Sequel::Postgres::JSONBArray)
43
+ .constructor(Sequel.method(:pg_jsonb))
44
+
45
+ JSONBHash = Dry::Types::Definition
46
+ .new(Sequel::Postgres::JSONBHash)
47
+ .constructor(Sequel.method(:pg_jsonb))
48
+
49
+ JSONBOp = Dry::Types::Definition
50
+ .new(Sequel::Postgres::JSONBOp)
51
+ .constructor(Sequel.method(:pg_jsonb))
52
+
53
+ JSONB = JSONBArray | JSONBHash | JSONBOp
54
+
55
+ Bytea = Dry::Types::Definition
56
+ .new(Sequel::SQL::Blob)
57
+ .constructor(Sequel::SQL::Blob.method(:new))
58
+
59
+ # MONEY
60
+
61
+ Money = Types::Decimal
62
+ end
63
+ end
64
+ end
65
+ end
@@ -23,6 +23,10 @@ module ROM
23
23
  attr_accessor :instance
24
24
  end
25
25
 
26
+ CONNECTION_EXTENSIONS = {
27
+ postgres: %i(pg_array pg_json)
28
+ }.freeze
29
+
26
30
  # Return optionally configured logger
27
31
  #
28
32
  # @return [Object] logger
@@ -56,7 +60,7 @@ module ROM
56
60
  conn_options = options.reject { |k, _| repo_options.include?(k) }
57
61
 
58
62
  @connection = connect(uri, conn_options)
59
- add_extensions(Array(options[:extensions])) if options[:extensions]
63
+ load_extensions(Array(options[:extensions]))
60
64
 
61
65
  super(uri, options.reject { |k, _| conn_options.keys.include?(k) })
62
66
 
@@ -177,11 +181,18 @@ module ROM
177
181
  end
178
182
  end
179
183
 
180
- # Add extensions to the database connection
184
+ # Load database-specific extensions
181
185
  #
182
186
  # @api private
183
- def add_extensions(exts)
184
- connection.extension(*exts)
187
+ def load_extensions(exts)
188
+ db_type = connection.database_type.to_sym
189
+
190
+ if ROM::SQL.available_extension?(db_type)
191
+ ROM::SQL.load_extensions(db_type)
192
+ end
193
+
194
+ extensions = (CONNECTION_EXTENSIONS.fetch(db_type) { [] } + exts).uniq
195
+ connection.extension(*extensions)
185
196
  end
186
197
  end
187
198
  end
@@ -42,14 +42,18 @@ module ROM
42
42
 
43
43
  klass.class_eval do
44
44
  schema_dsl SQL::Schema::DSL
45
- schema_inferrer ROM::SQL::Schema::Inferrer
45
+ schema_inferrer -> (dataset, gateway) do
46
+ inferrer_for_db = ROM::SQL::Schema::Inferrer.get(gateway.connection.database_type.to_sym)
47
+ inferrer_for_db.new.call(dataset, gateway)
48
+ end
46
49
 
47
50
  dataset do
48
51
  table = opts[:from].first
49
52
 
50
53
  if db.table_exists?(table)
51
54
  pk_header = klass.primary_key_header(db, table)
52
- select(*columns).order(*pk_header.qualified)
55
+ col_names = klass.schema ? klass.schema.attributes.keys : columns
56
+ select(*col_names).order(*pk_header.qualified)
53
57
  else
54
58
  self
55
59
  end
@@ -305,6 +305,24 @@ module ROM
305
305
  __new__(dataset.__send__(__method__, *args, &block))
306
306
  end
307
307
 
308
+ # Restrict a relation to match grouping criteria
309
+ #
310
+ # @example
311
+ # users.with_task_count.having( task_count: 2 )
312
+ #
313
+ # users.with_task_count.having { task_count > 3 }
314
+ #
315
+ # @param [Hash] *args An optional hash with conditions for HAVING clause
316
+ #
317
+ # @return [Relation]
318
+ #
319
+ # @see http://sequel.jeremyevans.net/rdoc/files/doc/dataset_filtering_rdoc.html
320
+ #
321
+ # @api public
322
+ def having(*args, &block)
323
+ __new__(dataset.__send__(__method__, *args, &block))
324
+ end
325
+
308
326
  # Inverts the current WHERE and HAVING clauses. If there is neither a
309
327
  # WHERE or HAVING clause, adds a WHERE clause that is always false.
310
328
  #
@@ -16,10 +16,13 @@ module ROM
16
16
  end
17
17
 
18
18
  def opts
19
- opts = {}
20
- opts[:associations] = associations_dsl.call if associations_dsl
21
- opts[:inferrer] = inferrer.new(self) if inferrer
22
- opts
19
+ opts = { inferrer: inferrer }
20
+
21
+ if associations_dsl
22
+ { **opts, associations: associations_dsl.call }
23
+ else
24
+ opts
25
+ end
23
26
  end
24
27
  end
25
28
  end
@@ -1,27 +1,39 @@
1
1
  module ROM
2
2
  module SQL
3
3
  class Schema < ROM::Schema
4
+ # @api private
4
5
  class Inferrer
5
6
  extend ClassMacros
6
7
 
7
- defines :type_mapping, :pk_type
8
+ defines :ruby_type_mapping, :numeric_pk_type, :db_type, :db_registry
8
9
 
9
- type_mapping(
10
- integer: Types::Strict::Int,
11
- string: Types::Strict::String,
12
- date: Types::Strict::Date,
13
- datetime: Types::Strict::Time,
14
- boolean: Types::Strict::Bool,
15
- decimal: Types::Strict::Decimal,
16
- blob: Types::Strict::String
10
+ ruby_type_mapping(
11
+ integer: Types::Int,
12
+ string: Types::String,
13
+ date: Types::Date,
14
+ datetime: Types::Time,
15
+ boolean: Types::Bool,
16
+ decimal: Types::Decimal,
17
+ float: Types::Float,
18
+ blob: Types::Blob
17
19
  ).freeze
18
20
 
19
- pk_type Types::Serial
21
+ numeric_pk_type Types::Serial
20
22
 
21
- attr_reader :dsl
23
+ db_registry Hash.new(self)
22
24
 
23
- def initialize(dsl)
24
- @dsl = dsl
25
+ def self.inherited(klass)
26
+ super
27
+
28
+ Inferrer.db_registry[klass.db_type] = klass unless klass.name.nil?
29
+ end
30
+
31
+ def self.[](type)
32
+ Class.new(self) { db_type(type) }
33
+ end
34
+
35
+ def self.get(type)
36
+ db_registry[type]
25
37
  end
26
38
 
27
39
  # @api private
@@ -29,33 +41,35 @@ module ROM
29
41
  columns = gateway.connection.schema(dataset)
30
42
  fks = fks_for(gateway, dataset)
31
43
 
32
- columns.each do |(name, definition)|
33
- dsl.attribute name, build_type(definition.merge(foreign_key: fks[name]))
44
+ columns.each_with_object({}) do |(name, definition), attrs|
45
+ type = build_type(definition.merge(foreign_key: fks[name]))
46
+ attrs[name] = type.meta(name: name)
34
47
  end
35
-
36
- pks = columns
37
- .map { |(name, definition)| name if definition.fetch(:primary_key) }
38
- .compact
39
-
40
- dsl.primary_key(*pks) if pks.any?
41
-
42
- dsl.attributes
43
48
  end
44
49
 
45
50
  private
46
51
 
47
- # @api private
48
- def build_type(primary_key: , type: , allow_null: , foreign_key: , **rest)
52
+ def build_type(primary_key:, db_type:, type:, allow_null:, foreign_key:, **rest)
49
53
  if primary_key
50
- self.class.pk_type
54
+ map_pk_type(type, db_type)
51
55
  else
52
- type = self.class.type_mapping.fetch(type)
53
- type = type.optional if allow_null
54
- type = type.meta(foreign_key: true, relation: foreign_key) if foreign_key
55
- type
56
+ mapped_type = map_type(type, db_type)
57
+ mapped_type = mapped_type.optional if allow_null
58
+ mapped_type = mapped_type.meta(foreign_key: true, relation: foreign_key) if foreign_key
59
+ mapped_type
56
60
  end
57
61
  end
58
62
 
63
+ def map_pk_type(_ruby_type, _db_type)
64
+ self.class.numeric_pk_type.meta(primary_key: true)
65
+ end
66
+
67
+ def map_type(ruby_type, db_type)
68
+ self.class.ruby_type_mapping.fetch(ruby_type) {
69
+ raise UnknownDBTypeError, "Cannot find corresponding type for #{ruby_type || db_type}"
70
+ }
71
+ end
72
+
59
73
  # @api private
60
74
  def fks_for(gateway, dataset)
61
75
  gateway.connection.foreign_key_list(dataset).each_with_object({}) do |definition, fks|
@@ -65,7 +79,6 @@ module ROM
65
79
  end
66
80
  end
67
81
 
68
- # @api private
69
82
  def build_fk(columns: , table: , **rest)
70
83
  if columns.size == 1
71
84
  [columns[0], table]
data/lib/rom/sql/types.rb CHANGED
@@ -5,7 +5,11 @@ module ROM
5
5
  module Types
6
6
  include ROM::Types
7
7
 
8
- Serial = Strict::Int.constrained(gt: 0).meta(primary_key: true)
8
+ Serial = Int.constrained(gt: 0).meta(primary_key: true)
9
+
10
+ Blob = Dry::Types::Definition
11
+ .new(Sequel::SQL::Blob)
12
+ .constructor(Sequel::SQL::Blob.method(:new))
9
13
  end
10
14
  end
11
15
  end
@@ -1,5 +1,5 @@
1
1
  module ROM
2
2
  module SQL
3
- VERSION = '0.8.0'.freeze
3
+ VERSION = '0.9.0'.freeze
4
4
  end
5
5
  end
data/rom-sql.gemspec CHANGED
@@ -4,26 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'rom/sql/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "rom-sql"
7
+ spec.name = 'rom-sql'
8
8
  spec.version = ROM::SQL::VERSION.dup
9
- spec.authors = ["Piotr Solnica"]
10
- spec.email = ["piotr.solnica@gmail.com"]
9
+ spec.authors = ['Piotr Solnica']
10
+ spec.email = ['piotr.solnica@gmail.com']
11
11
  spec.summary = 'SQL databases support for ROM'
12
12
  spec.description = spec.summary
13
- spec.homepage = "http://rom-rb.org"
14
- spec.license = "MIT"
13
+ spec.homepage = 'http://rom-rb.org'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_runtime_dependency "sequel", "~> 4.25"
22
- spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
23
- spec.add_runtime_dependency "dry-types", "~> 0.8"
24
- spec.add_runtime_dependency "rom", "~> 2.0"
25
- spec.add_runtime_dependency "rom-support", "~> 2.0"
21
+ spec.add_runtime_dependency 'sequel', '~> 4.25'
22
+ spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
23
+ spec.add_runtime_dependency 'dry-types', '~> 0.9'
24
+ spec.add_runtime_dependency 'dry-core', '~> 0.2'
25
+ spec.add_runtime_dependency 'rom', '~> 2.0'
26
+ spec.add_runtime_dependency 'rom-support', '~> 2.0'
26
27
 
27
- spec.add_development_dependency "bundler"
28
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
29
30
  end
@@ -0,0 +1,40 @@
1
+ RSpec.describe 'ROM::SQL::Schema::PostgresInferrer', :postgres do
2
+ include_context 'database setup'
3
+
4
+ before do
5
+ conn.drop_table?(:test_inferrence)
6
+
7
+ conn.create_table :test_inferrence do
8
+ primary_key :id, :uuid
9
+ Json :json_data
10
+ Jsonb :jsonb_data
11
+ Decimal :money, null: false
12
+ column :tags, "text[]"
13
+ column :tag_ids, "bigint[]"
14
+ end
15
+ end
16
+
17
+ let(:dataset) { :test_inferrence }
18
+
19
+ let(:schema) { container.relations[dataset].schema }
20
+
21
+ context 'inferring db-specific attributes' do
22
+ before do
23
+ dataset = self.dataset
24
+ conf.relation(dataset) do
25
+ schema(dataset, infer: true)
26
+ end
27
+ end
28
+
29
+ it 'can infer attributes for dataset' do
30
+ expect(schema.attributes).to eql(
31
+ id: ROM::SQL::Types::PG::UUID.meta(name: :id, primary_key: true),
32
+ json_data: ROM::SQL::Types::PG::JSON.optional.meta(name: :json_data),
33
+ jsonb_data: ROM::SQL::Types::PG::JSONB.optional.meta(name: :jsonb_data),
34
+ money: ROM::SQL::Types::Decimal.meta(name: :money),
35
+ tags: ROM::SQL::Types::PG::Array('text').optional.meta(name: :tags),
36
+ tag_ids: ROM::SQL::Types::PG::Array('biging').optional.meta(name: :tag_ids)
37
+ )
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ RSpec.describe 'PostgreSQL extension', :postgres do
2
+ include_context 'database setup'
3
+
4
+ before do
5
+ conn.drop_table?(:pg_people)
6
+ conn.drop_table?(:people)
7
+
8
+ conn.create_table :pg_people do
9
+ primary_key :id
10
+ String :name
11
+ column :tags, "text[]"
12
+ end
13
+
14
+ conf.relation(:people) do
15
+ schema(:pg_people, infer: true)
16
+ end
17
+
18
+ conf.commands(:people) do
19
+ define(:create)
20
+ end
21
+ end
22
+
23
+ let(:people_relation) { relations[:people] }
24
+
25
+ describe 'using arrays' do
26
+ let(:people) { commands[:people] }
27
+
28
+ it 'inserts array values' do
29
+ people.create.call(name: 'John Doe', tags: ['foo'])
30
+ expect(people_relation.to_a).to eq([id: 1, name: 'John Doe', tags: ['foo']])
31
+ end
32
+
33
+ it 'inserts empty arrays' do
34
+ people.create.call(name: 'John Doe', tags: [])
35
+ expect(people_relation.to_a).to eq([id: 1, name: 'John Doe', tags: []])
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,115 @@
1
+ RSpec.describe 'ROM::SQL::Types' do
2
+ describe 'ROM::SQL::Types::PG::JSON' do
3
+ it 'coerces to pg json hash' do
4
+ input = { foo: 'bar' }
5
+
6
+ expect(ROM::SQL::Types::PG::JSON[input]).to eql(Sequel.pg_json(input))
7
+ end
8
+
9
+ it 'coerces to pg json array' do
10
+ input = [1, 2, 3]
11
+ output = ROM::SQL::Types::PG::JSON[input]
12
+
13
+ expect(output).to be_instance_of(Sequel::Postgres::JSONArray)
14
+ expect(output.to_a).to eql(input)
15
+ end
16
+ end
17
+
18
+ describe 'ROM::SQL::Types::PG::Bytea' do
19
+ it 'coerces strings to Sequel::SQL::Blob' do
20
+ input = 'sutin'
21
+ output = ROM::SQL::Types::PG::Bytea[input]
22
+
23
+ expect(output).to be_instance_of(Sequel::SQL::Blob)
24
+ expect(output).to eql('sutin')
25
+ end
26
+ end
27
+
28
+ describe ROM::SQL::Types::PG::UUID do
29
+ it 'coerces strings to UUID' do
30
+ input = SecureRandom.uuid
31
+ output = described_class[input]
32
+
33
+ expect(output).to be_instance_of(String)
34
+ end
35
+ end
36
+
37
+ describe ROM::SQL::Types::PG::Array do
38
+ it 'coerces to pg array' do
39
+ input = [1, 2, 3]
40
+ output = ROM::SQL::Types::PG::Array('integer')[input]
41
+
42
+ expect(output).to be_instance_of(Sequel::Postgres::PGArray)
43
+ expect(output.to_a).to eql(input)
44
+ end
45
+
46
+ it 'accepts any other type of objects' do
47
+ input = [nil, 1, 'sutin', :sutin, 1.0, {}].sample
48
+ output = ROM::SQL::Types::PG::Array('integer')[input]
49
+
50
+ expect(output).to be_instance_of(Sequel::Postgres::ArrayOp)
51
+ expect(output.value).to eql(input)
52
+ end
53
+ end
54
+
55
+ describe ROM::SQL::Types::PG::JSON do
56
+ it 'coerces to pg json hash' do
57
+ input = { foo: 'bar' }
58
+ output = described_class[input]
59
+
60
+ expect(output).to be_instance_of(Sequel::Postgres::JSONHash)
61
+ expect(output).to eql(Sequel.pg_json(input))
62
+ end
63
+
64
+ it 'coerces to pg json array' do
65
+ input = [1, 2, 3]
66
+ output = described_class[input]
67
+
68
+ expect(output).to be_instance_of(Sequel::Postgres::JSONArray)
69
+ expect(output.to_a).to eql(input)
70
+ end
71
+
72
+ it 'accepts any other type of objects' do
73
+ input = [nil, 1, 'sutin', :sutin, 1.0].sample
74
+ output = described_class[input]
75
+
76
+ expect(output).to be_instance_of(Sequel::Postgres::JSONOp)
77
+ expect(output.value).to eql(input)
78
+ end
79
+ end
80
+
81
+ describe ROM::SQL::Types::PG::JSONB do
82
+ it 'coerces to pg jsonb hash' do
83
+ input = { foo: 'bar' }
84
+ output = described_class[input]
85
+
86
+ expect(output).to be_instance_of(Sequel::Postgres::JSONBHash)
87
+ expect(output).to eql(Sequel.pg_jsonb(input))
88
+ end
89
+
90
+ it 'coerces to pg jsonb array' do
91
+ input = [1, 2, 3]
92
+ output = described_class[input]
93
+
94
+ expect(output).to be_instance_of(Sequel::Postgres::JSONBArray)
95
+ expect(output.to_a).to eql(input)
96
+ end
97
+
98
+ it 'accepts any other type of objects' do
99
+ input = [nil, 1, 'sutin', :sutin, 1.0].sample
100
+ output = described_class[input]
101
+
102
+ expect(output).to be_instance_of(Sequel::Postgres::JSONBOp)
103
+ expect(output.value).to eql(input)
104
+ end
105
+ end
106
+
107
+ describe ROM::SQL::Types::PG::Money do
108
+ it 'coerces to pg Money' do
109
+ input = BigDecimal.new(1.0, 2)
110
+ output = described_class[input]
111
+
112
+ expect(output).to be_instance_of(BigDecimal)
113
+ end
114
+ end
115
+ end