Module: CouchbaseOrm::HasMany

Included in:
Base
Defined in:
lib/couchbase-orm/utilities/has_many.rb

Instance Method Summary collapse

Instance Method Details

#build_index(type, klass, remote_class, remote_method, through_key, foreign_key) ⇒ Object



74
75
76
77
78
79
80
81
82
83
# File 'lib/couchbase-orm/utilities/has_many.rb', line 74

def build_index(type, klass, remote_class, remote_method, through_key, foreign_key)
  case type
  when :n1ql
    build_index_n1ql(klass, remote_class, remote_method, through_key, foreign_key)
  when :view
    build_index_view(klass, remote_class, remote_method, through_key, foreign_key)
  else
    raise 'type is unknown'
  end
end

#build_index_n1ql(klass, remote_class, remote_method, through_key, foreign_key) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/couchbase-orm/utilities/has_many.rb', line 103

def build_index_n1ql(klass, remote_class, remote_method, through_key, foreign_key)
  if remote_class
    klass.class_eval do
      n1ql remote_method, emit_key: 'id', query_fn: proc { |bucket, values, options|
        raise ArgumentError.new('values[0] must not be blank') if values[0].blank?

        cluster.query("SELECT raw #{through_key} FROM `#{bucket.name}` where type = \"#{design_document}\" and #{foreign_key} = #{quote(values[0])}", options)
      }
    end
  else
    klass.class_eval do
      index_n1ql foreign_key, validate: false
    end
  end
end

#build_index_view(klass, remote_class, remote_method, through_key, foreign_key) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/couchbase-orm/utilities/has_many.rb', line 85

def build_index_view(klass, remote_class, remote_method, through_key, foreign_key)
  if remote_class
    klass.class_eval do
      view remote_method, map: <<-EMAP
                    function(doc) {
                        if (doc.type === "{{design_document}}" && doc.#{through_key}) {
                        emit(doc.#{foreign_key}, null);
                        }
                    }
      EMAP
    end
  else
    klass.class_eval do
      index_view foreign_key, validate: false
    end
  end
end

#has_many(model, class_name: nil, foreign_key: nil, through: nil, through_class: nil, through_key: nil, type: :view, **options) ⇒ Object

:foreign_key, :class_name, :through



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
64
65
66
67
68
69
70
71
72
# File 'lib/couchbase-orm/utilities/has_many.rb', line 6

def has_many(model, class_name: nil, foreign_key: nil, through: nil, through_class: nil, through_key: nil,
             type: :view, **options)
  class_name = (class_name || model.to_s.singularize.camelcase).to_s
  foreign_key = (foreign_key || ActiveSupport::Inflector.foreign_key(self.name)).to_sym
  if through || through_class
    remote_class = class_name
    class_name = (through_class || through.to_s.camelcase).to_s
    through_key = (through_key || "#{remote_class.underscore}_id").to_sym
    remote_method = :"by_#{foreign_key}_with_#{through_key}"
  else
    remote_method = :"find_by_#{foreign_key}"
  end

  instance_var = "@__assoc_#{model}"

  klass = begin
    class_name.constantize
  rescue NameError
    warn "WARNING: #{class_name} referenced in #{self.name} before it was aded"

    # Open the class early - load order will have to be changed to prevent this.
    # Warning notice required as a misspelling will not raise an error
    Object.class_eval <<-EKLASS, __FILE__, __LINE__ + 1
                        class #{class_name} < CouchbaseOrm::Base
                            attribute :#{foreign_key}
                        end
    EKLASS
    class_name.constantize
  end

  build_index(type, klass, remote_class, remote_method, through_key, foreign_key)

  if remote_class
    define_method(model) do
      return self.instance_variable_get(instance_var) if instance_variable_defined?(instance_var)

      remote_klass = remote_class.constantize
      raise ArgumentError.new("Can't find #{remote_method} without an id") unless self.id.present?

      enum = klass.__send__(remote_method, key: self.id) { |row|
        case type
        when :n1ql
          remote_klass.find(row)
        when :view
          remote_klass.find(row[through_key])
        else
          raise 'type is unknown'
        end
      }

      self.instance_variable_set(instance_var, enum)
    end
  else
    define_method(model) do
      return self.instance_variable_get(instance_var) if instance_variable_defined?(instance_var)

      self.instance_variable_set(instance_var, self.id ? klass.__send__(remote_method, self.id) : [])
    end
  end

  define_method(:"#{model}_reset") do
    self.remove_instance_variable(instance_var) if self.instance_variable_defined?(instance_var)
  end

  @associations ||= []
  @associations << [model, options[:dependent]]
end