annotaterb 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/annotate_rb/model_annotator/annotation_decider.rb +62 -0
- data/lib/annotate_rb/model_annotator/annotation_generator.rb +94 -0
- data/lib/annotate_rb/model_annotator/annotator.rb +27 -31
- data/lib/annotate_rb/model_annotator/column_annotation_builder.rb +92 -0
- data/lib/annotate_rb/model_annotator/column_attributes_builder.rb +102 -0
- data/lib/annotate_rb/model_annotator/column_type_builder.rb +51 -0
- data/lib/annotate_rb/model_annotator/column_wrapper.rb +84 -0
- data/lib/annotate_rb/model_annotator/constants.rb +2 -2
- data/lib/annotate_rb/model_annotator/file_annotator.rb +6 -2
- data/lib/annotate_rb/model_annotator/file_annotator_instruction.rb +17 -0
- data/lib/annotate_rb/model_annotator/foreign_key_annotation_builder.rb +55 -0
- data/lib/annotate_rb/model_annotator/helper.rb +75 -22
- data/lib/annotate_rb/model_annotator/index_annotation_builder.rb +74 -0
- data/lib/annotate_rb/model_annotator/model_file_annotator.rb +21 -84
- data/lib/annotate_rb/model_annotator/model_files_getter.rb +4 -2
- data/lib/annotate_rb/model_annotator/model_wrapper.rb +155 -0
- data/lib/annotate_rb/model_annotator/related_files_list_builder.rb +137 -0
- data/lib/annotate_rb/model_annotator.rb +11 -1
- data/lib/annotate_rb/options.rb +16 -9
- data/lib/annotate_rb/parser.rb +0 -14
- data/lib/annotate_rb.rb +0 -1
- metadata +13 -4
- data/lib/annotate_rb/env.rb +0 -30
- data/lib/annotate_rb/model_annotator/schema_info.rb +0 -480
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ForeignKeyAnnotationBuilder
|
6
|
+
def initialize(model, options)
|
7
|
+
@model = model
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
fk_info = if @options[:format_markdown]
|
13
|
+
"#\n# ### Foreign Keys\n#\n"
|
14
|
+
else
|
15
|
+
"#\n# Foreign Keys\n#\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
return '' unless @model.connection.respond_to?(:supports_foreign_keys?) &&
|
19
|
+
@model.connection.supports_foreign_keys? && @model.connection.respond_to?(:foreign_keys)
|
20
|
+
|
21
|
+
foreign_keys = @model.connection.foreign_keys(@model.table_name)
|
22
|
+
return '' if foreign_keys.empty?
|
23
|
+
|
24
|
+
format_name = lambda do |fk|
|
25
|
+
return fk.options[:column] if fk.name.blank?
|
26
|
+
|
27
|
+
@options[:show_complete_foreign_keys] ? fk.name : fk.name.gsub(/(?<=^fk_rails_)[0-9a-f]{10}$/, '...')
|
28
|
+
end
|
29
|
+
|
30
|
+
max_size = foreign_keys.map(&format_name).map(&:size).max + 1
|
31
|
+
foreign_keys.sort_by { |fk| [format_name.call(fk), fk.column] }.each do |fk|
|
32
|
+
ref_info = "#{fk.column} => #{fk.to_table}.#{fk.primary_key}"
|
33
|
+
constraints_info = ''
|
34
|
+
constraints_info += "ON DELETE => #{fk.on_delete} " if fk.on_delete
|
35
|
+
constraints_info += "ON UPDATE => #{fk.on_update} " if fk.on_update
|
36
|
+
constraints_info = constraints_info.strip
|
37
|
+
|
38
|
+
fk_info += if @options[:format_markdown]
|
39
|
+
format("# * `%s`%s:\n# * **`%s`**\n",
|
40
|
+
format_name.call(fk),
|
41
|
+
constraints_info.blank? ? '' : " (_#{constraints_info}_)",
|
42
|
+
ref_info)
|
43
|
+
else
|
44
|
+
format("# %-#{max_size}.#{max_size}s %s %s",
|
45
|
+
format_name.call(fk),
|
46
|
+
"(#{ref_info})",
|
47
|
+
constraints_info).rstrip + "\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
fk_info
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -3,51 +3,104 @@
|
|
3
3
|
module AnnotateRb
|
4
4
|
module ModelAnnotator
|
5
5
|
module Helper
|
6
|
-
|
6
|
+
INDEX_CLAUSES = {
|
7
|
+
unique: {
|
8
|
+
default: 'UNIQUE',
|
9
|
+
markdown: '_unique_'
|
10
|
+
},
|
11
|
+
where: {
|
12
|
+
default: 'WHERE',
|
13
|
+
markdown: '_where_'
|
14
|
+
},
|
15
|
+
using: {
|
16
|
+
default: 'USING',
|
17
|
+
markdown: '_using_'
|
18
|
+
}
|
19
|
+
}.freeze
|
7
20
|
|
8
21
|
class << self
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
22
|
+
def mb_chars_ljust(string, length)
|
23
|
+
string = string.to_s
|
24
|
+
padding = length - Helper.width(string)
|
25
|
+
if padding.positive?
|
26
|
+
string + (' ' * padding)
|
27
|
+
else
|
28
|
+
string[0..(length - 1)]
|
29
|
+
end
|
30
|
+
end
|
13
31
|
|
14
|
-
|
32
|
+
def index_unique_info(index, format = :default)
|
33
|
+
index.unique ? " #{INDEX_CLAUSES[:unique][format]}" : ''
|
15
34
|
end
|
16
35
|
|
17
|
-
def
|
18
|
-
|
36
|
+
def index_where_info(index, format = :default)
|
37
|
+
value = index.try(:where).try(:to_s)
|
38
|
+
if value.blank?
|
39
|
+
''
|
40
|
+
else
|
41
|
+
" #{INDEX_CLAUSES[:where][format]} #{value}"
|
42
|
+
end
|
43
|
+
end
|
19
44
|
|
20
|
-
|
21
|
-
|
45
|
+
def index_using_info(index, format = :default)
|
46
|
+
value = index.try(:using) && index.using.try(:to_sym)
|
47
|
+
if !value.blank? && value != :btree
|
48
|
+
" #{INDEX_CLAUSES[:using][format]} #{value}"
|
22
49
|
else
|
23
50
|
''
|
24
51
|
end
|
25
52
|
end
|
26
53
|
|
27
|
-
def
|
28
|
-
|
54
|
+
def map_col_type_to_ruby_classes(col_type)
|
55
|
+
case col_type
|
56
|
+
when 'integer' then Integer.to_s
|
57
|
+
when 'float' then Float.to_s
|
58
|
+
when 'decimal' then BigDecimal.to_s
|
59
|
+
when 'datetime', 'timestamp', 'time' then Time.to_s
|
60
|
+
when 'date' then Date.to_s
|
61
|
+
when 'text', 'string', 'binary', 'inet', 'uuid' then String.to_s
|
62
|
+
when 'json', 'jsonb' then Hash.to_s
|
63
|
+
when 'boolean' then 'Boolean'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def non_ascii_length(string)
|
68
|
+
string.to_s.chars.reject(&:ascii_only?).length
|
29
69
|
end
|
30
70
|
|
31
|
-
|
32
|
-
|
71
|
+
# Simple quoting for the default column value
|
72
|
+
def quote(value)
|
73
|
+
case value
|
74
|
+
when NilClass then 'NULL'
|
75
|
+
when TrueClass then 'TRUE'
|
76
|
+
when FalseClass then 'FALSE'
|
77
|
+
when Float, Integer then value.to_s
|
78
|
+
# BigDecimals need to be output in a non-normalized form and quoted.
|
79
|
+
when BigDecimal then value.to_s('F')
|
80
|
+
when Array then value.map { |v| quote(v) }
|
81
|
+
else
|
82
|
+
value.inspect
|
83
|
+
end
|
33
84
|
end
|
34
85
|
|
35
|
-
def
|
36
|
-
|
86
|
+
def width(string)
|
87
|
+
string.chars.inject(0) { |acc, elem| acc + (elem.bytesize == 3 ? 2 : 1) }
|
37
88
|
end
|
38
89
|
|
39
|
-
def
|
40
|
-
|
90
|
+
def magic_comments_as_string(content)
|
91
|
+
magic_comments = content.scan(Constants::MAGIC_COMMENT_MATCHER).flatten.compact
|
92
|
+
|
93
|
+
if magic_comments.any?
|
94
|
+
magic_comments.join
|
95
|
+
else
|
96
|
+
''
|
97
|
+
end
|
41
98
|
end
|
42
99
|
|
43
100
|
# TODO: Find another implementation that doesn't depend on ActiveSupport
|
44
101
|
def fallback(*args)
|
45
102
|
args.compact.detect(&:present?)
|
46
103
|
end
|
47
|
-
|
48
|
-
def reset_options(options)
|
49
|
-
options.flatten.each { |key| Env.write(key, nil) }
|
50
|
-
end
|
51
104
|
end
|
52
105
|
end
|
53
106
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class IndexAnnotationBuilder
|
6
|
+
def initialize(model, options)
|
7
|
+
@model = model
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def build
|
12
|
+
index_info = if @options[:format_markdown]
|
13
|
+
"#\n# ### Indexes\n#\n"
|
14
|
+
else
|
15
|
+
"#\n# Indexes\n#\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
indexes = @model.retrieve_indexes_from_table
|
19
|
+
return '' if indexes.empty?
|
20
|
+
|
21
|
+
max_size = indexes.collect { |index| index.name.size }.max + 1
|
22
|
+
indexes.sort_by(&:name).each do |index|
|
23
|
+
index_info += if @options[:format_markdown]
|
24
|
+
final_index_string_in_markdown(index)
|
25
|
+
else
|
26
|
+
final_index_string(index, max_size)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
index_info
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def final_index_string_in_markdown(index)
|
36
|
+
details = format(
|
37
|
+
'%s%s%s',
|
38
|
+
Helper.index_unique_info(index, :markdown),
|
39
|
+
Helper.index_where_info(index, :markdown),
|
40
|
+
Helper.index_using_info(index, :markdown)
|
41
|
+
).strip
|
42
|
+
details = " (#{details})" unless details.blank?
|
43
|
+
|
44
|
+
format(
|
45
|
+
"# * `%s`%s:\n# * **`%s`**\n",
|
46
|
+
index.name,
|
47
|
+
details,
|
48
|
+
index_columns_info(index).join("`**\n# * **`")
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def final_index_string(index, max_size)
|
53
|
+
format(
|
54
|
+
"# %-#{max_size}.#{max_size}s %s%s%s%s",
|
55
|
+
index.name,
|
56
|
+
"(#{index_columns_info(index).join(',')})",
|
57
|
+
Helper.index_unique_info(index),
|
58
|
+
Helper.index_where_info(index),
|
59
|
+
Helper.index_using_info(index)
|
60
|
+
).rstrip + "\n"
|
61
|
+
end
|
62
|
+
|
63
|
+
def index_columns_info(index)
|
64
|
+
Array(index.columns).map do |col|
|
65
|
+
if index.try(:orders) && index.orders[col.to_s]
|
66
|
+
"#{col} #{index.orders[col.to_s].upcase}"
|
67
|
+
else
|
68
|
+
col.to_s.gsub("\r", '\r').gsub("\n", '\n')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -2,36 +2,21 @@
|
|
2
2
|
|
3
3
|
module AnnotateRb
|
4
4
|
module ModelAnnotator
|
5
|
-
#
|
5
|
+
# Annotates a model file and its related files (controllers, factories, etc)
|
6
6
|
class ModelFileAnnotator
|
7
7
|
class << self
|
8
|
-
def call(annotated, file,
|
8
|
+
def call(annotated, file, options)
|
9
9
|
begin
|
10
|
-
return false if /#{Constants::SKIP_ANNOTATION_PREFIX}.*/ =~ (File.exist?(file) ? File.read(file) : '')
|
11
10
|
klass = ModelClassGetter.call(file, options)
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
not_sure_this_conditional = (!options[:exclude_sti_subclasses] || !(klass.superclass < ActiveRecord::Base && klass.table_name == klass.superclass.table_name))
|
19
|
-
|
20
|
-
annotate_conditions = [
|
21
|
-
klass_is_a_class,
|
22
|
-
klass_inherits_active_record_base,
|
23
|
-
not_sure_this_conditional,
|
24
|
-
klass_is_not_abstract,
|
25
|
-
klass_table_exists
|
26
|
-
]
|
27
|
-
|
28
|
-
do_annotate = annotate_conditions.all?
|
29
|
-
|
30
|
-
if do_annotate
|
31
|
-
files_annotated = annotate(klass, file, header, options)
|
32
|
-
annotated.concat(files_annotated)
|
12
|
+
instructions = build_instructions(klass, file, options)
|
13
|
+
instructions.each do |instruction|
|
14
|
+
if FileAnnotator.call_with_instructions(instruction)
|
15
|
+
annotated << instruction.file
|
16
|
+
end
|
33
17
|
end
|
34
18
|
|
19
|
+
annotated
|
35
20
|
rescue BadModelFileError => e
|
36
21
|
unless options[:ignore_unknown_models]
|
37
22
|
$stderr.puts "Unable to annotate #{file}: #{e.message}"
|
@@ -45,72 +30,24 @@ module AnnotateRb
|
|
45
30
|
|
46
31
|
private
|
47
32
|
|
48
|
-
|
49
|
-
|
50
|
-
# on the columns and their types) and put it at the front
|
51
|
-
# of the model and fixture source files.
|
52
|
-
#
|
53
|
-
# === Options (opts)
|
54
|
-
# :position_in_class<Symbol>:: where to place the annotated section in model file
|
55
|
-
# :position_in_test<Symbol>:: where to place the annotated section in test/spec file(s)
|
56
|
-
# :position_in_fixture<Symbol>:: where to place the annotated section in fixture file
|
57
|
-
# :position_in_factory<Symbol>:: where to place the annotated section in factory file
|
58
|
-
# :position_in_serializer<Symbol>:: where to place the annotated section in serializer file
|
59
|
-
# :exclude_tests<Symbol>:: whether to skip modification of test/spec files
|
60
|
-
# :exclude_fixtures<Symbol>:: whether to skip modification of fixture files
|
61
|
-
# :exclude_factories<Symbol>:: whether to skip modification of factory files
|
62
|
-
# :exclude_serializers<Symbol>:: whether to skip modification of serializer files
|
63
|
-
# :exclude_scaffolds<Symbol>:: whether to skip modification of scaffold files
|
64
|
-
# :exclude_controllers<Symbol>:: whether to skip modification of controller files
|
65
|
-
# :exclude_helpers<Symbol>:: whether to skip modification of helper files
|
66
|
-
# :exclude_sti_subclasses<Symbol>:: whether to skip modification of files for STI subclasses
|
67
|
-
#
|
68
|
-
# == Returns:
|
69
|
-
# an array of file names that were annotated.
|
70
|
-
#
|
71
|
-
def annotate(klass, file, header, options = {})
|
72
|
-
begin
|
73
|
-
klass.reset_column_information
|
74
|
-
info = SchemaInfo.generate(klass, header, options)
|
75
|
-
model_name = klass.name.underscore
|
76
|
-
table_name = klass.table_name
|
77
|
-
model_file_name = File.join(file)
|
78
|
-
annotated = []
|
79
|
-
|
80
|
-
if FileAnnotator.call(model_file_name, info, :position_in_class, options)
|
81
|
-
annotated << model_file_name
|
82
|
-
end
|
83
|
-
|
84
|
-
Helper.matched_types(options).each do |key|
|
85
|
-
exclusion_key = "exclude_#{key.pluralize}".to_sym
|
86
|
-
position_key = "position_in_#{key}".to_sym
|
87
|
-
|
88
|
-
# Same options for active_admin models
|
89
|
-
if key == 'admin'
|
90
|
-
exclusion_key = 'exclude_class'.to_sym
|
91
|
-
position_key = 'position_in_class'.to_sym
|
92
|
-
end
|
33
|
+
def build_instructions(klass, file, options = {})
|
34
|
+
instructions = []
|
93
35
|
|
94
|
-
|
36
|
+
klass.reset_column_information
|
37
|
+
annotation = AnnotationGenerator.new(klass, options).generate
|
38
|
+
model_name = klass.name.underscore
|
39
|
+
table_name = klass.table_name
|
95
40
|
|
96
|
-
|
41
|
+
model_instruction = FileAnnotatorInstruction.new(file, annotation, :position_in_class, options)
|
42
|
+
instructions << model_instruction
|
97
43
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
.flatten
|
102
|
-
.each do |f|
|
103
|
-
if FileAnnotator.call(f, info, position_key, options)
|
104
|
-
annotated << f
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
rescue StandardError => e
|
109
|
-
$stderr.puts "Unable to annotate #{file}: #{e.message}"
|
110
|
-
$stderr.puts "\t" + e.backtrace.join("\n\t") if options[:trace]
|
44
|
+
related_files = RelatedFilesListBuilder.new(file, model_name, table_name, options).build
|
45
|
+
related_file_instructions = related_files.map do |f, position_key|
|
46
|
+
_instruction = FileAnnotatorInstruction.new(f, annotation, position_key, options)
|
111
47
|
end
|
48
|
+
instructions.concat(related_file_instructions)
|
112
49
|
|
113
|
-
|
50
|
+
instructions
|
114
51
|
end
|
115
52
|
end
|
116
53
|
end
|
@@ -11,6 +11,8 @@ module AnnotateRb
|
|
11
11
|
def call(options)
|
12
12
|
model_files = []
|
13
13
|
|
14
|
+
# Note: This is currently broken as we don't set `is_rake` anywhere.
|
15
|
+
# It's an artifact from the old Annotate gem and how it did control flow.
|
14
16
|
model_files = list_model_files_from_argument(options) if !options[:is_rake]
|
15
17
|
|
16
18
|
return model_files if !model_files.empty?
|
@@ -30,7 +32,7 @@ module AnnotateRb
|
|
30
32
|
rescue SystemCallError
|
31
33
|
$stderr.puts "No models found in directory '#{options[:model_dir].join("', '")}'."
|
32
34
|
$stderr.puts "Either specify models on the command line, or use the --model-dir option."
|
33
|
-
$stderr.puts "Call '
|
35
|
+
$stderr.puts "Call 'annotaterb --help' for more info."
|
34
36
|
# exit 1 # TODO: Return exit code back to caller. Right now it messes up RSpec being able to run
|
35
37
|
end
|
36
38
|
|
@@ -50,7 +52,7 @@ module AnnotateRb
|
|
50
52
|
|
51
53
|
if model_files.size != specified_files.size
|
52
54
|
$stderr.puts "The specified file could not be found in directory '#{options[:model_dir].join("', '")}'."
|
53
|
-
$stderr.puts "Call '
|
55
|
+
$stderr.puts "Call 'annotaterb --help' for more info."
|
54
56
|
# exit 1 # TODO: Return exit code back to caller. Right now it messes up RSpec being able to run
|
55
57
|
end
|
56
58
|
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnnotateRb
|
4
|
+
module ModelAnnotator
|
5
|
+
class ModelWrapper
|
6
|
+
# Should be the wrapper for an ActiveRecord model that serves as the source of truth of the model
|
7
|
+
# of the model that we're annotating
|
8
|
+
|
9
|
+
def initialize(klass, options = {})
|
10
|
+
@klass = klass
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
# Gets the columns of the ActiveRecord model, processes them, and then returns them.
|
15
|
+
def columns
|
16
|
+
@columns ||= begin
|
17
|
+
cols = raw_columns
|
18
|
+
cols += translated_columns
|
19
|
+
|
20
|
+
ignore_columns = @options[:ignore_columns]
|
21
|
+
if ignore_columns
|
22
|
+
cols = cols.reject do |col|
|
23
|
+
col.name.match(/#{ignore_columns}/)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
cols = cols.sort_by(&:name) if @options[:sort]
|
28
|
+
cols = classified_sort(cols) if @options[:classified_sort]
|
29
|
+
|
30
|
+
cols
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def connection
|
35
|
+
@klass.connection
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the unmodified model columns
|
39
|
+
def raw_columns
|
40
|
+
@raw_columns ||= @klass.columns
|
41
|
+
end
|
42
|
+
|
43
|
+
def primary_key
|
44
|
+
@klass.primary_key
|
45
|
+
end
|
46
|
+
|
47
|
+
def table_exists?
|
48
|
+
@klass.table_exists?
|
49
|
+
end
|
50
|
+
|
51
|
+
def column_defaults
|
52
|
+
@klass.column_defaults
|
53
|
+
end
|
54
|
+
|
55
|
+
# Add columns managed by the globalize gem if this gem is being used.
|
56
|
+
# TODO: Audit if this is still needed, it seems like Globalize gem is no longer maintained
|
57
|
+
def translated_columns
|
58
|
+
return [] unless @klass.respond_to?(:translation_class)
|
59
|
+
|
60
|
+
ignored_cols = ignored_translation_table_columns
|
61
|
+
|
62
|
+
@klass.translation_class.columns.reject do |col|
|
63
|
+
ignored_cols.include? col.name.to_sym
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def table_name
|
68
|
+
@klass.table_name
|
69
|
+
end
|
70
|
+
|
71
|
+
def model_name
|
72
|
+
@klass.name.underscore
|
73
|
+
end
|
74
|
+
|
75
|
+
# Calculates the max width of the schema for the model by looking at the columns, schema comments, with respect
|
76
|
+
# to the options.
|
77
|
+
def max_schema_info_width
|
78
|
+
cols = columns
|
79
|
+
|
80
|
+
if with_comments?
|
81
|
+
max_size = cols.map do |column|
|
82
|
+
column.name.size + (column.comment ? Helper.width(column.comment) : 0)
|
83
|
+
end.max || 0
|
84
|
+
max_size += 2
|
85
|
+
else
|
86
|
+
max_size = cols.map(&:name).map(&:size).max
|
87
|
+
end
|
88
|
+
max_size += @options[:format_rdoc] ? 5 : 1
|
89
|
+
|
90
|
+
max_size
|
91
|
+
end
|
92
|
+
|
93
|
+
def retrieve_indexes_from_table
|
94
|
+
table_name = @klass.table_name
|
95
|
+
return [] unless table_name
|
96
|
+
|
97
|
+
indexes = @klass.connection.indexes(table_name)
|
98
|
+
return indexes if indexes.any? || !@klass.table_name_prefix
|
99
|
+
|
100
|
+
# Try to search the table without prefix
|
101
|
+
table_name_without_prefix = table_name.to_s.sub(@klass.table_name_prefix, '')
|
102
|
+
@klass.connection.indexes(table_name_without_prefix)
|
103
|
+
end
|
104
|
+
|
105
|
+
def with_comments?
|
106
|
+
@options[:with_comment] &&
|
107
|
+
raw_columns.first.respond_to?(:comment) &&
|
108
|
+
raw_columns.map(&:comment).any? { |comment| !comment.nil? }
|
109
|
+
end
|
110
|
+
|
111
|
+
def classified_sort(cols)
|
112
|
+
rest_cols = []
|
113
|
+
timestamps = []
|
114
|
+
associations = []
|
115
|
+
id = nil
|
116
|
+
|
117
|
+
cols.each do |c|
|
118
|
+
if c.name.eql?('id')
|
119
|
+
id = c
|
120
|
+
elsif c.name.eql?('created_at') || c.name.eql?('updated_at')
|
121
|
+
timestamps << c
|
122
|
+
elsif c.name[-3, 3].eql?('_id')
|
123
|
+
associations << c
|
124
|
+
else
|
125
|
+
rest_cols << c
|
126
|
+
end
|
127
|
+
end
|
128
|
+
[rest_cols, timestamps, associations].each { |a| a.sort_by!(&:name) }
|
129
|
+
|
130
|
+
([id] << rest_cols << timestamps << associations).flatten.compact
|
131
|
+
end
|
132
|
+
|
133
|
+
# These are the columns that the globalize gem needs to work but
|
134
|
+
# are not necessary for the models to be displayed as annotations.
|
135
|
+
def ignored_translation_table_columns
|
136
|
+
# Construct the foreign column name in the translations table
|
137
|
+
# eg. Model: Car, foreign column name: car_id
|
138
|
+
foreign_column_name = [
|
139
|
+
@klass.translation_class.to_s
|
140
|
+
.gsub('::Translation', '').gsub('::', '_')
|
141
|
+
.downcase,
|
142
|
+
'_id'
|
143
|
+
].join.to_sym
|
144
|
+
|
145
|
+
[
|
146
|
+
:id,
|
147
|
+
:created_at,
|
148
|
+
:updated_at,
|
149
|
+
:locale,
|
150
|
+
foreign_column_name
|
151
|
+
]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|