Class: DeclareSchema::Model::HabtmModelShim

Inherits:
Object
  • Object
show all
Defined in:
lib/declare_schema/model/habtm_model_shim.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(join_table, parents, connection:) ⇒ HabtmModelShim

Returns a new instance of HabtmModelShim.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 19

def initialize(join_table, parents, connection:)
  @join_table = join_table

  parents.is_a?(Array) && parents.size == 2 or
    raise ArgumentError, "parents must be <Array[2]>; got #{parents.inspect}"

  # Rails requires HABTM foreign keys to be in alphabetical order, so we start by sorting by those
  parents.sort_by!(&:first)
  @foreign_keys = parents.map(&:first)
  @parent_models = parents.map(&:last)
  @parent_table_names = parent_models.map(&:table_name)

  @connection = connection
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



17
18
19
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 17

def connection
  @connection
end

#foreign_keysObject (readonly)

Returns the value of attribute foreign_keys.



17
18
19
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 17

def foreign_keys
  @foreign_keys
end

#join_tableObject (readonly)

Returns the value of attribute join_table.



17
18
19
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 17

def join_table
  @join_table
end

#parent_modelsObject (readonly)

Returns the value of attribute parent_models.



17
18
19
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 17

def parent_models
  @parent_models
end

#parent_table_namesObject (readonly)

Returns the value of attribute parent_table_names.



17
18
19
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 17

def parent_table_names
  @parent_table_names
end

Class Method Details

.from_reflection(reflection) ⇒ Object



7
8
9
10
11
12
13
14
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 7

def from_reflection(reflection)
  new(reflection.join_table,
      [
        [reflection.foreign_key, reflection.active_record],
        [reflection.association_foreign_key, reflection.klass]
      ],
      connection: reflection.active_record.connection)
end

Instance Method Details

#_declared_primary_keyObject



80
81
82
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 80

def _declared_primary_key
  foreign_keys
end

#_table_optionsObject



34
35
36
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 34

def _table_options
  {}
end

#columns_hashObject

Mirror the AR class API for ‘model.columns_hash` so the migrator’s change_column_back / add_column_back paths work uniformly across real AR models and HABTM shims. Backed by ‘connection.columns(table_name)` rather than AR’s class-level cache because the shim has no class-level cache.



55
56
57
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 55

def columns_hash
  connection.columns(table_name).index_by(&:name)
end

#constraint_definitionsObject



101
102
103
104
105
106
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 101

def constraint_definitions
  @constraint_definitions ||= Set.new([
    ForeignKeyDefinition.new(foreign_keys.first, constraint_name: "#{join_table}_FK1", child_table_name: @join_table, parent_table_name: parent_table_names.first, dependent: :delete),
    ForeignKeyDefinition.new(foreign_keys.last, constraint_name: "#{join_table}_FK2", child_table_name: @join_table, parent_table_name: parent_table_names.last, dependent: :delete)
  ])
end

#field_specsObject



59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 59

def field_specs
  foreign_keys.each_with_index.each_with_object({}) do |(foreign_key, i), result|
    parent_model = parent_models[i]
    result[foreign_key] =
      if parent_model.respond_to?(:_foreign_key_field_spec)
        # declare_schema model: mirror the parent's primary key (type, limit, etc.)
        parent_model._foreign_key_field_spec(self, foreign_key, position: i, null: false)
      else
        # Non-declare_schema parent: fall back to the configured default PK type.
        ::DeclareSchema::Model::FieldSpec.new(self, foreign_key, ::DeclareSchema.default_generated_primary_key_type, position: i, null: false)
      end
  end
end

#ignore_indexesObject



97
98
99
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 97

def ignore_indexes
  @ignore_indexes ||= Set.new
end

#index_definitionsObject



84
85
86
87
88
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 84

def index_definitions
  [
    IndexDefinition.new(foreign_keys.last, table_name: table_name, unique: false) # index for queries where we only have the last foreign key
  ]
end

#index_definitions_with_primary_keyObject



90
91
92
93
94
95
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 90

def index_definitions_with_primary_key
  [
    *index_definitions,
    IndexDefinition.new(foreign_keys, table_name: table_name, name: Model::IndexDefinition::PRIMARY_KEY_NAME, unique: true) # creates a primary composite key on both foreign keys
  ]
end

#primary_keyObject

The HABTM join table’s primary key is the composite of its two foreign keys. (Rails 7.1+ supports composite PKs natively; on 7.0 nothing in AR introspects this shim, so returning an Array is safe for our callers.)



76
77
78
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 76

def primary_key
  foreign_keys
end

#table_nameObject



38
39
40
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 38

def table_name
  join_table
end

#table_name=(new_table_name) ⇒ Object

The migrator (in change_column_back / add_column_back / etc.) wraps column introspection in ‘with_previous_model_table_name`, which expects a model that exposes `table_name=`. Real AR classes do; this shim doesn’t keep AR-style cached metadata keyed on table_name, so we just rewrite @join_table – the only state our ‘table_name` reads.



47
48
49
# File 'lib/declare_schema/model/habtm_model_shim.rb', line 47

def table_name=(new_table_name)
  @join_table = new_table_name
end