Module: SimplyCouch::Model::HasMany

Included in:
ClassMethods
Defined in:
lib/simply_couch/model/has_many.rb

Defined Under Namespace

Classes: Property

Instance Method Summary collapse

Instance Method Details

#define_has_many_count(name, options, through = nil) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/simply_couch/model/has_many.rb', line 115

def define_has_many_count(name, options, through = nil)
  method_name = name.to_s.singularize.underscore.gsub('/', '__') + "_count"
  define_method(method_name) do |*args|
    local_options = args.first && args.first.is_a?(Hash) && args.first
    if local_options
      local_options.assert_valid_keys(:force_reload, :with_deleted)
      forced_reload = local_options[:force_reload]
      with_deleted = local_options[:with_deleted]
    else
      forced_reload = false
      with_deleted = false
    end

    if forced_reload || instance_variable_get("@#{method_name}").nil?
      instance_variable_set("@#{method_name}", count_associated(through || options[:class_name], self.class, :with_deleted => with_deleted, :foreign_key => options[:foreign_key]))
    end
    instance_variable_get("@#{method_name}")
  end
end

#define_has_many_getter(name, options) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/simply_couch/model/has_many.rb', line 9

def define_has_many_getter(name, options)
  define_method(name) do |*args|
    local_options = args.first && args.first.is_a?(Hash) && args.first
    forced_reload, with_deleted, limit, descending = extract_association_options(local_options)

    cached_results = send("_get_cached_#{name}")
    cache_key = _cache_key_for(local_options)
    if forced_reload || cached_results[cache_key].nil? 
      cached_results[cache_key] = find_associated(options[:class_name], self.class, :with_deleted => with_deleted, :limit => limit, :descending => descending, :foreign_key => options[:foreign_key])
      instance_variable_set("@#{name}", cached_results)
      self.class.set_parent_has_many_association_object(self, cached_results[cache_key])
    end
    cached_results[cache_key]
  end
end

#define_has_many_setter_add(name, options) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/simply_couch/model/has_many.rb', line 65

def define_has_many_setter_add(name, options)
  define_method("add_#{name.to_s.singularize}") do |value|
    klass = self.class.get_class_from_name(name)
    raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
    foreign_key = "#{self.class.foreign_key}="
    # If foreign key is namespace: admin__user, try jus user if admin_user_id is not present
    foreign_key.gsub!(/.*__/, '') if !value.respond_to?(foreign_key) && value.respond_to?(foreign_key.sub(/.*__/, ''))
    value.send(foreign_key, id)
    value.save(false)
    
    cached_results = send("_get_cached_#{name}")[:all]
    send("_set_cached_#{name}", (cached_results || []) << value, :all)
    nil
  end
end

#define_has_many_setter_remove(name, options) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/simply_couch/model/has_many.rb', line 81

def define_has_many_setter_remove(name, options)
  define_method "remove_#{name.to_s.singularize}" do |value|
    klass = self.class.get_class_from_name(name)
    raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
    raise ArgumentError, "cannot remove not mine" unless value.send(self.class.foreign_key.to_sym) == id

    if options[:dependent] == :destroy
      value.destroy
    elsif options[:dependent] == :ignore
      # skip
    else # nullify
      foreign_key = "#{self.class.foreign_key}="
      # If foreign key is namespace: admin__user, try jus user if admin_user_id is not present
      foreign_key.gsub!(/.*__/, '') if !value.respond_to?(foreign_key) && value.respond_to?(foreign_key.sub(/.*__/, ''))
      value.send(foreign_key, nil)
      value.save(false)
    end
    
    cached_results = send("_get_cached_#{name}")[:all]
    send("_set_cached_#{name}", (cached_results || []).delete_if{|item| item.id == value.id}, :all)
    nil
  end
end

#define_has_many_setter_remove_all(name, options) ⇒ Object



105
106
107
108
109
110
111
112
113
# File 'lib/simply_couch/model/has_many.rb', line 105

def define_has_many_setter_remove_all(name, options)
  define_method "remove_all_#{name}" do
    all = send("#{name}", :force_reload => true)
    
    all.collect{|i| i}.each do |item|
      send("remove_#{name.to_s.singularize}", item)
    end
  end
end

#define_has_many_through_getter(name, options, through) ⇒ Object

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/simply_couch/model/has_many.rb', line 25

def define_has_many_through_getter(name, options, through)
  raise ArgumentError, "no such relation: #{self} - #{through}" unless instance_methods.map(&:to_sym).include?(through.to_sym)
  
  define_method(name) do |*args|
    local_options = args.first && args.first.is_a?(Hash) && args.first
    if local_options
      local_options.assert_valid_keys(:force_reload, :with_deleted, :limit)
      forced_reload = local_options[:force_reload]
      with_deleted = local_options[:with_deleted]
      limit = local_options[:limit]
    else
      forced_reload = false
      with_deleted = false
      limit = nil
    end
    
    cached_results = send("_get_cached_#{name}")
    cache_key = _cache_key_for(local_options)
    
    if forced_reload || cached_results[cache_key].nil?
      
      # there is probably a faster way to query this
      through_property = self.class.properties.find{|p| p.name == through}
      if through_property && through_property.respond_to?(:options) && through_property.options[:class_name].present?
        through_finder = through_property.options[:class_name].constantize.foreign_property
      else
        through_finder = through # try with the association name
      end
      intermediate_objects = find_associated(through_finder, self.class, :with_deleted => with_deleted, :limit => limit, :foreign_key => options[:foreign_key])
      
      through_objects = intermediate_objects.map do |intermediate_object|
        intermediate_object.send(name.to_s.singularize.underscore.gsub('/', '__'), :with_deleted => with_deleted)
      end.flatten.uniq
      cached_results[cache_key] = through_objects
      instance_variable_set("@#{name}", cached_results)
    end
    cached_results[cache_key]
  end
end

#has_many(name, options = {}) ⇒ Object



4
5
6
7
# File 'lib/simply_couch/model/has_many.rb', line 4

def has_many(name, options = {})
  check_existing_properties(name, SimplyCouch::Model::HasMany::Property)
  properties << SimplyCouch::Model::HasMany::Property.new(self, name, options)
end

#set_parent_has_many_association_object(parent, child_collection) ⇒ Object



135
136
137
138
139
140
141
# File 'lib/simply_couch/model/has_many.rb', line 135

def set_parent_has_many_association_object(parent, child_collection)
  child_collection.each do |child|
    if child.respond_to?("#{parent.class.name.to_s.singularize.downcase}=")
      child.send("#{parent.class.name.to_s.singularize.camelize.downcase}=", parent)
    end
  end
end