From 2c80b1aa84b53526626ed5f7208ead59dfbfcead Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 31 Aug 2023 11:28:41 +0100 Subject: [PATCH 1/7] Add or-default functionality --- func.go | 1 + func_or_default.go | 58 +++++++++++++++++++++++++++++++++ internal/command/select_test.go | 24 ++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 func_or_default.go diff --git a/func.go b/func.go index 3e2b8966..f95c214d 100644 --- a/func.go +++ b/func.go @@ -68,6 +68,7 @@ func standardFunctions() *FunctionCollection { LastFunc, PropertyFunc, AppendFunc, + OrDefaultFunc, // Filters FilterFunc, diff --git a/func_or_default.go b/func_or_default.go new file mode 100644 index 00000000..f5e3da79 --- /dev/null +++ b/func_or_default.go @@ -0,0 +1,58 @@ +package dasel + +import ( + "errors" + "fmt" +) + +// ErrPropertyNotFound +// ErrIndexNotFound + +var OrDefaultFunc = BasicFunction{ + name: "orDefault", + runFn: func(c *Context, s *Step, args []string) (Values, error) { + if err := requireExactlyXArgs("orDefault", args, 2); err != nil { + return nil, err + } + + input := s.inputs() + + if c.CreateWhenMissing() { + input = input.initEmptydencodingMaps() + } + + runSubselect := func(value Value, selector string, defaultSelector string) (Value, error) { + gotValues, err := c.subSelect(value, selector) + if err != nil { + notFound := false + if errors.Is(err, &ErrPropertyNotFound{}) { + notFound = true + } else if errors.Is(err, &ErrIndexNotFound{}) { + notFound = true + } + if notFound { + gotValues, err = c.subSelect(value, defaultSelector) + } else { + return Value{}, err + } + } + if len(gotValues) != 1 { + return Value{}, fmt.Errorf("orDefault expects selector to return exactly 1 value") + } + return gotValues[0], err + } + + res := make(Values, 0) + + for _, val := range input { + resolvedValue, err := runSubselect(val, args[0], args[1]) + if err != nil { + return nil, err + } + + res = append(res, resolvedValue) + } + + return res, nil + }, +} diff --git a/internal/command/select_test.go b/internal/command/select_test.go index 8dbbd3e3..d888d432 100644 --- a/internal/command/select_test.go +++ b/internal/command/select_test.go @@ -228,4 +228,28 @@ octal: 8`)), nil, )) + t.Run("OrDefault", runTest( + []string{"-r", "json", "all().orDefault(locale,string(nope))"}, + []byte(`{ + "-LCr5pXw_fN32IqNDr4E": { + "bookCategory": "poetry", + "locale": "en-us", + "mediaType": "book", + "publisher": "Pomelo Books", + "title": "Sound Waves", + "type": "poetry" + }, + "-LDDHjkdY0306fZdvhEQ": { + "ISBN13": "978-1534402966", + "bookCategory": "fiction", + "title": "What Can You Do with a Toolbox?", + "type": "picturebook" + } +}`), + newline([]byte(`"en-us" +"nope"`)), + nil, + nil, + )) + } From ad1ecf92c5bfc466f497dace1fa080310816e045 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 31 Aug 2023 11:46:43 +0100 Subject: [PATCH 2/7] Add some tests --- func_or_default.go | 11 ++++-- func_or_default_test.go | 86 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 func_or_default_test.go diff --git a/func_or_default.go b/func_or_default.go index f5e3da79..da5a01a0 100644 --- a/func_or_default.go +++ b/func_or_default.go @@ -27,7 +27,7 @@ var OrDefaultFunc = BasicFunction{ notFound := false if errors.Is(err, &ErrPropertyNotFound{}) { notFound = true - } else if errors.Is(err, &ErrIndexNotFound{}) { + } else if errors.Is(err, &ErrIndexNotFound{Index: -1}) { notFound = true } if notFound { @@ -36,10 +36,13 @@ var OrDefaultFunc = BasicFunction{ return Value{}, err } } - if len(gotValues) != 1 { - return Value{}, fmt.Errorf("orDefault expects selector to return exactly 1 value") + if len(gotValues) == 1 && err == nil { + return gotValues[0], nil } - return gotValues[0], err + if err != nil { + return Value{}, err + } + return Value{}, fmt.Errorf("orDefault expects selector to return exactly 1 value") } res := make(Values, 0) diff --git a/func_or_default_test.go b/func_or_default_test.go new file mode 100644 index 00000000..5c0ac9da --- /dev/null +++ b/func_or_default_test.go @@ -0,0 +1,86 @@ +package dasel + +import ( + "testing" +) + +func TestOrDefaultFunc(t *testing.T) { + t.Run("Args", selectTestErr( + "orDefault()", + map[string]interface{}{}, + &ErrUnexpectedFunctionArgs{ + Function: "property", + Args: []string{}, + }), + ) + + t.Run("OriginalAndDefaultNotFoundProperty", selectTestErr( + "orDefault(a,b)", + map[string]interface{}{"x": "y"}, + &ErrPropertyNotFound{ + Property: "b", + }), + ) + + t.Run("OriginalAndDefaultNotFoundIndex", selectTestErr( + "orDefault(x.[1],x.[2])", + map[string]interface{}{"x": []int{1}}, + &ErrIndexNotFound{ + Index: 2, + }), + ) + + original := map[string]interface{}{ + "name": map[string]interface{}{ + "first": "Tom", + "last": "Wright", + }, + "colours": []interface{}{ + "red", "green", "blue", + }, + } + + t.Run( + "FirstNameOrLastName", + selectTest( + "orDefault(name.first,name.last)", + original, + []interface{}{ + "Tom", + }, + ), + ) + + t.Run( + "MiddleNameOrDefault", + selectTest( + "orDefault(name.middle,string(default))", + original, + []interface{}{ + "default", + }, + ), + ) + + t.Run( + "FirstColourOrSecondColour", + selectTest( + "orDefault(colours.[0],colours.[2])", + original, + []interface{}{ + "red", + }, + ), + ) + + t.Run( + "FourthColourOrDefault", + selectTest( + "orDefault(colours.[3],string(default))", + original, + []interface{}{ + "default", + }, + ), + ) +} From 51bbeef56919f698fddf0ae97291861c523fe9d5 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 31 Aug 2023 11:50:56 +0100 Subject: [PATCH 3/7] Fix a broken test --- func_or_default_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/func_or_default_test.go b/func_or_default_test.go index 5c0ac9da..1f8e2af8 100644 --- a/func_or_default_test.go +++ b/func_or_default_test.go @@ -9,7 +9,7 @@ func TestOrDefaultFunc(t *testing.T) { "orDefault()", map[string]interface{}{}, &ErrUnexpectedFunctionArgs{ - Function: "property", + Function: "orDefault", Args: []string{}, }), ) From 0b0a1c51e105e2ecec1b7307f3d8c0d8d1a66780 Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 31 Aug 2023 14:34:50 +0100 Subject: [PATCH 4/7] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb13184..179c2e30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- `orDefault()` function. + ### Fixed - Resolved an issue with YAML parser that was causing strings to be read as booleans. From 034fc9297b861ccc4130ced3b005814be53b331f Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Thu, 31 Aug 2023 16:17:08 +0100 Subject: [PATCH 5/7] Remove redundant comments --- func_or_default.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/func_or_default.go b/func_or_default.go index da5a01a0..49fc8dd3 100644 --- a/func_or_default.go +++ b/func_or_default.go @@ -5,9 +5,6 @@ import ( "fmt" ) -// ErrPropertyNotFound -// ErrIndexNotFound - var OrDefaultFunc = BasicFunction{ name: "orDefault", runFn: func(c *Context, s *Step, args []string) (Values, error) { From 4c0c8999ea5da53ac4a805a2fc3210dde851cf5c Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Wed, 18 Oct 2023 17:51:32 +0100 Subject: [PATCH 6/7] Add a test --- internal/command/select_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/internal/command/select_test.go b/internal/command/select_test.go index 833e7dae..95602e1e 100644 --- a/internal/command/select_test.go +++ b/internal/command/select_test.go @@ -252,6 +252,30 @@ octal: 8`)), nil, )) + t.Run("OrDefaultLookup", runTest( + []string{"-r", "json", "all().orDefault(locale,bookCategory)"}, + []byte(`{ + "-LCr5pXw_fN32IqNDr4E": { + "bookCategory": "poetry", + "locale": "en-us", + "mediaType": "book", + "publisher": "Pomelo Books", + "title": "Sound Waves", + "type": "poetry" + }, + "-LDDHjkdY0306fZdvhEQ": { + "ISBN13": "978-1534402966", + "bookCategory": "fiction", + "title": "What Can You Do with a Toolbox?", + "type": "picturebook" + } +}`), + newline([]byte(`"en-us" +"fiction"`)), + nil, + nil, + )) + t.Run("Issue364 - CSV root element part 1", runTest( []string{"-r", "csv", "-w", "csv", "all().merge()"}, []byte(`A,B,C From 7ba50af48601aac3d9757c463e5c23c448698bab Mon Sep 17 00:00:00 2001 From: Tom Wright Date: Wed, 18 Oct 2023 18:00:20 +0100 Subject: [PATCH 7/7] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 801f2496..1348522b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `orDefault()` function. +- `orDefault()` function. [See docs](https://daseldocs.tomwright.me/functions/ordefault) ### Fixed