Module: CouchbaseOrm::Persistence

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

Defined Under Namespace

Modules: ClassMethods Classes: Metadata

Instance Method Summary collapse

Methods included from Encrypt

#as_json, #decode_encrypted_attributes, #encode_encrypted_attributes, #to_json

Instance Method Details

#assign_attributes(hash) ⇒ Object



213
214
215
# File 'lib/couchbase-orm/persistence.rb', line 213

def assign_attributes(hash)
  super(hash.except('type'))
end

#delete(**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.



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/couchbase-orm/persistence.rb', line 158

def delete(**options)
  raise 'Cannot delete an embedded document!' if embedded?

  options[:cas] = @__metadata__.cas if options.delete(: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(**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.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/couchbase-orm/persistence.rb', line 178

def destroy(**options)
  raise 'Cannot destroy an embedded document!' if embedded?

  return self if destroyed?
  raise 'model not persisted' unless persisted?

  run_callbacks :destroy do
    destroy_associations!

    options[:cas] = @__metadata__.cas if options.delete(: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:



115
116
117
# File 'lib/couchbase-orm/persistence.rb', line 115

def destroyed?
  @destroyed
end

#init_with(coder) {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/couchbase-orm/persistence.rb', line 82

def init_with(coder)
  @__metadata__ = Metadata.new
  @attributes = coder['attributes']
  CouchbaseOrm.logger.debug { "Initialize model #{self.class} with #{@attributes&.to_s&.truncate(200)}" }

  init_internals

  @new_record = coder['new_record']

  unless @new_record
    @attributes.write_from_database('id', coder['id'])
    @__metadata__.cas = coder['cas']
  end

  self.class.define_attribute_methods

  yield self if block_given?

  run_callbacks :find
  run_callbacks :initialize

  self
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:



108
109
110
# File 'lib/couchbase-orm/persistence.rb', line 108

def new_record?
  @__metadata__.cas.nil?
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:



121
122
123
# File 'lib/couchbase-orm/persistence.rb', line 121

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:



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/couchbase-orm/persistence.rb', line 273

def reload
  raise 'Cannot reload an embedded document!' if embedded?
  raise 'unable to reload, model not persisted' unless id

  CouchbaseOrm.logger.debug "Data - Get #{id}"
  resp = self.class.collection.get!(id)
  new_attributes = resp.content
  new_attributes.delete('type')

  builder = self.class.attributes_builder
  attribute_set = builder.build_from_database(new_attributes)

  keep_id = self.id
  @attributes = attribute_set
  @attributes.write_from_database('id', keep_id)
  @__metadata__.cas = resp.cas
  CouchbaseOrm.logger.debug { "reload model #{self.class} with #{@attributes&.to_s&.truncate(200)}" }

  reset_associations
  cleanup_embedded_memoization!
  clear_changes_information
  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.



131
132
133
134
135
136
137
# File 'lib/couchbase-orm/persistence.rb', line 131

def save(**options)
  raise 'Cannot save an embedded document!' if embedded?
  raise 'Cannot save a destroyed document!' if destroyed?

  @_with_cas = options[:with_cas]
  create_or_update
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.



146
147
148
149
150
151
# File 'lib/couchbase-orm/persistence.rb', line 146

def save!(**options)
  raise 'Cannot save! an embedded document!' if embedded?

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

#touch(**options) ⇒ Object

Updates the TTL of the document



298
299
300
301
302
303
304
305
# File 'lib/couchbase-orm/persistence.rb', line 298

def touch(**options)
  raise 'Cannot touch an embedded document!' if embedded?

  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.



219
220
221
222
223
224
# File 'lib/couchbase-orm/persistence.rb', line 219

def update(hash)
  raise 'Cannot update an embedded document!' if embedded?

  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.



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

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.



206
207
208
209
210
211
# File 'lib/couchbase-orm/persistence.rb', line 206

def update_attribute(name, value)
  raise 'Cannot update_attribute an embedded document!' if embedded?

  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.



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/couchbase-orm/persistence.rb', line 241

def update_columns(with_cas: false, **hash)
  raise 'Cannot update_columns an embedded document!' if embedded?
  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
           raw = serialized_attributes.except('id').merge(type: self.class.design_document)
           CouchbaseOrm.logger.debug { "Data - Replace #{id} #{raw.to_s.truncate(200)}" }
           self.class.collection.replace(id, raw, **options)
         end

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

  changes_applied
  self
end