Module: CouchbaseOrm::Persistence

Extended by:
ActiveSupport::Concern
Includes:
Encrypt
Included in:
Base
Defined in:
lib/couchbase-orm/persistence.rb

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Methods included from Encrypt

#as_json, #decode_encrypted_attributes, #encode_encrypted_attributes, #to_json

Instance Method Details

#_create_record(*_args, **options) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/couchbase-orm/persistence.rb', line 256

def _create_record(*_args, **options)
    return false unless perform_validations(:create, options)

    run_callbacks :create do
        run_callbacks :save do
            assign_attributes(id: self.class.uuid_generator.next(self)) unless self.id
            CouchbaseOrm.logger.debug { "_create_record - Upsert #{id} #{serialized_attributes.to_s.truncate(200)}" }
            if options[:transcoder].nil?
                options[:transcoder] = CouchbaseOrm::JsonTranscoder.new(json_validation_config: self.class.json_validation_config)
            end
            resp = self.class.collection.upsert(self.id, serialized_attributes.except("id").merge(type: self.class.design_document), Couchbase::Options::Upsert.new(**options))

            # Ensure the model is up to date
            @__metadata__.cas = resp.cas

            changes_applied
            true
        end
    end
end

#_update_record(*_args, with_cas: false, **options) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/couchbase-orm/persistence.rb', line 235

def _update_record(*_args, with_cas: false, **options)
    return false unless perform_validations(:update, options)
    return true unless changed? || self.class.attribute_types.any? { |_, type| type.is_a?(CouchbaseOrm::Types::Nested) || type.is_a?(CouchbaseOrm::Types::Array)  }

    run_callbacks :update do
        run_callbacks :save do
            options[:cas] = @__metadata__.cas if with_cas
            CouchbaseOrm.logger.debug { "_update_record - replace #{id} #{serialized_attributes.to_s.truncate(200)}" }
            if options[:transcoder].nil?
                options[:transcoder] = CouchbaseOrm::JsonTranscoder.new(json_validation_config: self.class.json_validation_config)
            end
            resp = self.class.collection.replace(id, serialized_attributes.except("id").merge(type: self.class.design_document), Couchbase::Options::Replace.new(**options))

            # Ensure the model is up to date
            @__metadata__.cas = resp.cas

            changes_applied
            true
        end
    end
end

#assign_attributes(hash) ⇒ Object



156
157
158
159
# File 'lib/couchbase-orm/persistence.rb', line 156

def assign_attributes(hash)
    hash = hash.with_indifferent_access if hash.is_a?(Hash)
    super(hash.except("type"))
end

#delete(with_cas: false, **options) ⇒ Object Also known as: remove

Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can’t be persisted). Returns the frozen instance.

The record is simply removed, no callbacks are executed.



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/couchbase-orm/persistence.rb', line 108

def delete(with_cas: false, **options)
    options[:cas] = @__metadata__.cas if with_cas
    CouchbaseOrm.logger.debug "Data - Delete #{self.id}"
    self.class.collection.remove(self.id, **options)

    self.id = nil
    clear_changes_information
    @destroyed = true
    self.freeze
    self
end

#destroy(with_cas: false, **options) ⇒ Object Also known as: destroy!

Deletes the record in the database and freezes this instance to reflect that no changes should be made (since they can’t be persisted).

There’s a series of callbacks associated with #destroy.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/couchbase-orm/persistence.rb', line 126

def destroy(with_cas: false, **options)
    return self if destroyed?
    raise 'model not persisted' unless persisted?

    run_callbacks :destroy do
        destroy_associations!

        options[:cas] = @__metadata__.cas if with_cas
        CouchbaseOrm.logger.debug "Data - Destroy #{id}"
        self.class.collection.remove(id, **options)

        self.id = nil

        clear_changes_information
        @destroyed = true
        freeze
    end
end

#destroyed?Boolean

Returns true if this object has been destroyed, otherwise returns false.

Returns:



71
72
73
# File 'lib/couchbase-orm/persistence.rb', line 71

def destroyed?
    @destroyed ||= false
end

#new_record?Boolean Also known as: new?

Returns true if this object hasn’t been saved yet – that is, a record for the object doesn’t exist in the database yet; otherwise, returns false.

Returns:



65
66
67
# File 'lib/couchbase-orm/persistence.rb', line 65

def new_record?
    @__metadata__.cas.nil?
end

#perform_validations(context, options = {}) ⇒ Object



277
278
279
280
# File 'lib/couchbase-orm/persistence.rb', line 277

def perform_validations(context, options = {})
    return valid?(context) if options[:validate] != false
    true
end

#persisted?Boolean Also known as: exists?

Returns true if the record is persisted, i.e. it’s not a new record and it was not destroyed, otherwise returns false.

Returns:



77
78
79
# File 'lib/couchbase-orm/persistence.rb', line 77

def persisted?
    !new_record? && !destroyed?
end

#reloadObject

Reloads the record from the database.

This method finds record by its key and modifies the receiver in-place:



211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/couchbase-orm/persistence.rb', line 211

def reload
    raise "unable to reload, model not persisted" unless id

    CouchbaseOrm.logger.debug "Data - Get #{id}"
    resp = self.class.collection.get!(id)
    assign_attributes(decode_encrypted_attributes(resp.content.except("id", *self.class.ignored_properties ))) # API return a nil id
    @__metadata__.cas = resp.cas

    reset_associations
    clear_changes_information
    reset_object!
    self
end

#save(**options) ⇒ Object

Saves the model.

If the model is new, a record gets created in the database, otherwise the existing record gets updated.



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

def save(**options)
    raise "Cannot save a destroyed document!" if destroyed?
    self.new_record? ? _create_record(**options) : _update_record(**options)
end

#save!(**options) ⇒ Object

Saves the model.

If the model is new, a record gets created in the database, otherwise the existing record gets updated.

By default, #save! always runs validations. If any of them fail CouchbaseOrm::Error::RecordInvalid gets raised, and the record won’t be saved.



98
99
100
101
# File 'lib/couchbase-orm/persistence.rb', line 98

def save!(**options)
    self.class.fail_validate!(self) unless self.save(**options)
    self
end

#touch(**options) ⇒ Object

Updates the TTL of the document



226
227
228
229
230
231
# File 'lib/couchbase-orm/persistence.rb', line 226

def touch(**options)
    CouchbaseOrm.logger.debug "Data - Touch #{id}"
    _res = self.class.collection.touch(id, async: false, **options)
    @__metadata__.cas = resp.cas
    self
end

#update(hash) ⇒ Object Also known as: update_attributes

Updates the attributes of the model from the passed-in hash and saves the record. If the object is invalid, the saving will fail and false will be returned.



163
164
165
166
# File 'lib/couchbase-orm/persistence.rb', line 163

def update(hash)
    assign_attributes(hash)
    save
end

#update!(hash) ⇒ Object Also known as: update_attributes!

Updates its receiver just like #update but calls #save! instead of save, so an exception is raised if the record is invalid and saving will fail.



171
172
173
174
# File 'lib/couchbase-orm/persistence.rb', line 171

def update!(hash)
    assign_attributes(hash) # Assign attributes is provided by ActiveModel::AttributeAssignment
    save!
end

#update_attribute(name, value) ⇒ Object

Updates a single attribute and saves the record. This is especially useful for boolean flags on existing records. Also note that

  • Validation is skipped.

  • Callbacks are invoked.



151
152
153
154
# File 'lib/couchbase-orm/persistence.rb', line 151

def update_attribute(name, value)
    public_send(:"#{name}=", value)
    changed? ? save(validate: false) : true
end

#update_columns(with_cas: false, **hash) ⇒ Object

Updates the record without validating or running callbacks. Updates only the attributes that are passed in as parameters except if there is more than 16 attributes, in which case the whole record is saved.



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/couchbase-orm/persistence.rb', line 181

def update_columns(with_cas: false, **hash)
    raise "unable to update columns, model not persisted" unless id

    assign_attributes(hash)

    options = {extended: true}
    options[:cas] = @__metadata__.cas if with_cas

    # There is a limit of 16 subdoc operations per request
    resp = if hash.length <= 16
        self.class.collection.mutate_in(
            id,
            hash.map { |k, v| Couchbase::MutateInSpec.replace(k.to_s, v) }
        )
    else
        # Fallback to writing the whole document
        CouchbaseOrm.logger.debug { "Data - Replace #{id} #{attributes.to_s.truncate(200)}" }
        self.class.collection.replace(id, attributes.except("id").merge(type: self.class.design_document), **options)
    end

    # Ensure the model is up to date
    @__metadata__.cas = resp.cas

    changes_applied
    self
end