Class: RubyPgExtras::DetectFkColumn

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_pg_extras/detect_fk_column.rb

Constant Summary collapse

PLURAL_RULES =
[
  [/s$/i, "s"],
  [/^(ax|test)is$/i, '\1es'],
  [/(octop|vir)us$/i, '\1i'],
  [/(alias|status)$/i, '\1es'],
  [/(bu)s$/i, '\1ses'],
  [/(buffal|tomat)o$/i, '\1oes'],
  [/([ti])um$/i, '\1a'],
  [/sis$/i, "ses"],
  [/(?:([^f])fe|([lr])f)$/i, '\1\2ves'],
  [/([^aeiouy]|qu)y$/i, '\1ies'],
  [/(x|ch|ss|sh)$/i, '\1es'],
  [/(matr|vert|ind)(?:ix|ex)$/i, '\1ices'],
  [/^(m|l)ouse$/i, '\1ice'],
  [/^(ox)$/i, '\1en'],
  [/(quiz)$/i, '\1zes'],
]
IRREGULAR =
{
  "person" => "people",
  "man" => "men",
  "child" => "children",
  "sex" => "sexes",
  "move" => "moves",
  "zombie" => "zombies",
}
UNCOUNTABLE =
%w(equipment information rice money species series fish sheep jeans police)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.call(column_name, tables) ⇒ Object



32
33
34
# File 'lib/ruby_pg_extras/detect_fk_column.rb', line 32

def self.call(column_name, tables)
  new.call(column_name, tables)
end

Instance Method Details

#call(column_name, tables) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/ruby_pg_extras/detect_fk_column.rb', line 36

def call(column_name, tables)
  # Heuristic: Rails-style foreign keys are usually named `<table_singular>_id`.
  # We accept underscores in the prefix (e.g. `account_user_id` -> `account_users`).
  match = /\A(?<table_singular>.+)_id\z/i.match(column_name.to_s)
  return false unless match

  table_singular = match[:table_singular]
  return false if table_singular.empty?

  tables.include?(pluralize(table_singular))
end

#pluralize(word) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ruby_pg_extras/detect_fk_column.rb', line 48

def pluralize(word)
  # Table names from Postgres are typically lowercase. Normalize before applying rules.
  word = word.to_s.downcase

  return word if UNCOUNTABLE.include?(word)
  return IRREGULAR.fetch(word) if IRREGULAR.key?(word)
  # If the word is already an irregular plural (e.g. "people"), keep it as-is.
  return word if IRREGULAR.value?(word)

  PLURAL_RULES.reverse.each do |(rule, replacement)|
    return word.gsub(rule, replacement) if word.match?(rule)
  end
  word + "s"
end