Skip to content

Commit

Permalink
Merge branch 'master' into issue-392
Browse files Browse the repository at this point in the history
  • Loading branch information
TomWright authored Mar 14, 2024
2 parents 75812a5 + 0652b8e commit ef72645
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 15 deletions.
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

- Nothing yet.

## [v2.7.0] - 2024-03-14

### Added

- `null()` function. [See docs](https://daseldocs.tomwright.me/functions/null)

### Fixed

- Dasel now correctly handles `null` values.

## [v2.6.0] - 2024-02-15

### Added
Expand Down Expand Up @@ -655,7 +664,8 @@ See [documentation](https://daseldocs.tomwright.me) for all changes.

- Everything!

[unreleased]: https://github.com/TomWright/dasel/compare/v2.6.0...HEAD
[unreleased]: https://github.com/TomWright/dasel/compare/v2.7.0...HEAD
[v2.7.0]: https://github.com/TomWright/dasel/compare/v2.6.0...v2.7.0
[v2.6.0]: https://github.com/TomWright/dasel/compare/v2.5.0...v2.6.0
[v2.5.0]: https://github.com/TomWright/dasel/compare/v2.4.1...v2.5.0
[v2.4.1]: https://github.com/TomWright/dasel/compare/v2.4.0...v2.4.1
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# dasel

[![Gitbook](https://badges.aleen42.com/src/gitbook_1.svg)](https://daseldocs.tomwright.me)
[![Go Report Card](https://goreportcard.com/badge/github.com/TomWright/dasel)](https://goreportcard.com/report/github.com/TomWright/dasel)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/tomwright/dasel)](https://pkg.go.dev/github.com/tomwright/dasel)
[![Go Report Card](https://goreportcard.com/badge/github.com/TomWright/dasel/v2)](https://goreportcard.com/report/github.com/TomWright/dasel/v2)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/tomwright/dasel)](https://pkg.go.dev/github.com/tomwright/dasel/v2)
![Test](https://github.com/TomWright/dasel/workflows/Test/badge.svg)
![Build](https://github.com/TomWright/dasel/workflows/Build/badge.svg)
[![codecov](https://codecov.io/gh/TomWright/dasel/branch/master/graph/badge.svg)](https://codecov.io/gh/TomWright/dasel)
Expand Down
1 change: 1 addition & 0 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func standardFunctions() *FunctionCollection {
TypeFunc,
JoinFunc,
StringFunc,
NullFunc,

// Selectors
IndexFunc,
Expand Down
24 changes: 24 additions & 0 deletions func_null.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dasel

import (
"reflect"
)

var NullFunc = BasicFunction{
name: "null",
runFn: func(c *Context, s *Step, args []string) (Values, error) {
if err := requireNoArgs("null", args); err != nil {
return nil, err
}

input := s.inputs()

res := make(Values, len(input))

for k, _ := range args {
res[k] = ValueOf(reflect.ValueOf(new(any)).Elem())
}

return res, nil
},
}
29 changes: 29 additions & 0 deletions func_null_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package dasel

import (
"testing"
)

func TestNullFunc(t *testing.T) {
t.Run("Args", selectTestErr(
"null(1)",
map[string]interface{}{},
&ErrUnexpectedFunctionArgs{
Function: "null",
Args: []string{"1"},
}),
)

original := map[string]interface{}{}

t.Run(
"Null",
selectTest(
"null()",
original,
[]interface{}{
nil,
},
),
)
}
32 changes: 23 additions & 9 deletions func_or_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,40 @@ var OrDefaultFunc = BasicFunction{

runSubselect := func(value Value, selector string, defaultSelector string) (Value, error) {
gotValues, err := c.subSelect(value, selector)
notFound := false
if err != nil {
notFound := false
if errors.Is(err, &ErrPropertyNotFound{}) {
notFound = true
} else if errors.Is(err, &ErrIndexNotFound{Index: -1}) {
notFound = true
}
if notFound {
gotValues, err = c.subSelect(value, defaultSelector)
} else {
return Value{}, err
}
}
if len(gotValues) == 1 && err == nil {
return gotValues[0], nil

if !notFound {
// Check result of first query
if len(gotValues) != 1 {
return Value{}, fmt.Errorf("orDefault expects selector to return exactly 1 value")
}

// Consider nil values as not found
if gotValues[0].IsNil() {
notFound = true
}
}
if err != nil {
return Value{}, err

if notFound {
gotValues, err = c.subSelect(value, defaultSelector)
if err != nil {
return Value{}, err
}
if len(gotValues) != 1 {
return Value{}, fmt.Errorf("orDefault expects selector to return exactly 1 value")
}
}
return Value{}, fmt.Errorf("orDefault expects selector to return exactly 1 value")

return gotValues[0], nil
}

res := make(Values, 0)
Expand Down
10 changes: 10 additions & 0 deletions internal/command/delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,14 @@ func TestDeleteCommand(t *testing.T) {
nil,
nil,
))

t.Run("Issue346", func(t *testing.T) {
t.Run("DeleteNullValue", runTest(
[]string{"delete", "-r", "json", "foo"},
[]byte(`{"foo":null}`),
newline([]byte("{}")),
nil,
nil,
))
})
}
32 changes: 32 additions & 0 deletions internal/command/select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,5 +449,37 @@ d.e.f`)),
nil,
nil,
))

t.Run("Issue346", func(t *testing.T) {
t.Run("Select null or default string", runTest(
[]string{"-r", "json", "orDefault(foo,string(nope))"},
[]byte(`{
"foo": null
}`),
newline([]byte(`"nope"`)),
nil,
nil,
))

t.Run("Select null or default null", runTest(
[]string{"-r", "json", "orDefault(foo,null())"},
[]byte(`{
"foo": null
}`),
newline([]byte(`null`)),
nil,
nil,
))

t.Run("Select null value", runTest(
[]string{"-r", "json", "foo"},
[]byte(`{
"foo": null
}`),
newline([]byte(`null`)),
nil,
nil,
))
})

}
22 changes: 20 additions & 2 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ func (v Value) IsEmpty() bool {
return isEmptyReflectValue(unpackReflectValue(v.Value))
}

func (v Value) IsNil() bool {
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return v.Value.IsNil()
default:
return false
}
}

func isEmptyReflectValue(v reflect.Value) bool {
if (v == reflect.Value{}) {
return true
Expand Down Expand Up @@ -124,6 +133,9 @@ func unpackReflectValue(value reflect.Value, kinds ...reflect.Kind) reflect.Valu
if !containsKind(kinds, res.Kind()) {
return res
}
if res.IsNil() {
return res
}
res = res.Elem()
}
}
Expand All @@ -138,6 +150,9 @@ func (v Value) FirstAddressable() reflect.Value {

// Unpack returns the underlying reflect.Value after resolving any pointers or interface types.
func (v Value) Unpack(kinds ...reflect.Kind) reflect.Value {
if !v.Value.IsValid() {
return reflect.ValueOf(new(any)).Elem()
}
return unpackReflectValue(v.Value, kinds...)
}

Expand Down Expand Up @@ -182,6 +197,9 @@ func (v Value) dencodingMapIndex(key Value) Value {
if v, ok := om.Get(key.Value.String()); !ok {
return reflect.Value{}
} else {
if v == nil {
return reflect.ValueOf(new(any)).Elem()
}
return reflect.ValueOf(v)
}
}
Expand Down Expand Up @@ -503,7 +521,7 @@ func (v Values) Interfaces() []interface{} {
func (v Values) initEmptydencodingMaps() Values {
res := make(Values, len(v))
for k, value := range v {
if value.IsEmpty() {
if value.IsEmpty() || value.IsNil() {
res[k] = value.initEmptydencodingMap()
} else {
res[k] = value
Expand All @@ -515,7 +533,7 @@ func (v Values) initEmptydencodingMaps() Values {
func (v Values) initEmptySlices() Values {
res := make(Values, len(v))
for k, value := range v {
if value.IsEmpty() {
if value.IsEmpty() || value.IsNil() {
res[k] = value.initEmptySlice()
} else {
res[k] = value
Expand Down

0 comments on commit ef72645

Please sign in to comment.