Skip to content

Commit

Permalink
Add CountFunc
Browse files Browse the repository at this point in the history
  • Loading branch information
TomWright committed Nov 21, 2022
1 parent a8841ea commit 743da9c
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 6 deletions.
13 changes: 13 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ func newDeleteContext(value interface{}, selector string) *Context {
return newContextWithFunctions(value, selector, standardFunctions())
}

// Select resolves the given selector and returns the resulting values.
func Select(root interface{}, selector string) (Values, error) {
c := newSelectContext(root, selector)
return c.Run()
}

// Put resolves the given selector and writes the given value in their place.
// The root value may be changed in-place. If this is not desired you should copy the input
// value before passing it to Put.
func Put(root interface{}, selector string, value interface{}) (Value, error) {
toSet := ValueOf(value)
c := newPutContext(root, selector)
Expand All @@ -97,6 +101,9 @@ func Put(root interface{}, selector string, value interface{}) (Value, error) {
return c.Data(), nil
}

// Delete resolves the given selector and deletes any found values.
// The root value may be changed in-place. If this is not desired you should copy the input
// value before passing it to Delete.
func Delete(root interface{}, selector string) (Value, error) {
c := newDeleteContext(root, selector)
values, err := c.Run()
Expand All @@ -117,21 +124,27 @@ func (c *Context) subSelect(value interface{}, selector string) (Values, error)
return c.subSelectContext(value, selector).Run()
}

// WithSelector updates c with the given selector.
func (c *Context) WithSelector(s string) *Context {
c.selector = s
c.selectorResolver = NewSelectorResolver(s, c.functions)
return c
}

// WithCreateWhenMissing updates c with the given create value.
// If this value is true, elements (such as properties) will be initialised instead
// of return not found errors.
func (c *Context) WithCreateWhenMissing(create bool) *Context {
c.createWhenMissing = create
return c
}

// CreateWhenMissing returns true if the internal createWhenMissing value is true.
func (c *Context) CreateWhenMissing() bool {
return c.createWhenMissing
}

// Data returns the root element of the context.
func (c *Context) Data() Value {
return c.data
}
Expand Down
1 change: 1 addition & 0 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func standardFunctions() *FunctionCollection {
LenFunc,
KeyFunc,
MergeFunc,
CountFunc,

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

var CountFunc = BasicFunction{
name: "count",
runFn: func(c *Context, s *Step, args []string) (Values, error) {
input := s.inputs()

return Values{
ValueOf(len(input)),
}, nil
},
}
41 changes: 41 additions & 0 deletions func_count_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dasel

import (
"testing"
)

func TestCountFunc(t *testing.T) {
data := map[string]interface{}{
"string": "hello",
"slice": []interface{}{
1, 2, 3,
},
"falseBool": false,
"trueBool": true,
}

t.Run(
"RootObject",
selectTest(
"count()",
data,
[]interface{}{1},
),
)
t.Run(
"All",
selectTest(
"all().count()",
data,
[]interface{}{4},
),
)
t.Run(
"NestedAll",
selectTest(
"slice.all().count()",
data,
[]interface{}{3},
),
)
}
10 changes: 4 additions & 6 deletions internal/command/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,12 @@ func runTest(args []string, in []byte, expStdOut []byte, expStdErr []byte, expEr
return
}

if !reflect.DeepEqual(expStdOut, gotStdOut) {
t.Errorf("expected stdout %s, got %s", string(expStdOut), string(gotStdOut))
return
}

if !reflect.DeepEqual(expStdErr, gotStdErr) {
t.Errorf("expected stderr %s, got %s", string(expStdErr), string(gotStdErr))
return
}

if !reflect.DeepEqual(expStdOut, gotStdOut) {
t.Errorf("expected stdout %s, got %s", string(expStdOut), string(gotStdOut))
}
}
}
Expand Down
83 changes: 83 additions & 0 deletions internal/command/select_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package command

import (
"testing"
)

func standardJsonSelectTestData() []byte {
return []byte(`{
"users": [
{
"name": {
"first": "Tom",
"last": "Wright"
},
"flags": {
"isBanned": false
}
},
{
"name": {
"first": "Jim",
"last": "Wright"
},
"flags": {
"isBanned": true
}
},
{
"name": {
"first": "Joe",
"last": "Blogs"
},
"flags": {
"isBanned": false
}
}
]
}`)
}

func TestSelectCommand(t *testing.T) {

t.Run("TotalUsers", runTest(
[]string{"-r", "json", "--pretty=false", "users.len()"},
standardJsonSelectTestData(),
newline([]byte(`3`)),
nil,
nil,
))

t.Run("TotalBannedUsers", runTest(
[]string{"-r", "json", "--pretty=false", "users.all().filter(equal(flags.isBanned,true)).count()"},
standardJsonSelectTestData(),
newline([]byte(`1`)),
nil,
nil,
))

t.Run("TotalUnBannedUsers", runTest(
[]string{"-r", "json", "--pretty=false", "users.all().filter(equal(flags.isBanned,false)).count()"},
standardJsonSelectTestData(),
newline([]byte(`2`)),
nil,
nil,
))

t.Run("NotBannedUsers", runTest(
[]string{"-r", "json", "--pretty=false", "users.all().filter(equal(flags.isBanned,false)).name.first"},
standardJsonSelectTestData(),
newline([]byte(`"Tom"
"Joe"`)),
nil,
nil,
))

t.Run("BannedUsers", runTest(
[]string{"-r", "json", "--pretty=false", "users.all().filter(equal(flags.isBanned,true)).name.first"},
standardJsonSelectTestData(),
newline([]byte(`"Jim"`)),
nil,
nil,
))
}

0 comments on commit 743da9c

Please sign in to comment.