From 52bd555933d370cd78826d6897a30ec855a917e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=9Awi=C4=85tkowski?= Date: Sun, 27 Oct 2024 13:22:01 +0100 Subject: [PATCH 1/2] Add tests replicating the issue with custom types --- spec/integration/commands/create_spec.rb | 16 ++++++++++++++++ spec/integration/commands/update_spec.rb | 19 +++++++++++++++++++ spec/shared/json_notes.rb | 23 +++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 spec/shared/json_notes.rb diff --git a/spec/integration/commands/create_spec.rb b/spec/integration/commands/create_spec.rb index b59e89dd..e36469aa 100644 --- a/spec/integration/commands/create_spec.rb +++ b/spec/integration/commands/create_spec.rb @@ -178,6 +178,22 @@ def self.[](input) ]) end + context "with json notes" do + include_context "json_notes" + + before do + conf.commands(:json_notes) do + define(:create) + end + end + + it "writes and reads back custom type" do + json_notes = commands[:json_notes] + + expect(json_notes[:create].call(note: "this is my note")).to eq([{id: 1, note: "this is my note"}]) + end + end + it "re-raises not-null constraint violation error" do expect { create_user.call(name: nil) diff --git a/spec/integration/commands/update_spec.rb b/spec/integration/commands/update_spec.rb index 24838021..7bc23269 100644 --- a/spec/integration/commands/update_spec.rb +++ b/spec/integration/commands/update_spec.rb @@ -109,6 +109,25 @@ def by_name(name) expect(result).to eq([{id: 1, name: "Josie"}, {id: 2, name: "Josie"}]) end + + context "with json notes" do + include_context "json_notes" + + before do + conf.commands(:json_notes) do + define(:update) + end + end + + let(:json_notes) { container.relations[:json_notes] } + + it "writes and reads back custom type" do + note_id = conn[:json_notes].insert(note: "note version 1") + result = json_notes.by_pk(note_id).command(:update).call(note: "note version 2") + + expect(result).to eq([{id: 1, note: "note version 2"}]) + end + end end end end diff --git a/spec/shared/json_notes.rb b/spec/shared/json_notes.rb new file mode 100644 index 00000000..35232038 --- /dev/null +++ b/spec/shared/json_notes.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +RSpec.shared_context "json_notes" do + before do + inferrable_relations.concat %i[json_notes] + end + + before do |_example| + conn.create_table :json_notes do + primary_key :id + String :note + end + + write_type = Dry.Types.Constructor(String) { |value| JSON.dump({content: value}) } + read_type = Dry.Types.Constructor(String) { |value| JSON.parse(value)["content"] } + + conf.relation(:json_notes) do + schema(infer: true) do + attribute :note, write_type, read: read_type + end + end + end +end From c4fc45024b0655219826ed05da59dbfe167fdc98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20=C5=9Awi=C4=85tkowski?= Date: Sun, 27 Oct 2024 13:51:22 +0100 Subject: [PATCH 2/2] Use dataset to fetch record after insert Similarily to what Update command do, use `dataset` to load the tuple after `insert` in Create command. This way it loads "raw" data, without applying read types yet. So when tuples are passed into `finalize` hook, it can properly apply these read types. --- lib/rom/sql/commands/create.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rom/sql/commands/create.rb b/lib/rom/sql/commands/create.rb index e20ffa6a..dddf8172 100644 --- a/lib/rom/sql/commands/create.rb +++ b/lib/rom/sql/commands/create.rb @@ -46,7 +46,7 @@ def finalize(tuples, *) # @api private def insert(tuples) pks = tuples.map { |tuple| relation.insert(tuple) } - relation.where(relation.primary_key => pks).to_a + relation.dataset.where(relation.primary_key => pks).to_a end # Executes multi_insert statement and returns inserted tuples @@ -54,7 +54,7 @@ def insert(tuples) # @api private def multi_insert(tuples) pks = relation.multi_insert(tuples, return: :primary_key) - relation.where(relation.primary_key => pks).to_a + relation.dataset.where(relation.primary_key => pks).to_a end # Yields tuples for insertion or return an enumerator