Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validate param into save #85

Merged
merged 3 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading