Skip to content

Commit

Permalink
Merge pull request #85 from Mapotempo/add_validate_param_into_save
Browse files Browse the repository at this point in the history
Add validate param into save
  • Loading branch information
giallon authored May 30, 2024
2 parents 5f15e1f + 12aeb6d commit c6c82a8
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 28 deletions.
8 changes: 7 additions & 1 deletion lib/couchbase-orm/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@ def initialize(*args, **kwargs)
end

class Base < Document
include ::ActiveRecord::Validations
include Persistence
include ::ActiveRecord::AttributeMethods::Dirty
include ::ActiveRecord::Validations # must be included after Persistence
include ::ActiveRecord::Timestamp # must be included after Persistence

include Associations
Expand Down Expand Up @@ -339,5 +339,11 @@ def eql?(other)
def ==(other)
super || other.instance_of?(self.class) && !id.nil? && other.id == id
end

private

def raise_validation_error
raise CouchbaseOrm::Error::RecordInvalid.new(self)
end
end
end
16 changes: 8 additions & 8 deletions lib/couchbase-orm/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ def initialize(message = nil, record = nil)
end

class RecordInvalid < Error
def initialize(message = nil, record = nil)
def initialize(record = nil)
if record
errors = record.errors.full_messages.join(", ")
message = I18n.t(
:"couchbase.#{record.class.design_document}.errors.messages.record_invalid",
errors: errors,
default: :"couchbase.errors.messages.record_invalid"
)
@record = record
errors = @record.errors.full_messages.join(", ")
message = I18n.t(:"#{@record.class.i18n_scope}.errors.messages.record_invalid", errors: errors, default: :"errors.messages.record_invalid")
else
message = "Record invalid"
end
super(message, record)
end
end
class TypeMismatchError < Error; end
class RecordExists < Error; end
class CouchbaseOrm::Error::EmptyNotAllowed < Error; end
class EmptyNotAllowed < Error; end
class DocumentNotFound < Error; end
end
end
35 changes: 16 additions & 19 deletions lib/couchbase-orm/persistence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ def persisted?
#
# If the model is new, a record gets created in the database, otherwise
# the existing record gets updated.
def save(**options)
def save(**options, &block)
raise "Cannot save a destroyed document!" if destroyed?
self.new_record? ? _create_record(**options) : _update_record(**options)
@_with_cas = options[:with_cas]
create_or_update(**options, &block)
end

# Saves the model.
Expand All @@ -91,7 +92,7 @@ def save(**options)
#
# By default, #save! always runs validations. If any of them fail
# CouchbaseOrm::Error::RecordInvalid gets raised, and the record won't be saved.
def save!(**options)
def save!(**options, &block)
self.class.fail_validate!(self) unless self.save(**options)
self
end
Expand All @@ -101,8 +102,8 @@ def save!(**options)
# persisted). Returns the frozen instance.
#
# The record is simply removed, no callbacks are executed.
def delete(with_cas: false, **options)
options[:cas] = @__metadata__.cas if with_cas
def delete(**options)
options[:cas] = @__metadata__.cas if options.delete(:with_cas)
CouchbaseOrm.logger.debug "Data - Delete #{self.id}"
self.class.collection.remove(self.id, **options)

Expand All @@ -119,14 +120,14 @@ def delete(with_cas: false, **options)
# that no changes should be made (since they can't be persisted).
#
# There's a series of callbacks associated with #destroy.
def destroy(with_cas: false, **options)
def destroy(**options)
return self if destroyed?
raise 'model not persisted' unless persisted?

run_callbacks :destroy do
destroy_associations!

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

Expand Down Expand Up @@ -225,15 +226,17 @@ def touch(**options)
self
end

def create_or_update(**, &block)
self.new_record? ? _create_record(&block) : _update_record(&block)
end


def _update_record(*_args, with_cas: false, **options)
return false unless perform_validations(:update, options)
def _update_record(*, &block)
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
options = {}
options[:cas] = @__metadata__.cas if @_with_cas
CouchbaseOrm.logger.debug { "_update_record - replace #{id} #{serialized_attributes.to_s.truncate(200)}" }
resp = self.class.collection.replace(id, serialized_attributes.except("id").merge(type: self.class.design_document), Couchbase::Options::Replace.new(**options))

Expand All @@ -245,14 +248,13 @@ def _update_record(*_args, with_cas: false, **options)
end
end
end
def _create_record(*_args, **options)
return false unless perform_validations(:create, options)

def _create_record(*, &block)
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)}" }
resp = self.class.collection.upsert(self.id, serialized_attributes.except("id").merge(type: self.class.design_document), Couchbase::Options::Upsert.new(**options))
resp = self.class.collection.upsert(self.id, serialized_attributes.except("id").merge(type: self.class.design_document), Couchbase::Options::Upsert.new)

# Ensure the model is up to date
@__metadata__.cas = resp.cas
Expand All @@ -262,10 +264,5 @@ def _create_record(*_args, **options)
end
end
end

def perform_validations(context, options = {})
return valid?(context) if options[:validate] != false
true
end
end
end
10 changes: 10 additions & 0 deletions spec/persistence_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,16 @@ class ModelWithValidations < CouchbaseOrm::Base
}) }.to raise_error(ActiveModel::UnknownAttributeError)
end

it "should not perform validation with validate true" do
model = ModelWithValidations.new

expect(model.valid?).to be(false)
expect(model.save(validate: false)).to be(true)
expect(model.persisted?).to be(true)

model.destroy
end

describe BasicModel do
it_behaves_like "ActiveModel"
end
Expand Down

0 comments on commit c6c82a8

Please sign in to comment.