Class: Sequel::Model::Associations::AssociationReflection

Inherits:
Hash
  • Object
show all
Includes:
Inflections
Defined in:
lib/sequel/model/associations.rb

Overview

AssociationReflection is a Hash subclass that keeps information on Sequel::Model associations. It provides methods to reduce internal code duplication. It should not be instantiated by the user.

Constant Summary

Constants included from Inflections

Inflections::CAMELIZE_CONVERT_REGEXP, Inflections::CAMELIZE_MODULE_REGEXP, Inflections::DASH, Inflections::DEMODULIZE_CONVERT_REGEXP, Inflections::EMPTY_STRING, Inflections::SLASH, Inflections::UNDERSCORE, Inflections::UNDERSCORE_CONVERT_REGEXP1, Inflections::UNDERSCORE_CONVERT_REGEXP2, Inflections::UNDERSCORE_CONVERT_REPLACE, Inflections::UNDERSCORE_MODULE_REGEXP, Inflections::VALID_CONSTANT_NAME_REGEXP

Instance Method Summary collapse

Methods included from Inflections

clear, irregular, plural, singular, uncountable

Methods inherited from Hash

#&, #case, #hstore, #pg_json, #sql_expr, #sql_negate, #sql_or, #|, #~

Instance Method Details

#_add_methodObject

Name symbol for the _add internal association method



21
22
23
# File 'lib/sequel/model/associations.rb', line 21

def _add_method
  :"_add_#{singularize(self[:name])}"
end

#_remove_all_methodObject

Name symbol for the _remove_all internal association method



26
27
28
# File 'lib/sequel/model/associations.rb', line 26

def _remove_all_method
  :"_remove_all_#{self[:name]}"
end

#_remove_methodObject

Name symbol for the _remove internal association method



31
32
33
# File 'lib/sequel/model/associations.rb', line 31

def _remove_method
  :"_remove_#{singularize(self[:name])}"
end

#_setter_methodObject

Name symbol for the _setter association method



36
37
38
# File 'lib/sequel/model/associations.rb', line 36

def _setter_method
  :"_#{self[:name]}="
end

#add_methodObject

Name symbol for the add association method



41
42
43
# File 'lib/sequel/model/associations.rb', line 41

def add_method
  :"add_#{singularize(self[:name])}"
end

#apply_dataset_changes(ds) ⇒ Object

Apply all non-instance specific changes to the given dataset and return it.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/sequel/model/associations.rb', line 62

def apply_dataset_changes(ds)
  ds.extend(AssociationDatasetMethods)
  ds.association_reflection = self
  self[:extend].each{|m| ds.extend(m)}
  ds = ds.select(*select) if select
  if c = self[:conditions]
    ds = (c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c)
  end
  ds = ds.order(*self[:order]) if self[:order]
  ds = ds.limit(*self[:limit]) if self[:limit]
  ds = ds.limit(1) if !returns_array? && self[:key]
  ds = ds.eager(*self[:eager]) if self[:eager]
  ds = ds.distinct if self[:distinct]
  ds
end

#associated_classObject

The class associated to the current model class via this association



51
52
53
# File 'lib/sequel/model/associations.rb', line 51

def associated_class
  cached_fetch(:class){constantize(self[:class_name])}
end

#associated_datasetObject

The dataset associated via this association, with the non-instance specific changes already applied.



57
58
59
# File 'lib/sequel/model/associations.rb', line 57

def associated_dataset
  cached_fetch(:_dataset){apply_dataset_changes(associated_class.dataset.clone)}
end

#association_methodObject

Name symbol for association method, the same as the name of the association.



46
47
48
# File 'lib/sequel/model/associations.rb', line 46

def association_method
  self[:name]
end

#can_have_associated_objects?(obj) ⇒ Boolean

Whether this association can have associated objects, given the current object. Should be false if obj cannot have associated objects because the necessary key columns are NULL.

Returns:

  • (Boolean)


81
82
83
# File 'lib/sequel/model/associations.rb', line 81

def can_have_associated_objects?(obj)
  true
end

#dataset_methodObject

Name symbol for the dataset association method



86
87
88
# File 'lib/sequel/model/associations.rb', line 86

def dataset_method
  :"#{self[:name]}_dataset"
end

#dataset_need_primary_key?Boolean

Whether the dataset needs a primary key to function, true by default.

Returns:

  • (Boolean)


91
92
93
# File 'lib/sequel/model/associations.rb', line 91

def dataset_need_primary_key?
  true
end

#eager_graph_lazy_dataset?Boolean

Whether to eagerly graph a lazy dataset, true by default. If this is false, the association won’t respect the :eager_graph option when loading the association for a single record.

Returns:

  • (Boolean)


135
136
137
# File 'lib/sequel/model/associations.rb', line 135

def eager_graph_lazy_dataset?
  true
end

#eager_limit_strategyObject

The eager limit strategy to use for this dataset.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/sequel/model/associations.rb', line 96

def eager_limit_strategy
  cached_fetch(:_eager_limit_strategy) do
    if self[:limit]
      case s = cached_fetch(:eager_limit_strategy){self[:model].default_eager_limit_strategy || :ruby}
      when true
        ds = associated_class.dataset
        if ds.supports_window_functions?
          :window_function
        else
          :ruby
        end
      else
        s
      end
    else
      nil
    end
  end
end

#eager_loader_keyObject

The key to use for the key hash when eager loading



117
118
119
# File 'lib/sequel/model/associations.rb', line 117

def eager_loader_key
  self[:eager_loader_key]
end

#eager_loading_predicate_keyObject

Alias of predicate_key, only for backwards compatibility.



128
129
130
# File 'lib/sequel/model/associations.rb', line 128

def eager_loading_predicate_key
  predicate_key
end

#eager_loading_use_associated_key?Boolean

By default associations do not need to select a key in an associated table to eagerly load.

Returns:

  • (Boolean)


123
124
125
# File 'lib/sequel/model/associations.rb', line 123

def eager_loading_use_associated_key?
  false
end

#limit_and_offsetObject

The limit and offset for this association (returned as a two element array).



140
141
142
143
144
145
146
# File 'lib/sequel/model/associations.rb', line 140

def limit_and_offset
  if (v = self[:limit]).is_a?(Array)
    v
  else
    [v, nil]
  end
end

#need_associated_primary_key?Boolean

Whether the associated object needs a primary key to be added/removed, false by default.

Returns:

  • (Boolean)


150
151
152
# File 'lib/sequel/model/associations.rb', line 150

def need_associated_primary_key?
  false
end

#predicate_keysObject

The keys to use for loading of the regular dataset, as an array.



155
156
157
# File 'lib/sequel/model/associations.rb', line 155

def predicate_keys
  cached_fetch(:predicate_keys){Array(predicate_key)}
end

#qualify(table, col) ⇒ Object

Qualify col with the given table name. If col is an array of columns, return an array of qualified columns. Only qualifies Symbols and SQL::Identifier values, other values are not modified.



162
163
164
165
166
167
168
169
170
171
# File 'lib/sequel/model/associations.rb', line 162

def qualify(table, col)
  transform(col) do |k|
    case k
    when Symbol, SQL::Identifier
      SQL::QualifiedIdentifier.new(table, k)
    else
      Sequel::Qualifier.new(self[:model].dataset, table).transform(k)
    end
  end
end

#qualify_assoc(col) ⇒ Object

Qualify col with the associated model’s table name.



174
175
176
# File 'lib/sequel/model/associations.rb', line 174

def qualify_assoc(col)
  qualify(associated_class.table_name, col)
end

#qualify_cur(col) ⇒ Object

Qualify col with the current model’s table name.



179
180
181
# File 'lib/sequel/model/associations.rb', line 179

def qualify_cur(col)
  qualify(self[:model].table_name, col)
end

#reciprocalObject

Returns the reciprocal association variable, if one exists. The reciprocal association is the association in the associated class that is the opposite of the current association. For example, Album.many_to_one :artist and Artist.one_to_many :albums are reciprocal associations. This information is to populate reciprocal associations. For example, when you do this_artist.add_album(album) it sets album.artist to this_artist.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/sequel/model/associations.rb', line 189

def reciprocal
  cached_fetch(:reciprocal) do
    possible_recips = []
    fallback_recips = []

    associated_class.all_association_reflections.each do |assoc_reflect|
      if reciprocal_association?(assoc_reflect)
        if deprecated_reciprocal_association?(assoc_reflect)
          fallback_recips << assoc_reflect
        else
          possible_recips << assoc_reflect
        end
      end
    end

    Sequel::Deprecation.deprecate("Multiple reciprocal association candidates found for #{self[:name]} association (#{possible_recips.map{|r| r[:name]}.join(', ')}).  Choosing the first candidate is", "Please explicitly specify the reciprocal option for the #{self[:name]} association") if possible_recips.size >= 2
    if possible_recips.empty? && !fallback_recips.empty?
      possible_recips = fallback_recips
      Sequel::Deprecation.deprecate("All reciprocal association candidates found for #{self[:name]} association have conditions, blocks, or differing primary keys (#{possible_recips.map{|r| r[:name]}.join(', ')}).  Automatic choosing of an reciprocal association with conditions or blocks is", "Please explicitly specify the reciprocal option for the #{self[:name]} association")
    end

    unless possible_recips.empty?
      cached_set(:reciprocal_type, possible_recips.first[:type]) if reciprocal_type.is_a?(Array)
      possible_recips.first[:name]
    end
  end
end

#reciprocal_array?Boolean

Whether the reciprocal of this association returns an array of objects instead of a single object, true by default.

Returns:

  • (Boolean)


219
220
221
# File 'lib/sequel/model/associations.rb', line 219

def reciprocal_array?
  true
end

#remove_all_methodObject

Name symbol for the remove_all_ association method



224
225
226
# File 'lib/sequel/model/associations.rb', line 224

def remove_all_method
  :"remove_all_#{self[:name]}"
end

#remove_before_destroy?Boolean

Whether associated objects need to be removed from the association before being destroyed in order to preserve referential integrity.

Returns:

  • (Boolean)


230
231
232
# File 'lib/sequel/model/associations.rb', line 230

def remove_before_destroy?
  true
end

#remove_methodObject

Name symbol for the remove_ association method



235
236
237
# File 'lib/sequel/model/associations.rb', line 235

def remove_method
  :"remove_#{singularize(self[:name])}"
end

#remove_should_check_existing?Boolean

Whether to check that an object to be disassociated is already associated to this object, false by default.

Returns:

  • (Boolean)


240
241
242
# File 'lib/sequel/model/associations.rb', line 240

def remove_should_check_existing?
  false
end

#returns_array?Boolean

Whether this association returns an array of objects instead of a single object, true by default.

Returns:

  • (Boolean)


246
247
248
# File 'lib/sequel/model/associations.rb', line 246

def returns_array?
  true
end

#selectObject

The columns to select when loading the association.



251
252
253
# File 'lib/sequel/model/associations.rb', line 251

def select
  self[:select]
end

#set_reciprocal_to_self?Boolean

Whether to set the reciprocal association to self when loading associated records, false by default.

Returns:

  • (Boolean)


257
258
259
# File 'lib/sequel/model/associations.rb', line 257

def set_reciprocal_to_self?
  false
end

#setter_methodObject

Name symbol for the setter association method



262
263
264
# File 'lib/sequel/model/associations.rb', line 262

def setter_method
  :"#{self[:name]}="
end