Class: Hold::Sequel::IdentitySetRepository::WithPolymorphicTypeColumn

Inherits:
Hold::Sequel::IdentitySetRepository show all
Defined in:
lib/hold/sequel/with_polymorphic_type_column.rb

Overview

Subclass of Sequel::IdentitySetRepository which adds support for a polymorphic type column which is used to persist the class of the model.

Constant Summary

Constants inherited from Hold::Sequel::IdentitySetRepository

JUST_ID

Instance Attribute Summary

Attributes inherited from Hold::Sequel::IdentitySetRepository

#db, #default_properties, #id_sequence_table, #identity_mapper, #identity_property, #main_table, #property_mappers

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Hold::Sequel::IdentitySetRepository

#add_observer, #allocates_ids?, #array_cell_for_dataset, #construct_entity_from_id, constructor_dependencies, #contains?, #contains_id?, #count_dataset, #delete, #delete_id, #get_all, #get_by_id, #get_by_property, #get_many_by_ids, #get_many_by_property, #get_many_with_dataset, #get_property, #get_repo_dependencies_from, #get_with_dataset, inject_dependency, #inspect, #mapper, #model_class, model_class, new_from_dependencies, #post_delete, #post_insert, #post_update, #pre_delete, #pre_insert, #pre_update, property_mapper_args, provides_class, provides_features, #query, setter_dependencies, #store, #store_new, #table_id_column, tables, #transaction, #update, #update_by_id

Methods included from IdentitySetRepository

#allocates_ids?, #cell, #contains_id?, #delete_id, #get_by_id, #get_many_by_ids, #id_cell, #load, #reload, #update, #update_by_id

Methods included from Hold::SetRepository

#contains?, #delete, #get_all, #store, #store_new

Constructor Details

#initialize(db) ⇒ WithPolymorphicTypeColumn

Returns a new instance of WithPolymorphicTypeColumn.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 74

def initialize(db)
  super
  @qualified_type_column =
    ::Sequel::SQL::QualifiedIdentifier.new(self.class.type_column_table,
                                           self.class.type_column)

  @aliased_type_column =
    ::Sequel::SQL::AliasedExpression.new(@qualified_type_column, :type)

  @restricted_to_types = self.class.restricted_to_types
  @tables_restricting_type = {}
  self.class.tables.each do |name, options|
    @tables_restricting_type[name] = true if options[:restricts_type]
  end
end

Class Method Details

.class_to_type_mappingObject



16
17
18
19
20
21
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 16

def class_to_type_mapping
  @class_to_type_mapping ||=
    if superclass < WithPolymorphicTypeColumn
      superclass.class_to_type_mapping
    end
end

.restricted_to_typesObject



30
31
32
33
34
35
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 30

def restricted_to_types
  @restricted_to_types ||=
    if superclass < WithPolymorphicTypeColumn
      superclass.restricted_to_types
    end
end

.supported_classesObject



37
38
39
40
41
42
43
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 37

def supported_classes
  if restricted_to_types
    type_to_class_mapping.values_at(*restricted_to_types)
  else
    class_to_type_mapping.keys
  end
end

.type_columnObject



8
9
10
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 8

def type_column
  @type_column ||= superclass.type_column
end

.type_column_tableObject



12
13
14
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 12

def type_column_table
  @type_column_table ||= superclass.type_column_table
end

.type_to_class_mappingObject



23
24
25
26
27
28
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 23

def type_to_class_mapping
  @type_to_class_mapping ||=
    if superclass < WithPolymorphicTypeColumn
      superclass.type_to_class_mapping
    end
end

Instance Method Details

#can_construct_from_id_alone?(properties) ⇒ Boolean

This optimisation has to be turned off for polymorphic repositories, since even if we know the ID, we have to query the db to find out the appropriate class to construct the object as.

Returns:

  • (Boolean)


110
111
112
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 110

def can_construct_from_id_alone?(properties)
  super && @restricted_to_types && @restricted_to_types.length == 1
end

#can_get_class?(model_class) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 90

def can_get_class?(model_class)
  self.class.supported_classes.include?(model_class)
end

#can_set_class?(model_class) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 94

def can_set_class?(model_class)
  self.class.supported_classes.include?(model_class)
end

#columns_aliases_and_tables_for_properties(properties) ⇒ Object

ensure we select the type column in addition to any columns for mapped properties, so we know which class to instantiate for each row.

If we’re restricted to only one class, we don’t need to select the type column



119
120
121
122
123
124
125
126
127
128
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 119

def columns_aliases_and_tables_for_properties(properties)
  columns_by_property, aliased_columns, tables = super
  unless @restricted_to_types && @restricted_to_types.length == 1
    aliased_columns << @aliased_type_column
    unless tables.include?(self.class.type_column_table)
      tables << self.class.type_column_table
    end
  end
  [columns_by_property, aliased_columns, tables]
end

#construct_entity(property_hash, row = nil) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 98

def construct_entity(property_hash, row = nil)
  type_value = row && row[:type] || (return super)
  klass =
    self.class.type_to_class_mapping[type_value] ||
    (fail "WithPolymorphicTypeColumn: type column value #{type_value}" \
          ' not found in mapping')
  klass.new(property_hash)
end

#dataset_to_select_tables(*tables) ⇒ Object

Where ‘restricted_to_types’ has been set, ensure we add a filter to the where clause restricting to rows with the allowed class (or classes).

Except, where one of the tables used is specified in this repo’s config as :restricts_type => true, this is taken to mean that (inner) joining to this table effectively acts as this repo’s restricted_to_types restriction. hence no additional where clause is needed in order to do this. Helps with Class Table Inheritance.



139
140
141
142
143
144
145
146
# File 'lib/hold/sequel/with_polymorphic_type_column.rb', line 139

def dataset_to_select_tables(*tables)
  if @restricted_to_types &&
     !@tables_restricting_type.values_at(*tables).any?
    super.filter(@qualified_type_column => @restricted_to_types)
  else
    super
  end
end