Skip to content
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
2 changes: 1 addition & 1 deletion lib/couchbase-orm/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Document
include Encrypt

extend Enum
extend IgnoredProperties

define_model_callbacks :initialize, :only => :after

Expand Down Expand Up @@ -134,7 +135,6 @@ class Base < Document
extend EnsureUnique
extend HasMany
extend Index
extend IgnoredProperties
extend JsonSchema::Validation
extend PropertiesAlwaysExistsInDocument

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
Loading