Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions lib/couchbase-orm/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ def serialized_attributes
end

class NestedDocument < Document
extend IgnoredProperties

def initialize(*args, **kwargs)
super
if respond_to?(:id) && id.nil?
Expand Down
19 changes: 17 additions & 2 deletions lib/couchbase-orm/types/nested.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,29 @@ def initialize(type:)
def cast(value)
return nil if value.nil?
return value if value.is_a?(@model_class)
return @model_class.new(value) if value.is_a?(Hash)

if value.is_a?(Hash)
# Filter out ignored properties before creating the nested instance
# Optimization: only call .except if there are properties to ignore
ignored = @model_class.ignored_properties
filtered_value = ignored.empty? ? value : value.except(*ignored)
return @model_class.new(filtered_value)
end

raise ArgumentError, "Nested: #{value.inspect} (#{value.class}) is not supported for cast"
end

def serialize(value)
return nil if value.nil?
value = @model_class.new(value) if value.is_a?(Hash)

if value.is_a?(Hash)
# Filter out ignored properties before creating the nested instance
# Optimization: only call .except if there are properties to ignore
ignored = @model_class.ignored_properties
filtered_value = ignored.empty? ? value : value.except(*ignored)
value = @model_class.new(filtered_value)
end

return value.send(:serialized_attributes) if value.is_a?(@model_class)

raise ArgumentError, "Nested: #{value.inspect} (#{value.class}) is not supported for serialization"
Expand Down
60 changes: 60 additions & 0 deletions spec/type_nested_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,64 @@ class WithValidationParent < CouchbaseOrm::Base
expect(obj.child.child.errors[:name]).to eq ["can't be blank"]
end
end

describe "Ignored Properties" do
class SubTypeWithIgnoredProperties < CouchbaseOrm::NestedDocument
self.ignored_properties = [:deprecated_property]
attribute :name, :string
attribute :value, :string
end

class ParentWithNestedIgnoredProperties < CouchbaseOrm::Base
self.ignored_properties = [:deprecated_at_root]
attribute :title, :string
attribute :nested, :nested, type: SubTypeWithIgnoredProperties
end

it "should ignore deprecated properties in nested documents on reload" do
# Create and save a parent with nested document
parent = ParentWithNestedIgnoredProperties.new
parent.title = "Test Parent"
parent.nested = SubTypeWithIgnoredProperties.new(name: "Nested", value: "Valid")
parent.save!

# Manually add a deprecated property to the nested document in the database
doc_id = parent.id
raw_doc = ParentWithNestedIgnoredProperties.bucket.default_collection.get(doc_id).content
raw_doc["nested"]["deprecated_property"] = "This should be ignored"
ParentWithNestedIgnoredProperties.bucket.default_collection.replace(doc_id, raw_doc)

# Reload the parent
parent.reload

# The deprecated property should NOT be present in the nested document
expect(parent.nested.attributes.keys).not_to include("deprecated_property")
expect(parent.nested.name).to eq("Nested")
expect(parent.nested.value).to eq("Valid")
end

it "should ignore deprecated properties in deeply nested documents" do
# Create a parent with nested documents that have a child
parent = ParentWithNestedIgnoredProperties.new
parent.title = "Test Parent"
parent.nested = SubTypeWithIgnoredProperties.new(name: "Parent Nested", value: "Parent Value")
parent.save!

# Manually add deprecated properties at multiple levels
doc_id = parent.id
raw_doc = ParentWithNestedIgnoredProperties.bucket.default_collection.get(doc_id).content
raw_doc["deprecated_at_root"] = "Should be ignored at root level"
raw_doc["nested"]["deprecated_property"] = "Should be ignored in nested"
ParentWithNestedIgnoredProperties.bucket.default_collection.replace(doc_id, raw_doc)

# Reload the parent
parent.reload

# Deprecated properties should not be present at any level
expect(parent.attributes.keys).not_to include("deprecated_at_root")
expect(parent.nested.attributes.keys).not_to include("deprecated_property")
expect(parent.nested.name).to eq("Parent Nested")
expect(parent.nested.value).to eq("Parent Value")
end
end
end