lib/zermelo/associations/class_methods.rb in zermelo-1.1.0 vs lib/zermelo/associations/class_methods.rb in zermelo-1.2.0
- old
+ new
@@ -1,14 +1,12 @@
require 'zermelo/associations/association_data'
require 'zermelo/associations/index_data'
-require 'zermelo/associations/belongs_to'
-require 'zermelo/associations/has_and_belongs_to_many'
-require 'zermelo/associations/has_many'
-require 'zermelo/associations/has_one'
-require 'zermelo/associations/has_sorted_set'
+require 'zermelo/associations/singular'
+require 'zermelo/associations/multiple'
require 'zermelo/associations/index'
+require 'zermelo/associations/range_index'
require 'zermelo/associations/unique_index'
# NB: this module gets mixed in to Zermelo::Record as class methods
# TODO update other side of associations without having to load the record (?)
@@ -28,44 +26,54 @@
index(::Zermelo::Associations::Index, arg, :type => att_types[arg])
end
nil
end
+ def range_index_by(*args)
+ att_types = attribute_types
+ args.each do |arg|
+ index(::Zermelo::Associations::RangeIndex, arg, :type => att_types[arg])
+ end
+ nil
+ end
+
def unique_index_by(*args)
att_types = attribute_types
args.each do |arg|
index(::Zermelo::Associations::UniqueIndex, arg, :type => att_types[arg])
end
nil
end
def has_many(name, args = {})
- associate(::Zermelo::Associations::HasMany, name, args)
+ associate(::Zermelo::Associations::Multiple, :has_many, name, args)
nil
end
- def has_one(name, args = {})
- associate(::Zermelo::Associations::HasOne, name, args)
+ def has_sorted_set(name, args = {})
+ associate(::Zermelo::Associations::Multiple, :has_sorted_set, name, args)
nil
end
- def has_sorted_set(name, args = {})
- associate(::Zermelo::Associations::HasSortedSet, name, args)
+ def has_and_belongs_to_many(name, args = {})
+ associate(::Zermelo::Associations::Multiple, :has_and_belongs_to_many, name, args)
nil
end
- def has_and_belongs_to_many(name, args = {})
- associate(::Zermelo::Associations::HasAndBelongsToMany, name, args)
+ def has_one(name, args = {})
+ associate(::Zermelo::Associations::Singular, :has_one, name, args)
nil
end
def belongs_to(name, args = {})
- associate(::Zermelo::Associations::BelongsTo, name, args)
+ associate(::Zermelo::Associations::Singular, :belongs_to, name, args)
nil
end
# end used by client classes
+ private
+
# used internally by other parts of Zermelo to implement the above
# configuration
# Works out which classes should be locked when updating associations
# TODO work out if this can be replaced by 'related_klasses' assoc data
@@ -75,19 +83,16 @@
@lock.synchronize do
@association_data ||= {}
@association_data.values.each do |data|
klass = data.data_klass
next if visited.include?(klass)
- visited |= klass.associated_classes(visited, false)
+ visited |= klass.send(:associated_classes, visited, false)
end
end
visited
end
- # TODO for each association: check whether it has changed
- # would need an instance-level hash with association name as key,
- # boolean 'changed' value
def with_associations(record)
@lock.synchronize do
@association_data ||= {}
@association_data.keys.each do |name|
yield record.send("#{name}_proxy".to_sym)
@@ -110,18 +115,10 @@
yield idx_data unless idx_data.nil?
end
end
# end used internally within Zermelo
- # # TODO can remove need for some of the inverse mapping
- # # was inverse_of(source, klass)
- # with_association_data do |d|
- # d.detect {|name, data| data.klass == klass && data.inverse == source}
- # end
-
- private
-
def add_index_data(klass, name, args = {})
return if name.nil?
data = Zermelo::Associations::IndexData.new(
:name => name,
@@ -149,74 +146,64 @@
end
}
instance_eval idx, __FILE__, __LINE__
end
- def add_association_data(klass, name, args = {})
-
- # TODO have inverse be a reference (or copy?) of the association data
- # record for that inverse association; would need to defer lookup until
- # all data in place for all assocs, so might be best if looked up and
- # cached on first use
+ def add_association_data(klass, type, name, args = {})
inverse = if args[:inverse_of].nil? || args[:inverse_of].to_s.empty?
nil
else
args[:inverse_of].to_s
end
callbacks = case klass.name
- when ::Zermelo::Associations::HasMany.name,
- ::Zermelo::Associations::HasSortedSet.name,
- ::Zermelo::Associations::HasAndBelongsToMany.name
- [:before_add, :after_add, :before_remove, :after_remove]
- when ::Zermelo::Associations::HasOne.name,
- ::Zermelo::Associations::BelongsTo.name
- [:before_set, :after_set, :before_clear, :after_clear]
+ when ::Zermelo::Associations::Multiple.name
+ [:before_add, :after_add, :before_remove, :after_remove, :before_read, :after_read]
+ when ::Zermelo::Associations::Singular.name
+ [:before_set, :after_set, :before_clear, :after_clear, :before_read, :after_read]
else
[]
end
data = Zermelo::Associations::AssociationData.new(
:name => name,
:data_klass_name => args[:class_name],
+ :data_type => type,
:type_klass => klass,
:inverse => inverse,
:related_klass_names => args[:related_class_names],
:callbacks => callbacks.each_with_object({}) {|c, memo|
memo[c] = args[c]
}
)
- if klass.name == Zermelo::Associations::HasSortedSet.name
- data.sort_key = (args[:key] || :id)
+ if :has_sorted_set.eql?(type)
+ data.sort_key = args[:key]
+ data.sort_order =
+ !args[:order].nil? && :desc.eql?(args[:order].to_sym) ? :desc : :asc
end
@lock.synchronize do
@association_data ||= {}
@association_data[name] = data
end
end
- def associate(klass, name, args = {})
+ def associate(klass, type, name, args = {})
return if name.nil?
- add_association_data(klass, name, args)
+ add_association_data(klass, type, name, args)
assoc = case klass.name
- when ::Zermelo::Associations::HasMany.name,
- ::Zermelo::Associations::HasSortedSet.name,
- ::Zermelo::Associations::HasAndBelongsToMany.name
-
+ when ::Zermelo::Associations::Multiple.name
%Q{
def #{name}
#{name}_proxy
end
}
- when ::Zermelo::Associations::HasOne.name,
- ::Zermelo::Associations::BelongsTo.name
-
+ when ::Zermelo::Associations::Singular.name
%Q{
def #{name}
#{name}_proxy.value
end
@@ -230,10 +217,10 @@
proxy = %Q{
def #{name}_proxy
raise "Associations cannot be invoked for records without an id" if self.id.nil?
- @#{name}_proxy ||= #{klass.name}.new(self, '#{name}')
+ @#{name}_proxy ||= #{klass.name}.new(:#{type}, self.class, self.id, '#{name}')
end
private :#{name}_proxy
}
class_eval proxy, __FILE__, __LINE__
class_eval assoc, __FILE__, __LINE__
\ No newline at end of file