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:



127
128
129
130
131
132
133
134
135
136
137
138
139
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
# File 'lib/couchbase-orm/base.rb', line 127

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



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/couchbase-orm/base.rb', line 63

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



86
87
88
# File 'lib/couchbase-orm/base.rb', line 86

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:



119
120
121
# File 'lib/couchbase-orm/base.rb', line 119

def exists?(id)
    !bucket.get(id, quiet: true).nil?
end

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



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/couchbase-orm/base.rb', line 90

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

    record = bucket.get(*ids, **options)
    records = record.is_a?(Array) ? record : [record]
    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: []



113
114
115
116
# File 'lib/couchbase-orm/base.rb', line 113

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

.uuid_generatorObject



55
56
57
# File 'lib/couchbase-orm/base.rb', line 55

def uuid_generator
    @uuid_generator ||= IdGenerator
end

.uuid_generator=(generator) ⇒ Object



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

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.



269
270
271
272
273
274
275
276
# File 'lib/couchbase-orm/base.rb', line 269

def ==(other)
    case other
    when self.class
        hash == other.hash
    else
        false
    end
end

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



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

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

#attribute=(name, value) ⇒ Object



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

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

#attributesObject



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

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

#attributes=(attributes) ⇒ Object



215
216
217
218
219
220
# File 'lib/couchbase-orm/base.rb', line 215

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:



260
261
262
# File 'lib/couchbase-orm/base.rb', line 260

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.



251
252
253
# File 'lib/couchbase-orm/base.rb', line 251

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



179
180
181
# File 'lib/couchbase-orm/base.rb', line 179

def id
    @__metadata__.key || @id
end

#id=(value) ⇒ Object



183
184
185
186
187
# File 'lib/couchbase-orm/base.rb', line 183

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: []



189
190
191
# File 'lib/couchbase-orm/base.rb', line 189

def read_attribute(attr_name)
    @__attributes__[attr_name]
end

#to_modelObject

Public: Allows for access to ActiveModel functionality.

Returns self.



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

def to_model
    self
end

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



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

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