From a8b121480af1cade0da4388eb50adf79e4b372f6 Mon Sep 17 00:00:00 2001 From: Paul Bernays Date: Tue, 31 Dec 2024 14:24:58 +1000 Subject: [PATCH] feat: add `timestamp_columns` config option --- .../model_annotator/model_wrapper.rb | 12 ++++- lib/annotate_rb/options.rb | 4 ++ .../annotation/annotation_builder_spec.rb | 54 +++++++++++++++++++ spec/lib/annotate_rb/options_spec.rb | 10 ++-- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/lib/annotate_rb/model_annotator/model_wrapper.rb b/lib/annotate_rb/model_annotator/model_wrapper.rb index 2c60d479..7cab4f9d 100644 --- a/lib/annotate_rb/model_annotator/model_wrapper.rb +++ b/lib/annotate_rb/model_annotator/model_wrapper.rb @@ -6,6 +6,8 @@ class ModelWrapper # Should be the wrapper for an ActiveRecord model that serves as the source of truth of the model # of the model that we're annotating + DEFAULT_TIMESTAMP_COLUMNS = %w[created_at updated_at] + def initialize(klass, options) @klass = klass @options = options @@ -143,10 +145,13 @@ def classified_sort(cols) associations = [] id = nil + # specs don't load defaults, so ensure we have defaults here + timestamp_columns = @options[:timestamp_columns] || DEFAULT_TIMESTAMP_COLUMNS + cols.each do |c| if c.name.eql?("id") id = c - elsif c.name.eql?("created_at") || c.name.eql?("updated_at") + elsif timestamp_columns.include?(c.name) timestamps << c elsif c.name[-3, 3].eql?("_id") associations << c @@ -154,7 +159,10 @@ def classified_sort(cols) rest_cols << c end end - [rest_cols, timestamps, associations].each { |a| a.sort_by!(&:name) } + + timestamp_order = timestamp_columns.each_with_index.to_h + timestamps.sort_by! { |col| timestamp_order[col.name] } + [rest_cols, associations].each { |a| a.sort_by!(&:name) } ([id] << rest_cols << timestamps << associations).flatten.compact end diff --git a/lib/annotate_rb/options.rb b/lib/annotate_rb/options.rb index 6b0fa21e..37385498 100644 --- a/lib/annotate_rb/options.rb +++ b/lib/annotate_rb/options.rb @@ -69,6 +69,9 @@ def from(options = {}, state = {}) # ModelAnnotator hide_limit_column_types: "", + # ModelAnnotator + timestamp_columns: ModelAnnotator::ModelWrapper::DEFAULT_TIMESTAMP_COLUMNS, + ignore_columns: nil, # ModelAnnotator ignore_routes: nil, # RouteAnnotator ignore_unknown_models: false, # ModelAnnotator @@ -130,6 +133,7 @@ def from(options = {}, state = {}) :debug, :hide_default_column_types, :hide_limit_column_types, + :timestamp_columns, :ignore_columns, :ignore_routes, :ignore_unknown_models, diff --git a/spec/lib/annotate_rb/model_annotator/annotation/annotation_builder_spec.rb b/spec/lib/annotate_rb/model_annotator/annotation/annotation_builder_spec.rb index 4cd2f6a8..f32947fb 100644 --- a/spec/lib/annotate_rb/model_annotator/annotation/annotation_builder_spec.rb +++ b/spec/lib/annotate_rb/model_annotator/annotation/annotation_builder_spec.rb @@ -182,6 +182,60 @@ it 'works with option "classified_sort"' do is_expected.to eq expected_result end + + context "when default timestamps are included" do + let(:columns) do + [ + mock_column("parent_id", :integer), + mock_column("updated_at", :datetime), + mock_column("name", :string), + mock_column("id", :integer), + mock_column("deleted_at", :datetime), + mock_column("created_at", :datetime) + ] + end + + it "sorts default timestamps second last before associations" do + is_expected.to eq <<~EOS + # == Schema Information + # + # Table name: users + # + # id :integer not null, primary key + # deleted_at :datetime not null + # name :string not null + # created_at :datetime not null + # updated_at :datetime not null + # parent_id :integer not null + # + EOS + end + + context "when timestamps_column option is set" do + let(:options) do + AnnotateRb::Options.new( + classified_sort: true, + timestamp_columns: %w[created_at updated_at deleted_at] + ) + end + + it "sorts configured timestamps into config order" do + is_expected.to eq <<~EOS + # == Schema Information + # + # Table name: users + # + # id :integer not null, primary key + # name :string not null + # created_at :datetime not null + # updated_at :datetime not null + # deleted_at :datetime not null + # parent_id :integer not null + # + EOS + end + end + end end context "when geometry columns are included" do diff --git a/spec/lib/annotate_rb/options_spec.rb b/spec/lib/annotate_rb/options_spec.rb index ad5eceaa..f45afa30 100644 --- a/spec/lib/annotate_rb/options_spec.rb +++ b/spec/lib/annotate_rb/options_spec.rb @@ -56,11 +56,11 @@ describe ".load_defaults" do subject { described_class.new(options, state).load_defaults } + let(:options) { {} } let(:state) { {} } context 'when default value of "show_complete_foreign_keys" is not set' do let(:key) { :show_complete_foreign_keys } - let(:options) { {} } it "returns false" do expect(subject[key]).to eq(false) @@ -76,10 +76,14 @@ end end + describe "default timestamp_columns" do + it "sets defaults matching Rails' convention" do + expect(subject[:timestamp_columns]).to match_array(%w[created_at updated_at]) + end + end + describe "comment options" do context "when using defaults" do - let(:options) { {} } - it "uses the defaults" do expect(subject[:with_comment]).to eq(true) expect(subject[:with_column_comments]).to eq(true)