Class: CouchbaseOrm::Base

Inherits:
Object
  • Object
show all
Extended by:
EnsureUnique, Enum, HasMany, Index, Join
Includes:
ActiveModel::Dirty, ActiveModel::Model, ActiveModel::Serializers::JSON, ActiveModel::Validations, ActiveModel::Validations::Callbacks, Associations, Persistence, Views
Defined in:
lib/couchbase-orm/base.rb

Defined Under Namespace

Classes: Metadata

Constant Summary collapse

ID_LOOKUP =
['id', :id].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Associations

#destroy_associations!, #reset_associations

Methods included from Persistence

#delete, #destroy, #destroyed?, #new_record?, #persisted?, #reload, #save, #save!, #touch, #update, #update!, #update_attribute, #update_columns

Constructor Details

#initialize(model = nil, ignore_doc_type: false, **attributes) {|_self| ... } ⇒ Base

Add support for libcouchbase response objects

Yields:

  • (_self)

Yield Parameters:



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/couchbase-orm/base.rb', line 140

def initialize(model = nil, ignore_doc_type: false, **attributes)
    @__metadata__   = Metadata.new

    # Assign default values
    @__attributes__ = ::ActiveSupport::HashWithIndifferentAccess.new({type: self.class.design_document})
    self.class.attributes.each do |key, options|
        default = options[:default]
        if default.respond_to?(:call)
            write_attribute key, default.call
        else
            write_attribute key, default
        end
    end

    if model
        case model
        when ::Libcouchbase::Response
            doc = model.value || raise('empty response provided')
            type = doc.delete(:type)
            doc.delete(:id)

            if type && !ignore_doc_type && type.to_s != self.class.design_document
                raise "document type mismatch, #{type} != #{self.class.design_document}"
            end

            @__metadata__.key = model.key
            @__metadata__.cas = model.cas

            # This ensures that defaults are applied
            @__attributes__.merge! doc
            clear_changes_information
        when CouchbaseOrm::Base
            clear_changes_information
            attributes = model.attributes
            attributes.delete(:id)
            super(attributes)
        else
            clear_changes_information
            super(attributes.merge(Hash(model)))
        end
    else
        clear_changes_information
        super(attributes)
    end

    yield self if block_given?

    run_callbacks :initialize
end

Class Method Details

.attribute(*names, **options) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/couchbase-orm/base.rb', line 68

def attribute(*names, **options)
    @attributes ||= {}
    names.each do |name|
        name = name.to_sym

        @attributes[name] = options

        unless self.instance_methods.include?(name)
            define_method(name) do
                read_attribute(name)
            end
        end

        eq_meth = :"#{name}="
        unless self.instance_methods.include?(eq_meth)
            define_method(eq_meth) do |value|
                value = yield(value) if block_given?
                write_attribute(name, value)
            end
        end
    end
end

.attributesObject



91
92
93
# File 'lib/couchbase-orm/base.rb', line 91

def attributes
    @attributes ||= {}
end

.bucketObject



51
52
53
# File 'lib/couchbase-orm/base.rb', line 51

def bucket
    @bucket ||= Connection.bucket
end

.bucket=(bucket) ⇒ Object



47
48
49
# File 'lib/couchbase-orm/base.rb', line 47

def bucket=(bucket)
    @bucket = bucket
end

.connect(**options) ⇒ Object



43
44
45
# File 'lib/couchbase-orm/base.rb', line 43

def connect(**options)
    @bucket = ::Libcouchbase::Bucket.new(**options)
end

.exists?(id) ⇒ Boolean Also known as: has_key?

Returns:



128
129
130
131
132
133
134
# File 'lib/couchbase-orm/base.rb', line 128

def exists?(id)
    val = false
    ::ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
        val = bucket.get(id, quiet: true).nil?
    end
    !val
end

.find(*ids, **options) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/couchbase-orm/base.rb', line 95

def find(*ids, **options)
    options[:extended] = true
    options[:quiet] ||= false

    ids = ids.flatten.select { |id| id.present? }
    if ids.empty?
        return nil if options[:quiet]
        raise Libcouchbase::Error::EmptyKey, 'no id(s) provided'
    end

    records = nil
    ::ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
        records = bucket.get(*ids, **options)
    end

    records = records.is_a?(Array) ? records : [records]
    records.map! { |record|
        if record
            self.new(record)
        else
            false
        end
    }
    records.select! { |rec| rec }
    ids.length > 1 ? records : records[0]
end

.find_by_id(*ids, **options) ⇒ Object Also known as: []



122
123
124
125
# File 'lib/couchbase-orm/base.rb', line 122

def find_by_id(*ids, **options)
    options[:quiet] = true
    find(*ids, **options)
end

.uuid_generatorObject



60
61
62
# File 'lib/couchbase-orm/base.rb', line 60

def uuid_generator
    @uuid_generator ||= IdGenerator
end

.uuid_generator=(generator) ⇒ Object



64
65
66
# File 'lib/couchbase-orm/base.rb', line 64

def uuid_generator=(generator)
    @uuid_generator = generator
end

Instance Method Details

#==(other) ⇒ Object

Public: Overrides == to compare via class and entity id.

other - Another object to compare to

Returns a boolean.



282
283
284
# File 'lib/couchbase-orm/base.rb', line 282

def ==(other)
    hash == other.hash
end

#attribute(name) ⇒ Object Also known as: read_attribute_for_serialization



236
237
238
239
# File 'lib/couchbase-orm/base.rb', line 236

def attribute(name)
    return self.id if ID_LOOKUP.include?(name)
    @__attributes__[name]
end

#attribute=(name, value) ⇒ Object



242
243
244
# File 'lib/couchbase-orm/base.rb', line 242

def attribute=(name, value)
    __send__(:"#{name}=", value)
end

#attributesObject



222
223
224
225
226
# File 'lib/couchbase-orm/base.rb', line 222

def attributes
    copy = @__attributes__.merge({id: id})
    copy.delete(:type)
    copy
end

#attributes=(attributes) ⇒ Object



228
229
230
231
232
233
# File 'lib/couchbase-orm/base.rb', line 228

def attributes=(attributes)
    attributes.each do |key, value|
        setter = :"#{key}="
        send(setter, value) if respond_to?(setter)
    end
end

#eql?(other) ⇒ Boolean

Public: Overrides eql? to use == in the comparison.

other - Another object to compare to

Returns a boolean.

Returns:



273
274
275
# File 'lib/couchbase-orm/base.rb', line 273

def eql?(other)
    self == other
end

#hashObject

Public: Hashes identifying properties of the instance

Ruby normally hashes an object to be used in comparisons. In our case we may have two techincally different objects referencing the same entity id.

Returns a string representing the unique key.



264
265
266
# File 'lib/couchbase-orm/base.rb', line 264

def hash
    "#{self.class.name}-#{self.id}-#{@__metadata__.cas}-#{@__attributes__.hash}".hash
end

#idObject

Document ID is a special case as it is not stored in the document



192
193
194
# File 'lib/couchbase-orm/base.rb', line 192

def id
    @__metadata__.key || @id
end

#id=(value) ⇒ Object



196
197
198
199
200
# File 'lib/couchbase-orm/base.rb', line 196

def id=(value)
    raise 'ID cannot be changed' if @__metadata__.cas
    attribute_will_change!(:id)
    @id = value.to_s
end

#read_attribute(attr_name) ⇒ Object Also known as: []



202
203
204
# File 'lib/couchbase-orm/base.rb', line 202

def read_attribute(attr_name)
    @__attributes__[attr_name]
end

#to_modelObject

Public: Allows for access to ActiveModel functionality.

Returns self.



254
255
256
# File 'lib/couchbase-orm/base.rb', line 254

def to_model
    self
end

#write_attribute(attr_name, value) ⇒ Object Also known as: []=



207
208
209
210
211
212
213
214
# File 'lib/couchbase-orm/base.rb', line 207

def write_attribute(attr_name, value)
    unless value.nil?
        coerce = self.class.attributes[attr_name][:type]
        value = Kernel.send(coerce.to_s, value) if coerce
    end
    attribute_will_change!(attr_name) unless @__attributes__[attr_name] == value
    @__attributes__[attr_name] = value
end