From 693629afc897bb9429194281f9116810bd4434bf Mon Sep 17 00:00:00 2001 From: simon lehericey Date: Mon, 7 Oct 2024 15:00:22 +0200 Subject: [PATCH] add column type --- app/models/column.rb | 4 ++ app/types/column_type.rb | 38 ++++++++++++++++++ config/initializers/types.rb | 2 + spec/types/column_type_spec.rb | 71 ++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 app/types/column_type.rb create mode 100644 spec/types/column_type_spec.rb diff --git a/app/models/column.rb b/app/models/column.rb index a7f74fa69..7e7a8159c 100644 --- a/app/models/column.rb +++ b/app/models/column.rb @@ -27,4 +27,8 @@ class Column table:, column:, label:, classname:, type:, scope:, value_column:, filterable:, displayable: } end + + def self.find(h_id) + Procedure.with_discarded.find(h_id[:procedure_id]).find_column(h_id:) + end end diff --git a/app/types/column_type.rb b/app/types/column_type.rb new file mode 100644 index 000000000..b54e49f9c --- /dev/null +++ b/app/types/column_type.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class ColumnType < ActiveRecord::Type::Value + # value can come from: + # setter: column (Column), + # form_input: column.id == { procedure_id:, column_id: }.to_json (String), + # from db: { procedure_id:, column_id: } (Hash) + def cast(value) + case value + in NilClass + nil + in Column + value + # from form + in String => id + h_id = JSON.parse(id, symbolize_names: true) + Column.find(h_id) + # from db + in Hash => h_id + Column.find(h_id) + end + end + + # db -> ruby + def deserialize(value) = cast(value) + + # ruby -> db + def serialize(value) + case value + in NilClass + nil + in Column + JSON.generate(value.h_id) + else + raise ArgumentError, "Invalid value for Column serialization: #{value}" + end + end +end diff --git a/config/initializers/types.rb b/config/initializers/types.rb index 00774df32..a77b4b64d 100644 --- a/config/initializers/types.rb +++ b/config/initializers/types.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true +require Rails.root.join("app/types/column_type") require Rails.root.join("app/types/export_item_type") ActiveSupport.on_load(:active_record) do + ActiveRecord::Type.register(:column, ColumnType) ActiveRecord::Type.register(:export_item, ExportItemType) end diff --git a/spec/types/column_type_spec.rb b/spec/types/column_type_spec.rb new file mode 100644 index 000000000..5512f2b2f --- /dev/null +++ b/spec/types/column_type_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +describe ColumnType do + let(:type) { ColumnType.new } + + describe 'cast' do + it 'from Column' do + column = Column.new(procedure_id: 1, table: 'table', column: 'column') + expect(type.cast(column)).to eq(column) + end + + it 'from nil' do + expect(type.cast(nil)).to eq(nil) + end + + describe 'from form' do + it 'with valid column id' do + column = Column.new(procedure_id: 1, table: 'table', column: 'column') + + expect(Column).to receive(:find).with(column.h_id).and_return(column) + expect(type.cast(column.id)).to eq(column) + end + + it 'with invalid column id' do + expect { type.cast('invalid') }.to raise_error(JSON::ParserError) + + id = { procedure_id: 'invalid', column_id: 'nop' }.to_json + expect { type.cast(id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + describe 'from db' do + it 'with valid column id' do + column = Column.new(procedure_id: 1, table: 'table', column: 'column') + expect(Column).to receive(:find).with(column.h_id).and_return(column) + expect(type.cast(column.h_id)).to eq(column) + end + + it 'with invalid column id' do + h_id = { procedure_id: 'invalid', column_id: 'nop' } + expect { type.cast(h_id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + end + + describe 'deserialize' do + context 'with valid value' do + it 'works' do + column = Column.new(procedure_id: 1, table: 'table', column: 'column') + expect(Column).to receive(:find).with(column.h_id).and_return(column) + + expect(type.deserialize(column.h_id)).to eq(column) + end + end + end + + describe 'serialize' do + it 'with SortedColumn' do + column = Column.new(procedure_id: 1, table: 'table', column: 'column') + expect(type.serialize(column)).to eq(column.h_id.to_json) + end + + it 'with nil' do + expect(type.serialize(nil)).to eq(nil) + end + + it 'with invalid value' do + expect { type.serialize('invalid') }.to raise_error(ArgumentError) + end + end +end