annotaterb 4.0.0 → 4.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -5
  3. data/VERSION +1 -1
  4. data/lib/annotate_rb/model_annotator/annotation_decider.rb +62 -0
  5. data/lib/annotate_rb/model_annotator/annotation_diff.rb +19 -0
  6. data/lib/annotate_rb/model_annotator/annotation_diff_generator.rb +44 -0
  7. data/lib/annotate_rb/model_annotator/annotation_generator.rb +94 -0
  8. data/lib/annotate_rb/model_annotator/annotator.rb +27 -31
  9. data/lib/annotate_rb/model_annotator/column_annotation_builder.rb +92 -0
  10. data/lib/annotate_rb/model_annotator/column_attributes_builder.rb +102 -0
  11. data/lib/annotate_rb/model_annotator/column_type_builder.rb +51 -0
  12. data/lib/annotate_rb/model_annotator/column_wrapper.rb +84 -0
  13. data/lib/annotate_rb/model_annotator/constants.rb +2 -2
  14. data/lib/annotate_rb/model_annotator/file_annotator.rb +9 -11
  15. data/lib/annotate_rb/model_annotator/file_annotator_instruction.rb +17 -0
  16. data/lib/annotate_rb/model_annotator/foreign_key_annotation_builder.rb +55 -0
  17. data/lib/annotate_rb/model_annotator/helper.rb +75 -22
  18. data/lib/annotate_rb/model_annotator/index_annotation_builder.rb +74 -0
  19. data/lib/annotate_rb/model_annotator/model_file_annotator.rb +21 -84
  20. data/lib/annotate_rb/model_annotator/model_files_getter.rb +4 -2
  21. data/lib/annotate_rb/model_annotator/model_wrapper.rb +155 -0
  22. data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +137 -0
  23. data/lib/annotate_rb/model_annotator.rb +13 -1
  24. data/lib/annotate_rb/options.rb +16 -9
  25. data/lib/annotate_rb/parser.rb +0 -14
  26. data/lib/annotate_rb.rb +0 -1
  27. metadata +15 -4
  28. data/lib/annotate_rb/env.rb +0 -30
  29. data/lib/annotate_rb/model_annotator/schema_info.rb +0 -480
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af9f792c5cb7386482abff5b7fb151dd000785316e0849139795ce473d48d076
4
- data.tar.gz: 3d96f0869c4fa6616570bd1e9d077c962e56f59be4437496fc0cd0e428b5f3e3
3
+ metadata.gz: 8888511eb71e6d0c45eadf9f562767868adf7cb9f2c5c58d6eb3458a65dfdc31
4
+ data.tar.gz: 51d25d56e5068979a09d4562e7018b0272f8f73e952941a4f66faece7408cc11
5
5
  SHA512:
6
- metadata.gz: 8cf8cb1fe5183a9f814272173f8af849499789790a87c63fa15de25a561c249490c7fefc8605c69464298923c14d6349d29ece493ab35c22e37466a0707e27b1
7
- data.tar.gz: 0e43bbc446a18dd28c08c68bda96e3acfe58b427e3d5d16f0836a713456629280dcc9eb67781013e1bf5a8c621cb3068b8e2058fb82267cc3a6e115805f64fad
6
+ metadata.gz: 9b878bfc48836e52fe762c547870b67619427772e54efd28835e8699371dc60fdb5511649d9f2bf39431541a9b07f8e32188469526dd109553f71badedd6ec45
7
+ data.tar.gz: df69b71c4c10cc046ebd6cf0a21391262b90e0bcffe19556b59214d7658623fa323a7adbf24e711726bb685377e47596d9b95fed9c2425f22f4877264eed97d8
data/README.md CHANGED
@@ -60,10 +60,7 @@ $ bin/rails g annotate_rb:install
60
60
  This will copy a rake task into your Rails project's `lib/tasks` directory that will hook into the Rails project rake tasks, automatically running AnnotateRb after database migration rake tasks.
61
61
 
62
62
  ## Migrating from the annotate gem
63
- The old [annotate gem](https://github.com/ctran/annotate_models) relied on environment variables and hardcoded values in rake files for configuration. AnnotateRb is different. It reads from an optional configuration yml file and options from the CLI to function.
64
-
65
- * Remove the following files `lib/tasks/annotate_models.rake`, `lib/tasks/annotate_models_migrate.rake`, `lib/tasks/annotate_routes.rake`.
66
- * Run the generator install command above.
63
+ Refer to the [migration guide](MIGRATION_GUIDE.md).
67
64
 
68
65
  ## Usage
69
66
 
@@ -160,7 +157,9 @@ Previously in the [Annotate](https://github.com/ctran/annotate_models) you could
160
157
  position: after
161
158
  ```
162
159
 
163
- Annotaterb reads first from the configuration file, if it exists, then merges it with any options passed into the CLI.
160
+ Annotaterb reads first from the configuration file, if it exists, then merges it with any options passed into the CLI.
161
+
162
+ For further details visit the [section in the migration guide](MIGRATION_GUIDE.md#automatic-annotations-after-running-database-migration-commands).
164
163
 
165
164
  ### How to skip annotating a particular model
166
165
  If you want to always skip annotations on a particular model, add this string
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.0.0
1
+ 4.1.1
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ # Class that encapsulates the logic to decide whether to annotate a model file and its related files or not.
6
+ class AnnotationDecider
7
+ def initialize(file, options)
8
+ @file = file
9
+ @options = options
10
+ end
11
+
12
+ def annotate?
13
+ return false if file_contains_skip_annotation
14
+
15
+ begin
16
+ klass = ModelClassGetter.call(@file, @options)
17
+
18
+ klass_is_a_class = klass.is_a?(Class)
19
+ klass_inherits_active_record_base = klass < ActiveRecord::Base
20
+ klass_is_not_abstract = klass.respond_to?(:abstract_class) && !klass.abstract_class?
21
+ klass_table_exists = klass.respond_to?(:abstract_class) && klass.table_exists?
22
+
23
+ not_sure_this_conditional = (!@options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name))
24
+
25
+ annotate_conditions = [
26
+ klass_is_a_class,
27
+ klass_inherits_active_record_base,
28
+ not_sure_this_conditional,
29
+ klass_is_not_abstract,
30
+ klass_table_exists
31
+ ]
32
+
33
+ to_annotate = annotate_conditions.all?
34
+
35
+ return to_annotate
36
+ rescue BadModelFileError => e
37
+ unless @options[:ignore_unknown_models]
38
+ $stderr.puts "Unable to annotate #{@file}: #{e.message}"
39
+ $stderr.puts "\t" + e.backtrace.join("\n\t") if @options[:trace]
40
+ end
41
+ rescue StandardError => e
42
+ $stderr.puts "Unable to annotate #{@file}: #{e.message}"
43
+ $stderr.puts "\t" + e.backtrace.join("\n\t") if @options[:trace]
44
+ end
45
+
46
+ false
47
+ end
48
+
49
+ private
50
+
51
+ def file_contains_skip_annotation
52
+ file_string = File.exist?(@file) ? File.read(@file) : ''
53
+
54
+ if /#{Constants::SKIP_ANNOTATION_PREFIX}.*/ =~ file_string
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ # Plain old Ruby object for holding the differences
6
+ class AnnotationDiff
7
+ attr_reader :current_columns, :new_columns
8
+
9
+ def initialize(current_columns, new_columns)
10
+ @current_columns = current_columns.dup.freeze
11
+ @new_columns = new_columns.dup.freeze
12
+ end
13
+
14
+ def changed?
15
+ @changed ||= @current_columns != @new_columns
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ # Compares the current file content and new annotation block and generates the column annotation differences
6
+ class AnnotationDiffGenerator
7
+ HEADER_PATTERN = /(^# Table name:.*?\n(#.*[\r]?\n)*[\r]?)/.freeze
8
+ COLUMN_PATTERN = /^#[\t ]+[\w\*\.`\[\]():]+[\t ]+.+$/.freeze
9
+
10
+ class << self
11
+ def call(file_content, annotation_block)
12
+ new(file_content, annotation_block).generate
13
+ end
14
+ end
15
+
16
+ # @param [String] file_content The current file content of the model file we intend to annotate
17
+ # @param [String] annotation_block The annotation block we intend to write to the model file
18
+ def initialize(file_content, annotation_block)
19
+ @file_content = file_content
20
+ @annotation_block = annotation_block
21
+ end
22
+
23
+ def generate
24
+ # Ignore the Schema version line because it changes with each migration
25
+ current_annotations = @file_content.match(HEADER_PATTERN).to_s
26
+ new_annotations = @annotation_block.match(HEADER_PATTERN).to_s
27
+
28
+ if current_annotations.present?
29
+ current_annotation_columns = current_annotations.scan(COLUMN_PATTERN).sort
30
+ else
31
+ current_annotation_columns = []
32
+ end
33
+
34
+ if new_annotations.present?
35
+ new_annotation_columns = new_annotations.scan(COLUMN_PATTERN).sort
36
+ else
37
+ new_annotation_columns = []
38
+ end
39
+
40
+ _result = AnnotationDiff.new(current_annotation_columns, new_annotation_columns)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ class AnnotationGenerator
6
+ # Annotate Models plugin use this header
7
+ PREFIX = '== Schema Information'.freeze
8
+ PREFIX_MD = '## Schema Information'.freeze
9
+
10
+ END_MARK = '== Schema Information End'.freeze
11
+
12
+ MD_NAMES_OVERHEAD = 6
13
+ MD_TYPE_ALLOWANCE = 18
14
+
15
+ def initialize(klass, options = {})
16
+ @model = ModelWrapper.new(klass, options)
17
+ @options = options
18
+ @info = "" # TODO: Make array and build string that way
19
+ end
20
+
21
+ def generate
22
+ @info = "# #{header}\n"
23
+ @info += schema_header_text
24
+
25
+ max_size = @model.max_schema_info_width
26
+
27
+ if @options[:format_markdown]
28
+ @info += format("# %-#{max_size + MD_NAMES_OVERHEAD}.#{max_size + MD_NAMES_OVERHEAD}s | %-#{MD_TYPE_ALLOWANCE}.#{MD_TYPE_ALLOWANCE}s | %s\n",
29
+ 'Name',
30
+ 'Type',
31
+ 'Attributes')
32
+ @info += "# #{'-' * (max_size + MD_NAMES_OVERHEAD)} | #{'-' * MD_TYPE_ALLOWANCE} | #{'-' * 27}\n"
33
+ end
34
+
35
+ @info += @model.columns.map do |col|
36
+ ColumnAnnotationBuilder.new(col, @model, max_size, @options).build
37
+ end.join
38
+
39
+ if @options[:show_indexes] && @model.table_exists?
40
+ @info += IndexAnnotationBuilder.new(@model, @options).build
41
+ end
42
+
43
+ if @options[:show_foreign_keys] && @model.table_exists?
44
+ @info += ForeignKeyAnnotationBuilder.new(@model, @options).build
45
+ end
46
+
47
+ @info += schema_footer_text
48
+
49
+ @info
50
+ end
51
+
52
+ def header
53
+ header = @options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup
54
+ version = ActiveRecord::Migrator.current_version rescue 0
55
+
56
+ if @options[:include_version] && version > 0
57
+ header += "\n# Schema version: #{version}"
58
+ end
59
+
60
+ header
61
+ end
62
+
63
+ def schema_header_text
64
+ info = []
65
+ info << "#"
66
+
67
+ if @options[:format_markdown]
68
+ info << "# Table name: `#{@model.table_name}`"
69
+ info << "#"
70
+ info << "# ### Columns"
71
+ else
72
+ info << "# Table name: #{@model.table_name}"
73
+ end
74
+ info << "#\n" # We want the last line break
75
+
76
+ info.join("\n")
77
+ end
78
+
79
+ def schema_footer_text
80
+ info = []
81
+
82
+ if @options[:format_rdoc]
83
+ info << "#--"
84
+ info << "# #{END_MARK}"
85
+ info << "#++\n"
86
+ else
87
+ info << "#\n"
88
+ end
89
+
90
+ info.join("\n")
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,31 +1,20 @@
1
- # require 'bigdecimal'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module AnnotateRb
4
4
  module ModelAnnotator
5
5
  class Annotator
6
- # Annotate Models plugin use this header
7
- PREFIX = '== Schema Information'.freeze
8
- PREFIX_MD = '## Schema Information'.freeze
9
-
10
- MAGIC_COMMENT_MATCHER = Regexp.new(/(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/).freeze
11
-
12
6
  class << self
13
- # We're passed a name of things that might be
14
- # ActiveRecord models. If we can find the class, and
15
- # if its a subclass of ActiveRecord::Base,
16
- # then pass it to the associated block
17
7
  def do_annotations(options = {})
18
- header = options[:format_markdown] ? PREFIX_MD.dup : PREFIX.dup
19
- version = ActiveRecord::Migrator.current_version rescue 0
20
- if options[:include_version] && version > 0
21
- header << "\n# Schema version: #{version}"
22
- end
23
-
24
8
  annotated = []
25
- model_files_to_annotate = ModelFilesGetter.call(options)
26
9
 
27
- model_files_to_annotate.each do |path, filename|
28
- ModelFileAnnotator.call(annotated, File.join(path, filename), header, options)
10
+ model_files_to_consider = ModelFilesGetter.call(options)
11
+
12
+ model_files_to_consider.each do |path, filename|
13
+ file = File.join(path, filename)
14
+
15
+ if AnnotationDecider.new(file, options).annotate?
16
+ ModelFileAnnotator.call(annotated, file, options)
17
+ end
29
18
  end
30
19
 
31
20
  if annotated.empty?
@@ -37,34 +26,41 @@ module AnnotateRb
37
26
 
38
27
  def remove_annotations(options = {})
39
28
  deannotated = []
40
- deannotated_klass = false
41
- ModelFilesGetter.call(options).each do |file|
42
- file = File.join(file)
29
+
30
+ model_files_to_consider = ModelFilesGetter.call(options)
31
+
32
+ model_files_to_consider.each do |path, filename|
33
+ deannotated_klass = false
34
+ file = File.join(path, filename)
35
+
43
36
  begin
44
37
  klass = ModelClassGetter.call(file, options)
45
38
  if klass < ActiveRecord::Base && !klass.abstract_class?
46
39
  model_name = klass.name.underscore
47
40
  table_name = klass.table_name
48
- model_file_name = file
49
- deannotated_klass = true if FileAnnotationRemover.call(model_file_name, options)
50
41
 
51
- patterns = PatternGetter.call(options)
42
+ if FileAnnotationRemover.call(file, options)
43
+ deannotated_klass = true
44
+ end
45
+
46
+ related_files = RelatedFilesListBuilder.new(file, model_name, table_name, options).build
52
47
 
53
- patterns
54
- .map { |f| FileNameResolver.call(f, model_name, table_name) }
55
- .each do |f|
48
+ related_files.each do |f, _position_key|
56
49
  if File.exist?(f)
57
50
  FileAnnotationRemover.call(f, options)
58
- deannotated_klass = true
59
51
  end
60
52
  end
61
53
  end
62
- deannotated << klass if deannotated_klass
54
+
55
+ if deannotated_klass
56
+ deannotated << klass
57
+ end
63
58
  rescue StandardError => e
64
59
  $stderr.puts "Unable to deannotate #{File.join(file)}: #{e.message}"
65
60
  $stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace]
66
61
  end
67
62
  end
63
+
68
64
  puts "Removed annotations from: #{deannotated.join(', ')}"
69
65
  end
70
66
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ class ColumnAnnotationBuilder
6
+ BARE_TYPE_ALLOWANCE = 16
7
+ MD_TYPE_ALLOWANCE = 18
8
+
9
+ def initialize(column, model, max_size, options)
10
+ @column = column
11
+ @model = model
12
+ @max_size = max_size
13
+ @options = options
14
+ end
15
+
16
+ def build
17
+ result = ''
18
+
19
+ is_primary_key = is_column_primary_key?(@model, @column.name)
20
+
21
+ table_indices = @model.retrieve_indexes_from_table
22
+ column_indices = table_indices.select { |ind| ind.columns.include?(@column.name) }
23
+
24
+ column_attributes = ColumnAttributesBuilder.new(@column, @options, is_primary_key, column_indices).build
25
+ formatted_column_type = ColumnTypeBuilder.new(@column, @options).build
26
+
27
+ col_name = if @model.with_comments? && @column.comment
28
+ "#{@column.name}(#{@column.comment.gsub(/\n/, '\\n')})"
29
+ else
30
+ @column.name
31
+ end
32
+
33
+ if @options[:format_rdoc]
34
+ result += format("# %-#{@max_size}.#{@max_size}s<tt>%s</tt>",
35
+ "*#{col_name}*::",
36
+ column_attributes.unshift(formatted_column_type).join(', ')).rstrip + "\n"
37
+ elsif @options[:format_yard]
38
+ result += sprintf("# @!attribute #{col_name}") + "\n"
39
+
40
+ if @column.respond_to?(:array) && @column.array
41
+ ruby_class = "Array<#{Helper.map_col_type_to_ruby_classes(formatted_column_type)}>"
42
+ else
43
+ ruby_class = Helper.map_col_type_to_ruby_classes(formatted_column_type)
44
+ end
45
+
46
+ result += sprintf("# @return [#{ruby_class}]") + "\n"
47
+ elsif @options[:format_markdown]
48
+ name_remainder = @max_size - col_name.length - Helper.non_ascii_length(col_name)
49
+ type_remainder = (MD_TYPE_ALLOWANCE - 2) - formatted_column_type.length
50
+ result += format("# **`%s`**%#{name_remainder}s | `%s`%#{type_remainder}s | `%s`",
51
+ col_name,
52
+ ' ',
53
+ formatted_column_type,
54
+ ' ',
55
+ column_attributes.join(', ').rstrip).gsub('``', ' ').rstrip + "\n"
56
+ else
57
+ result += format_default(col_name, @max_size, formatted_column_type, column_attributes)
58
+ end
59
+
60
+ result
61
+ end
62
+
63
+ private
64
+
65
+ def format_default(col_name, max_size, col_type, attrs)
66
+ format('# %s:%s %s',
67
+ Helper.mb_chars_ljust(col_name, max_size),
68
+ Helper.mb_chars_ljust(col_type, BARE_TYPE_ALLOWANCE),
69
+ attrs.join(', ')).rstrip + "\n"
70
+ end
71
+
72
+ # TODO: Simplify this conditional
73
+ def is_column_primary_key?(model, column_name)
74
+ if model.primary_key
75
+ if model.primary_key.is_a?(Array)
76
+ # If the model has multiple primary keys, check if this column is one of them
77
+ if model.primary_key.collect(&:to_sym).include?(column_name.to_sym)
78
+ return true
79
+ end
80
+ else
81
+ # If model has 1 primary key, check if this column is it
82
+ if column_name.to_sym == model.primary_key.to_sym
83
+ return true
84
+ end
85
+ end
86
+ end
87
+
88
+ false
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ class ColumnAttributesBuilder
6
+ # Don't show default value for these column types
7
+ NO_DEFAULT_COL_TYPES = %w[json jsonb hstore].freeze
8
+
9
+ def initialize(column, options, is_primary_key, column_indices)
10
+ @column = ColumnWrapper.new(column)
11
+ @options = options
12
+ @is_primary_key = is_primary_key
13
+ @column_indices = column_indices
14
+ end
15
+
16
+ # Get the list of attributes that should be included in the annotation for
17
+ # a given column.
18
+ def build
19
+ column_type = @column.column_type_string
20
+ attrs = []
21
+
22
+ unless @column.default.nil? || hide_default?
23
+ schema_default = "default(#{@column.default_string})"
24
+
25
+ attrs << schema_default
26
+ end
27
+
28
+ if @column.unsigned?
29
+ attrs << 'unsigned'
30
+ end
31
+
32
+ if !@column.null
33
+ attrs << 'not null'
34
+ end
35
+
36
+ if @is_primary_key
37
+ attrs << 'primary key'
38
+ end
39
+
40
+ is_special_type = %w[spatial geometry geography].include?(column_type)
41
+ is_decimal_type = column_type == 'decimal'
42
+
43
+ if !is_decimal_type && !is_special_type
44
+ if @column.limit && !@options[:format_yard]
45
+ if @column.limit.is_a?(Array)
46
+ attrs << "(#{@column.limit.join(', ')})"
47
+ end
48
+ end
49
+ end
50
+
51
+ # Check out if we got an array column
52
+ if @column.array?
53
+ attrs << 'is an Array'
54
+ end
55
+
56
+ # Check out if we got a geometric column
57
+ # and print the type and SRID
58
+ if @column.geometry_type?
59
+ attrs << "#{@column.geometry_type}, #{@column.srid}"
60
+ elsif @column.geometric_type? && @column.geometric_type.present?
61
+ attrs << "#{@column.geometric_type.to_s.downcase}, #{@column.srid}"
62
+ end
63
+
64
+ # Check if the column has indices and print "indexed" if true
65
+ # If the index includes another column, print it too.
66
+ if @options[:simple_indexes]
67
+ # Note: there used to be a klass.table_exists? call here, but removed it as it seemed unnecessary.
68
+
69
+ sorted_column_indices&.each do |index|
70
+ indexed_columns = index.columns.reject { |i| i == @column.name }
71
+
72
+ if indexed_columns.empty?
73
+ attrs << 'indexed'
74
+ else
75
+ attrs << "indexed => [#{indexed_columns.join(', ')}]"
76
+ end
77
+ end
78
+ end
79
+
80
+ attrs
81
+ end
82
+
83
+ def sorted_column_indices
84
+ # Not sure why there were & safe accessors here, but keeping in for time being.
85
+ sorted_indices = @column_indices&.sort_by(&:name)
86
+
87
+ _sorted_indices = sorted_indices.reject { |ind| ind.columns.is_a?(String) }
88
+ end
89
+
90
+ def hide_default?
91
+ excludes =
92
+ if @options[:hide_default_column_types].blank?
93
+ NO_DEFAULT_COL_TYPES
94
+ else
95
+ @options[:hide_default_column_types].split(',')
96
+ end
97
+
98
+ excludes.include?(@column.column_type_string)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ class ColumnTypeBuilder
6
+ # Don't show limit (#) on these column types
7
+ # Example: show "integer" instead of "integer(4)"
8
+ NO_LIMIT_COL_TYPES = %w[integer bigint boolean].freeze
9
+
10
+ def initialize(column, options)
11
+ @column = ColumnWrapper.new(column)
12
+ @options = options
13
+ end
14
+
15
+ # Returns the formatted column type as a string.
16
+ def build
17
+ column_type = @column.column_type_string
18
+
19
+ formatted_column_type = column_type
20
+
21
+ is_special_type = %w[spatial geometry geography].include?(column_type)
22
+ is_decimal_type = column_type == 'decimal'
23
+
24
+ if is_decimal_type
25
+ formatted_column_type = "decimal(#{@column.precision}, #{@column.scale})"
26
+ elsif is_special_type
27
+ # Do nothing. Kept as a code fragment in case we need to do something here.
28
+ else
29
+ if @column.limit && !@options[:format_yard]
30
+ if !@column.limit.is_a?(Array) && !hide_limit?
31
+ formatted_column_type = column_type + "(#{@column.limit})"
32
+ end
33
+ end
34
+ end
35
+
36
+ formatted_column_type
37
+ end
38
+
39
+ def hide_limit?
40
+ excludes =
41
+ if @options[:hide_limit_column_types].blank?
42
+ NO_LIMIT_COL_TYPES
43
+ else
44
+ @options[:hide_limit_column_types].split(',')
45
+ end
46
+
47
+ excludes.include?(@column.column_type_string)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnnotateRb
4
+ module ModelAnnotator
5
+ class ColumnWrapper
6
+ def initialize(column)
7
+ @column = column
8
+ end
9
+
10
+ def default
11
+ # Note: Used to be klass.column_defaults[name], where name is the column name.
12
+ # Looks to be identical, but keeping note here in case there are differences.
13
+ _column_default = @column.default
14
+ end
15
+
16
+ def default_string
17
+ Helper.quote(@column.default)
18
+ end
19
+
20
+ def type
21
+ @column.type
22
+ end
23
+
24
+ def column_type_string
25
+ if (@column.respond_to?(:bigint?) && @column.bigint?) || /\Abigint\b/ =~ @column.sql_type
26
+ 'bigint'
27
+ else
28
+ (@column.type || @column.sql_type).to_s
29
+ end
30
+ end
31
+
32
+ def unsigned?
33
+ @column.respond_to?(:unsigned?) && @column.unsigned?
34
+ end
35
+
36
+ def null
37
+ @column.null
38
+ end
39
+
40
+ def precision
41
+ @column.precision
42
+ end
43
+
44
+ def scale
45
+ @column.scale
46
+ end
47
+
48
+ def limit
49
+ @column.limit
50
+ end
51
+
52
+ def geometry_type?
53
+ @column.respond_to?(:geometry_type)
54
+ end
55
+
56
+ def geometry_type
57
+ # TODO: Check if we need to check if it responds before accessing the geometry type
58
+ @column.geometry_type
59
+ end
60
+
61
+ def geometric_type?
62
+ @column.respond_to?(:geometric_type)
63
+ end
64
+
65
+ def geometric_type
66
+ # TODO: Check if we need to check if it responds before accessing the geometric type
67
+ @column.geometric_type
68
+ end
69
+
70
+ def srid
71
+ # TODO: Check if we need to check if it responds before accessing the srid
72
+ @column.srid
73
+ end
74
+
75
+ def array?
76
+ @column.respond_to?(:array) && @column.array
77
+ end
78
+
79
+ def name
80
+ @column.name
81
+ end
82
+ end
83
+ end
84
+ end