From f3c29a464158daf4701021e31227b381534877d8 Mon Sep 17 00:00:00 2001 From: Ggicci Date: Sat, 30 Dec 2023 16:02:49 -0500 Subject: [PATCH] feat: expose Resolver.Copy --- directive.go | 17 +++++++++++++++-- directive_test.go | 8 ++++++++ resolver.go | 23 ++++++++++++++++++----- resolver_test.go | 4 ++-- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/directive.go b/directive.go index f3187d0..7ab310e 100644 --- a/directive.go +++ b/directive.go @@ -50,8 +50,17 @@ func ParseDirective(directive string) (*Directive, error) { return NewDirective(name, argv...), nil } -func isValidDirectiveName(name string) bool { - return reDirectiveName.MatchString(name) +// Copy creates a copy of the directive. The copy is a deep copy. +func (d *Directive) Copy() *Directive { + return NewDirective(d.Name, d.Argv...) +} + +// String returns the string representation of the directive. +func (d *Directive) String() string { + if len(d.Argv) == 0 { + return d.Name + } + return d.Name + "=" + strings.Join(d.Argv, ",") } // DirectiveExecutor is the interface that wraps the Execute method. @@ -108,3 +117,7 @@ type DirectiveRuntime struct { // and if in dirA we set a value of "foo" to "bar", then in dirB we can get the value of "foo" as "bar". Context context.Context } + +func isValidDirectiveName(name string) bool { + return reDirectiveName.MatchString(name) +} diff --git a/directive_test.go b/directive_test.go index 6ae8ae6..6fd088c 100644 --- a/directive_test.go +++ b/directive_test.go @@ -66,3 +66,11 @@ func TestParseDirective(t *testing.T) { assert.ErrorIs(t, err, testcase.err) } } + +func TestDirective_String(t *testing.T) { + d := owl.NewDirective("form", "page", "page_index") + assert.Equal(t, "form=page,page_index", d.String()) + + d = owl.NewDirective("required") + assert.Equal(t, "required", d.String()) +} diff --git a/resolver.go b/resolver.go index 04af98d..068f2fb 100644 --- a/resolver.go +++ b/resolver.go @@ -43,7 +43,7 @@ func New(structValue interface{}, opts ...Option) (*Resolver, error) { if err != nil { return nil, err } - tree = tree.copy() + tree = tree.Copy() // Apply options, build the context for each resolver. defaultOpts := []Option{WithNamespace(defaultNS)} @@ -67,15 +67,28 @@ func New(structValue interface{}, opts ...Option) (*Resolver, error) { return tree, nil } -func (r *Resolver) copy() *Resolver { +// Copy returns a copy of the resolver tree. The copy is a deep copy, which +// means the children are also copied. +func (r *Resolver) Copy() *Resolver { resolverCopy := new(Resolver) *resolverCopy = *r - resolverCopy.Context = context.Background() - // Copy the children. + // Copy index and path. + resolverCopy.Index = make([]int, len(r.Index)) + copy(resolverCopy.Index, r.Index) + resolverCopy.Path = make([]string, len(r.Path)) + copy(resolverCopy.Path, r.Path) + + // Copy the directives. + resolverCopy.Directives = make([]*Directive, len(r.Directives)) + for i, d := range r.Directives { + resolverCopy.Directives[i] = d.Copy() + } + + // Copy the children and set the parent. resolverCopy.Children = make([]*Resolver, len(r.Children)) for i, child := range r.Children { - resolverCopy.Children[i] = child.copy() + resolverCopy.Children[i] = child.Copy() resolverCopy.Children[i].Parent = resolverCopy } return resolverCopy diff --git a/resolver_test.go b/resolver_test.go index 6064888..d432fbe 100644 --- a/resolver_test.go +++ b/resolver_test.go @@ -182,7 +182,7 @@ func TestNew_SkipFieldsHavingNoDirectives(t *testing.T) { Index: []int{}, LookupPath: "", NumFields: 3, - Directives: nil, + Directives: []*owl.Directive{}, Leaf: false, }, { @@ -206,7 +206,7 @@ func TestNew_SkipFieldsHavingNoDirectives(t *testing.T) { Index: []int{3}, // Pagination is the 4th field, Hidden is the 3rd field. LookupPath: "Pagination", NumFields: 2, - Directives: nil, + Directives: []*owl.Directive{}, Leaf: false, }, {