From 9adc1bfc2a993855e68bfe42302774a484d32b93 Mon Sep 17 00:00:00 2001 From: Bruno Albuquerque Date: Wed, 18 Feb 2026 11:27:51 -0500 Subject: [PATCH] release: v4.0.0 - Updated module path and all imports to v4\n- Cleaned up public API documentation\n- Merged PatchBuilder and Node into a single fluent API\n- Enhanced ConflictResolver with current/proposed value context\n- Standardized on strict JSON Pointers\n- Fixed various static analysis issues and improved examples --- README.md | 65 +++++++++++++++++++----------- builder.go | 6 +-- builder_test.go | 2 +- cond/condition.go | 2 +- cond/condition_impl.go | 2 +- cond/condition_parser.go | 2 +- cond/condition_serialization.go | 2 +- cond/condition_test.go | 2 +- copy.go | 2 +- crdt/crdt.go | 8 ++-- crdt/crdt_test.go | 2 +- crdt/text.go | 2 +- crdt/text_test.go | 2 +- diff.go | 4 +- equal.go | 2 +- examples/audit_logging/main.go | 2 +- examples/business_rules/main.go | 2 +- examples/config_manager/main.go | 2 +- examples/crdt_sync/main.go | 2 +- examples/custom_types/main.go | 2 +- examples/http_patch_api/main.go | 2 +- examples/json_interop/main.go | 2 +- examples/key_normalization/main.go | 2 +- examples/keyed_inventory/main.go | 2 +- examples/move_detection/main.go | 2 +- examples/multi_error/main.go | 2 +- examples/state_management/main.go | 2 +- examples/text_sync/main.go | 2 +- examples/three_way_merge/main.go | 2 +- examples/websocket_sync/main.go | 2 +- go.mod | 2 +- internal/core/copy.go | 2 +- internal/core/equal.go | 2 +- internal/core/path.go | 2 +- internal/core/util.go | 2 +- internal/unsafe/disable_ro_test.go | 4 +- merge.go | 2 +- options.go | 2 +- patch.go | 2 +- patch_graph.go | 2 +- patch_ops.go | 6 +-- patch_serialization.go | 4 +- patch_serialization_test.go | 2 +- patch_test.go | 2 +- patch_utils.go | 2 +- patch_utils_test.go | 2 +- resolvers/crdt/lww.go | 4 +- resolvers/crdt/lww_test.go | 4 +- 48 files changed, 100 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index ab31d99..46c2413 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ `deep` is a high-performance, reflection-based engine for manipulating complex Go data structures. It provides recursive deep copying, semantic equality checks, and structural diffing to produce optimized patches. -V3 is designed for high-throughput applications, featuring a zero-allocation diffing engine and tag-aware operations. +V4 focuses on API ergonomics with a fluent patch builder and advanced conflict resolution for distributed systems. ## Installation ```bash -go get github.com/brunoga/deep/v3 +go get github.com/brunoga/deep/v4 ``` --- @@ -42,7 +42,7 @@ if deep.Equal(objA, objB) { ```go // Generate patch -patch := deep.Diff(oldState, newState) +patch, err := deep.Diff(oldState, newState) // Inspect changes fmt.Println(patch.Summary()) @@ -59,11 +59,29 @@ err := patch.ApplyChecked(&oldState) ## Advanced Capabilities -### Conflict Resolution & CRDTs -**Justification:** In distributed systems, state often diverges. `deep` provides first-class support for state convergence using Hybrid Logical Clocks (HLC). +### Fluent Patch Builder +V4 introduces a fluent API for manual patch construction, allowing for intuitive navigation and modification of data structures without manual path management. -* **LWW Resolver**: Automatic "Last-Write-Wins" resolution at the field level. -* **Example**: [CRDT Synchronization](./examples/crdt_sync/main.go) +```go +builder := deep.NewPatchBuilder[MyStruct]() +builder.Field("Profile").Field("Age").Set(30, 31) +builder.Field("Tags").Add(0, "new-tag") +patch, err := builder.Build() +``` + +### Advanced Conflict Resolution +For distributed systems and CRDTs, `deep` allows you to intercept and resolve conflicts dynamically. The resolver has access to both the **current** value at the target path and the **proposed** value. + +```go +type MyResolver struct{} + +func (r *MyResolver) Resolve(path string, op deep.OpKind, key, prevKey any, current, proposed reflect.Value) (reflect.Value, bool) { + // Custom logic: e.g., semantic 3-way merge or timestamp-based LWW + return proposed, true +} + +err := patch.ApplyResolved(&state, &MyResolver{}) +``` ### Struct Tag Control Fine-grained control over library behavior: @@ -76,34 +94,33 @@ Fine-grained control over library behavior: ## Performance Optimization -v3.0 is built for performance-critical hot paths: -* **Zero-Allocation Engine**: Uses `sync.Pool` for internal transient structures. +Built for performance-critical hot paths: +* **Zero-Allocation Engine**: Uses `sync.Pool` for internal transient structures during diffing. +* **Reflection Cache**: Global cache for type metadata to eliminate repetitive lookups. * **Lazy Allocation**: Maps and slices in patches are only allocated if changes are found. -* **Manual Release**: Use `patch.Release()` to return patch resources to the pool. --- ## Version History -### v1.0.0: The Foundation -* Initial recursive **Deep Copy** implementation. -* Basic **Deep Diff** producing Add/Remove/Replace operations. -* Support for standard Go types (Slices, Maps, Structs, Pointers). +### v4.0.0: Ergonomics & Context (Current) +* **Fluent Patch Builder**: Merged `Node` into `PatchBuilder` for a cleaner, chainable API. +* **Context-Aware Resolution**: `ConflictResolver` now receives both `current` and `proposed` values and can return a merged result. +* **Strict JSON Pointers**: Removed dot-notation support in favor of strict RFC 6901 compliance. +* **Simplified Registry**: Global `RegisterCustom*` functions for easier extension. + +### v3.0.0: High-Performance Engine +* **Zero-Allocation Engine**: Refactored to use object pooling. +* **`deep.Equal[T]`**: High-performance, tag-aware replacement for `reflect.DeepEqual`. +* **Move & Copy Detection**: Semantic detection of relocated values during `Diff`. ### v2.0.0: Synchronization & Standards -* **JSON Pointer (RFC 6901)**: Standardized all path navigation. +* **JSON Pointer (RFC 6901)**: Standardized path navigation. * **Keyed Slice Alignment**: Integrated identity-based matching into Myers' Diff. -* **Human-Readable Summaries**: Added `Patch.Summary()` for audit logging. * **HLC & CRDT**: Introduced Hybrid Logical Clocks and LWW conflict resolution. -* **Multi-Error Reporting**: `ApplyChecked` reports all validation failures at once. -### v3.0.0: High-Performance Engine (Current) -* **Zero-Allocation Engine**: Comprehensive refactor to use object pooling and path stacks. -* **`deep.Equal[T]`**: High-performance, tag-aware replacement for `reflect.DeepEqual`. -* **Move & Copy Detection**: Semantic detection of relocated values during `Diff`. -* **Custom Type Registry**: Support for registering specialized diffing logic for external types. -* **Pointer Identity Optimization**: Massive speedup via immediate short-circuiting for identical pointers. -* **Memory Efficiency**: Up to 80% reduction in memory overhead for large structural comparisons. +### v1.0.0: The Foundation +* Initial recursive **Deep Copy** and **Deep Diff** implementation. --- diff --git a/builder.go b/builder.go index 5f361c7..6bf16c2 100644 --- a/builder.go +++ b/builder.go @@ -6,8 +6,8 @@ import ( "strconv" "strings" - "github.com/brunoga/deep/v3/cond" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/cond" + "github.com/brunoga/deep/v4/internal/core" ) // PatchBuilder allows constructing a Patch[T] manually with on-the-fly type validation. @@ -472,7 +472,7 @@ func (b *PatchBuilder[T]) Elem() *PatchBuilder[T] { if b.state.err != nil || b.typ == nil || (b.typ.Kind() != reflect.Pointer && b.typ.Kind() != reflect.Interface) { return b } - updateFunc := b.update + var updateFunc func(diffPatch) var currentPatch diffPatch if b.typ.Kind() == reflect.Pointer { pp, ok := b.current.(*ptrPatch) diff --git a/builder_test.go b/builder_test.go index 15ac0cc..15ac256 100644 --- a/builder_test.go +++ b/builder_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/brunoga/deep/v3/cond" + "github.com/brunoga/deep/v4/cond" ) func TestBuilder_Basic(t *testing.T) { diff --git a/cond/condition.go b/cond/condition.go index 64ba777..d58e01e 100644 --- a/cond/condition.go +++ b/cond/condition.go @@ -3,7 +3,7 @@ package cond import ( "encoding/json" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // Condition represents a logical check against a value of type T. diff --git a/cond/condition_impl.go b/cond/condition_impl.go index e289609..a8dc69f 100644 --- a/cond/condition_impl.go +++ b/cond/condition_impl.go @@ -6,7 +6,7 @@ import ( "regexp" "strings" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) type rawDefinedCondition struct { diff --git a/cond/condition_parser.go b/cond/condition_parser.go index 27877fb..65e58ca 100644 --- a/cond/condition_parser.go +++ b/cond/condition_parser.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // ParseCondition parses a string expression into a Condition[T] tree. diff --git a/cond/condition_serialization.go b/cond/condition_serialization.go index b0657cb..6f35d34 100644 --- a/cond/condition_serialization.go +++ b/cond/condition_serialization.go @@ -7,7 +7,7 @@ import ( "reflect" "strings" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) func init() { diff --git a/cond/condition_test.go b/cond/condition_test.go index badf20d..e775637 100644 --- a/cond/condition_test.go +++ b/cond/condition_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) func TestJSONPointer_Resolve(t *testing.T) { diff --git a/copy.go b/copy.go index bafaaf3..c5b0bd2 100644 --- a/copy.go +++ b/copy.go @@ -1,7 +1,7 @@ package deep import ( - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // Copier is an interface that types can implement to provide their own diff --git a/crdt/crdt.go b/crdt/crdt.go index 9ded455..ad71d54 100644 --- a/crdt/crdt.go +++ b/crdt/crdt.go @@ -6,10 +6,10 @@ import ( "sort" "sync" - "github.com/brunoga/deep/v3" - "github.com/brunoga/deep/v3/cond" - "github.com/brunoga/deep/v3/crdt/hlc" - crdtresolver "github.com/brunoga/deep/v3/resolvers/crdt" + "github.com/brunoga/deep/v4" + "github.com/brunoga/deep/v4/cond" + "github.com/brunoga/deep/v4/crdt/hlc" + crdtresolver "github.com/brunoga/deep/v4/resolvers/crdt" ) func init() { diff --git a/crdt/crdt_test.go b/crdt/crdt_test.go index 194ac68..7c666aa 100644 --- a/crdt/crdt_test.go +++ b/crdt/crdt_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) type TestUser struct { diff --git a/crdt/text.go b/crdt/text.go index 2e43ac2..07fb73b 100644 --- a/crdt/text.go +++ b/crdt/text.go @@ -4,7 +4,7 @@ import ( "sort" "strings" - "github.com/brunoga/deep/v3/crdt/hlc" + "github.com/brunoga/deep/v4/crdt/hlc" ) // TextRun represents a contiguous run of characters with a unique starting ID. diff --git a/crdt/text_test.go b/crdt/text_test.go index ca1cd65..2a0cb71 100644 --- a/crdt/text_test.go +++ b/crdt/text_test.go @@ -4,7 +4,7 @@ import ( "sync" "testing" - "github.com/brunoga/deep/v3/crdt/hlc" + "github.com/brunoga/deep/v4/crdt/hlc" ) func TestText_Insert(t *testing.T) { diff --git a/diff.go b/diff.go index 3672ecf..c76290c 100644 --- a/diff.go +++ b/diff.go @@ -7,8 +7,8 @@ import ( "strings" "sync" - "github.com/brunoga/deep/v3/internal/core" - "github.com/brunoga/deep/v3/internal/unsafe" + "github.com/brunoga/deep/v4/internal/core" + "github.com/brunoga/deep/v4/internal/unsafe" ) // DiffOption allows configuring the behavior of the Diff function. diff --git a/equal.go b/equal.go index 376569f..8afbefd 100644 --- a/equal.go +++ b/equal.go @@ -1,7 +1,7 @@ package deep import ( - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // Equal performs a deep equality check between a and b. diff --git a/examples/audit_logging/main.go b/examples/audit_logging/main.go index 0edd8da..683c163 100644 --- a/examples/audit_logging/main.go +++ b/examples/audit_logging/main.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // User represents a typical user profile in a system. diff --git a/examples/business_rules/main.go b/examples/business_rules/main.go index 2111642..98dd31c 100644 --- a/examples/business_rules/main.go +++ b/examples/business_rules/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // Account represents a financial account. diff --git a/examples/config_manager/main.go b/examples/config_manager/main.go index e7e7549..0ef9678 100644 --- a/examples/config_manager/main.go +++ b/examples/config_manager/main.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // --- CONFIGURATION SCHEMA --- diff --git a/examples/crdt_sync/main.go b/examples/crdt_sync/main.go index dbbfe0e..1d9015e 100644 --- a/examples/crdt_sync/main.go +++ b/examples/crdt_sync/main.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/brunoga/deep/v3/crdt" + "github.com/brunoga/deep/v4/crdt" ) type Config struct { diff --git a/examples/custom_types/main.go b/examples/custom_types/main.go index 3888c1e..2898f4d 100644 --- a/examples/custom_types/main.go +++ b/examples/custom_types/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" "time" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) type Audit struct { diff --git a/examples/http_patch_api/main.go b/examples/http_patch_api/main.go index 65918a7..d3963d0 100644 --- a/examples/http_patch_api/main.go +++ b/examples/http_patch_api/main.go @@ -8,7 +8,7 @@ import ( "net/http" "net/http/httptest" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // Resource is the data we want to manage over the network. diff --git a/examples/json_interop/main.go b/examples/json_interop/main.go index 64b0df4..cdbab3c 100644 --- a/examples/json_interop/main.go +++ b/examples/json_interop/main.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // UIState represents something typically shared between a Go backend and a JS frontend. diff --git a/examples/key_normalization/main.go b/examples/key_normalization/main.go index b5e356c..c3d6965 100644 --- a/examples/key_normalization/main.go +++ b/examples/key_normalization/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // ResourceID represents a complex key that might have transient state. diff --git a/examples/keyed_inventory/main.go b/examples/keyed_inventory/main.go index 3346dd4..d9c9674 100644 --- a/examples/keyed_inventory/main.go +++ b/examples/keyed_inventory/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // Product represents an item in an inventory. diff --git a/examples/move_detection/main.go b/examples/move_detection/main.go index 7302da3..ba03e9c 100644 --- a/examples/move_detection/main.go +++ b/examples/move_detection/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) type Document struct { diff --git a/examples/multi_error/main.go b/examples/multi_error/main.go index 6e7b3fd..0c4f8bd 100644 --- a/examples/multi_error/main.go +++ b/examples/multi_error/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) type UserProfile struct { diff --git a/examples/state_management/main.go b/examples/state_management/main.go index a1af40f..e38c69d 100644 --- a/examples/state_management/main.go +++ b/examples/state_management/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // Document represents a document being edited. diff --git a/examples/text_sync/main.go b/examples/text_sync/main.go index 0013b5f..2048b3f 100644 --- a/examples/text_sync/main.go +++ b/examples/text_sync/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3/crdt" + "github.com/brunoga/deep/v4/crdt" ) // Document represents a text document using the specialized CRDT Text type. diff --git a/examples/three_way_merge/main.go b/examples/three_way_merge/main.go index 20634c8..0c15566 100644 --- a/examples/three_way_merge/main.go +++ b/examples/three_way_merge/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) type SystemConfig struct { diff --git a/examples/websocket_sync/main.go b/examples/websocket_sync/main.go index a2cee40..dd09992 100644 --- a/examples/websocket_sync/main.go +++ b/examples/websocket_sync/main.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - "github.com/brunoga/deep/v3" + "github.com/brunoga/deep/v4" ) // GameWorld represents a shared state (e.g., in a real-time game or collab tool). diff --git a/go.mod b/go.mod index c2f7501..6a6dc7d 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/brunoga/deep/v3 +module github.com/brunoga/deep/v4 go 1.20.0 diff --git a/internal/core/copy.go b/internal/core/copy.go index a0a7950..86d39c3 100644 --- a/internal/core/copy.go +++ b/internal/core/copy.go @@ -7,7 +7,7 @@ import ( "strings" "sync" - "github.com/brunoga/deep/v3/internal/unsafe" + "github.com/brunoga/deep/v4/internal/unsafe" ) // Copier is an interface that types can implement to provide their own diff --git a/internal/core/equal.go b/internal/core/equal.go index 70a4c60..30193ab 100644 --- a/internal/core/equal.go +++ b/internal/core/equal.go @@ -7,7 +7,7 @@ import ( "strings" "sync" - "github.com/brunoga/deep/v3/internal/unsafe" + "github.com/brunoga/deep/v4/internal/unsafe" ) // EqualOption allows configuring the behavior of the Equal function. diff --git a/internal/core/path.go b/internal/core/path.go index db8ad71..5439cf6 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/brunoga/deep/v3/internal/unsafe" + "github.com/brunoga/deep/v4/internal/unsafe" ) // DeepPath represents a path to a field or element within a structure. diff --git a/internal/core/util.go b/internal/core/util.go index 65e183a..95aa5c7 100644 --- a/internal/core/util.go +++ b/internal/core/util.go @@ -4,7 +4,7 @@ import ( "encoding/json" "reflect" - "github.com/brunoga/deep/v3/internal/unsafe" + "github.com/brunoga/deep/v4/internal/unsafe" ) func ConvertValue(v reflect.Value, targetType reflect.Type) reflect.Value { diff --git a/internal/unsafe/disable_ro_test.go b/internal/unsafe/disable_ro_test.go index c4eb398..8c2c31b 100644 --- a/internal/unsafe/disable_ro_test.go +++ b/internal/unsafe/disable_ro_test.go @@ -4,8 +4,8 @@ import ( "reflect" "testing" - "github.com/brunoga/deep/v3/internal/unsafe" - "github.com/brunoga/deep/v3/internal/unsafe/testdata/foo" + "github.com/brunoga/deep/v4/internal/unsafe" + "github.com/brunoga/deep/v4/internal/unsafe/testdata/foo" ) func TestDisableRO_CrossPackage(t *testing.T) { diff --git a/merge.go b/merge.go index cd8c1b1..bcb28f6 100644 --- a/merge.go +++ b/merge.go @@ -5,7 +5,7 @@ import ( "reflect" "strings" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // Conflict represents a merge conflict where two patches modify the same path diff --git a/options.go b/options.go index b7c22cf..213f985 100644 --- a/options.go +++ b/options.go @@ -3,7 +3,7 @@ package deep import ( "reflect" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // DiffOption allows configuring the behavior of the Diff function. diff --git a/patch.go b/patch.go index 2156ce8..8d372a5 100644 --- a/patch.go +++ b/patch.go @@ -7,7 +7,7 @@ import ( "reflect" "strings" - "github.com/brunoga/deep/v3/cond" + "github.com/brunoga/deep/v4/cond" ) // OpKind represents the type of operation in a patch. diff --git a/patch_graph.go b/patch_graph.go index 5042ddd..942816a 100644 --- a/patch_graph.go +++ b/patch_graph.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // dependencyNode represents a node in the dependency graph. diff --git a/patch_ops.go b/patch_ops.go index ff909d4..f6c7dcc 100644 --- a/patch_ops.go +++ b/patch_ops.go @@ -7,9 +7,9 @@ import ( "strconv" "strings" - "github.com/brunoga/deep/v3/cond" - "github.com/brunoga/deep/v3/internal/core" - "github.com/brunoga/deep/v3/internal/unsafe" + "github.com/brunoga/deep/v4/cond" + "github.com/brunoga/deep/v4/internal/core" + "github.com/brunoga/deep/v4/internal/unsafe" ) var ErrConditionSkipped = fmt.Errorf("condition skipped") diff --git a/patch_serialization.go b/patch_serialization.go index 737406a..d109259 100644 --- a/patch_serialization.go +++ b/patch_serialization.go @@ -7,8 +7,8 @@ import ( "reflect" "sync" - "github.com/brunoga/deep/v3/cond" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/cond" + "github.com/brunoga/deep/v4/internal/core" ) type patchSurrogate struct { diff --git a/patch_serialization_test.go b/patch_serialization_test.go index b90b4c7..1286bf2 100644 --- a/patch_serialization_test.go +++ b/patch_serialization_test.go @@ -7,7 +7,7 @@ import ( "reflect" "testing" - "github.com/brunoga/deep/v3/cond" + "github.com/brunoga/deep/v4/cond" ) func TestPatchJSONSerialization(t *testing.T) { diff --git a/patch_test.go b/patch_test.go index 5921da1..a99ede4 100644 --- a/patch_test.go +++ b/patch_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/brunoga/deep/v3/cond" + "github.com/brunoga/deep/v4/cond" ) func TestPatch_String_Basic(t *testing.T) { diff --git a/patch_utils.go b/patch_utils.go index 09ffd89..98b798b 100644 --- a/patch_utils.go +++ b/patch_utils.go @@ -3,7 +3,7 @@ package deep import ( "fmt" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) // applyToBuilder recursively applies an operation to a PatchBuilder. diff --git a/patch_utils_test.go b/patch_utils_test.go index 8e5e7e1..a1edfd9 100644 --- a/patch_utils_test.go +++ b/patch_utils_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/brunoga/deep/v3/internal/core" + "github.com/brunoga/deep/v4/internal/core" ) func TestPatch_NumericConversion(t *testing.T) { diff --git a/resolvers/crdt/lww.go b/resolvers/crdt/lww.go index 507c221..0bed4e4 100644 --- a/resolvers/crdt/lww.go +++ b/resolvers/crdt/lww.go @@ -3,8 +3,8 @@ package crdt import ( "reflect" - "github.com/brunoga/deep/v3" - "github.com/brunoga/deep/v3/crdt/hlc" + "github.com/brunoga/deep/v4" + "github.com/brunoga/deep/v4/crdt/hlc" ) // LWWResolver implements deep.ConflictResolver using Last-Write-Wins logic diff --git a/resolvers/crdt/lww_test.go b/resolvers/crdt/lww_test.go index cdcc407..2735911 100644 --- a/resolvers/crdt/lww_test.go +++ b/resolvers/crdt/lww_test.go @@ -4,8 +4,8 @@ import ( "reflect" "testing" - "github.com/brunoga/deep/v3" - "github.com/brunoga/deep/v3/crdt/hlc" + "github.com/brunoga/deep/v4" + "github.com/brunoga/deep/v4/crdt/hlc" ) func TestLWWResolver(t *testing.T) {