Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new transform, and converters #4

Merged
merged 1 commit into from
Jan 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 109 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ API Documentation is available at http://godoc.org/gopkg.in/qntfy/kazaam.v3.

## Features
Kazaam is primarily designed to be used as a library for transforming arbitrary JSON.
It ships with nine built-in transform types, and fifteen built-in converter types,
It ships with ten built-in transform types, and fifteen built-in converter types,
described below, which provide significant flexibility in reshaping JSON data.

Also included when you `go get` Kazaam, is a binary implementation, `kazaam` that can be used for
Expand All @@ -45,6 +45,7 @@ need arises.

Kazaam currently supports the following built-in transforms:
- shift
- steps
- concat
- coalesce
- extract
Expand Down Expand Up @@ -157,6 +158,33 @@ within the arguments are preserved, if the whitespace around the arguments is re
Arguments are passed to the converter functions as a single string, and will require the converter function to parse out any meaningful parameters.


### Steps
The steps transform performs a series of shift transforms with each step working on the ouptput from the last step. This
transform is very similar to the shift transform, and takes the same optional parameters.

The following example produces the same results as the `Shift` transform example presented earlier. The only difference
is that the each of the steps are guaranteed to transform in the specified order.

```json
{
"operation": "steps",
"spec": {
"steps": [
{
"object.id": "doc.uid"
},
{
"gid2": "doc.guid[1]"
},
{
"allGuids": "doc.guidObjects[*].id"
}
]
}
}
```


### Concat
The concat transform allows the combination of fields and literal strings into a single string value.
```json
Expand Down Expand Up @@ -519,6 +547,9 @@ Kazaam currently supports the following built-in Conveters:
`substr <num> [<num>]` | converts a string value to a substring value
`trim` | converts a string value by removing the leading and trailing whitespace characters
`upper` | converts a string value to uppercase characters
`len` | converts a string to an integer value equal to the length of the string
`splitn <string> <num>` | splits a string by a delimiter string and returns the Nth token (1 based)
`eqs <any>` | returns `true` or `false` based on whether the value matches the parameter

### Converter Examples ###

Expand Down Expand Up @@ -950,6 +981,83 @@ produces:
}
```

#### Len ####

Returns the length of a string value

Argument | Description
---------|------------

example:
```json
{
"operation": "shift",
"spec": {
"output": "tests.test_string | len"
}
}
```

produces:
```json
{
"output": 19
}
```

#### Splitn ####

Returns the Nth token of a string split by a delimiter string

Argument | Description
---------|------------
string | delimiter string
number | one based position of token to return

example:
```json
{
"operation": "shift",
"spec": {
"output": "tests.test_string | splitn o 2"
}
}
```

produces:
```json
{
"output": "wn f"
}
```

#### Eqs ####

Returns `true` or `false` based on whether the value equals the parameter

Argument | Description
---------|------------
any | value to compare


example:
```json
{
"operation": "shift",
"spec": {
"output": "tests.test_string | eqs \"The quick brown fox\""
}
}
```

produces:
```json
{
"output": true
}
```



## Usage

Expand Down
28 changes: 28 additions & 0 deletions converter/eqs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package converter

import (
"bytes"
"github.com/mbordner/kazaam/transform"
)

type Eqs struct {
ConverterBase
}

func (c *Eqs) Convert(jsonData []byte, value []byte, args []byte) (newValue []byte, err error) {

var argsValue *transform.JSONValue
argsValue, err = c.NewJSONValue(args)
if err != nil {
return
}

argsBytes := []byte(argsValue.GetStringValue())

if bytes.Equal(value, argsBytes) == true {
return []byte("true"), nil
}

return []byte("false"), nil

}
37 changes: 37 additions & 0 deletions converter/eqs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package converter

import (
"strconv"
"testing"
"github.com/mbordner/kazaam/registry"
)

func TestEqs_Convert(t *testing.T) {

registry.RegisterConverter("eqs", &Eqs{})
c := registry.GetConverter("eqs")

table := []struct {
value string
arguments string
expected string
}{
{`"The quick brown fox jumps over the lazy dog"`, `"The quick brown fox jumps over the lazy dog"`, `true`,},
{`42`,`42`,`true`,},
}

for _, test := range table {
v, e := c.Convert(getTestData(), []byte(test.value), []byte(strconv.Quote(test.arguments)))

if e != nil {
t.Error("error running convert function")
}

if string(v) != test.expected {
t.Error("unexpected result from convert")
t.Log("Expected: {}", test.expected)
t.Log("Actual: {}", string(v))
}
}

}
32 changes: 32 additions & 0 deletions converter/len.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package converter

import (
"fmt"
"github.com/mbordner/kazaam/transform"
"github.com/pkg/errors"
)

type Len struct {
ConverterBase
}

func (c *Len) Convert(jsonData []byte, value []byte, args []byte) (newValue []byte, err error) {
newValue = value

var jsonValue *transform.JSONValue
jsonValue, err = c.NewJSONValue(value)
if err != nil {
return
}

if jsonValue.IsString() == false {
err = errors.New("value must be string for len converter")
return
}

origValue := jsonValue.GetStringValue()

newValue = []byte(fmt.Sprintf("%d", len(origValue)))

return
}
37 changes: 37 additions & 0 deletions converter/len_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package converter

import (
"github.com/mbordner/kazaam/registry"
"strconv"
"testing"
)

func TestLen_Convert(t *testing.T) {

registry.RegisterConverter("len", &Len{})
c := registry.GetConverter("len")

table := []struct {
value string
arguments string
expected string
}{
{`"The quick brown fox jumps over the lazy dog"`, ``, `43`,},
{`"the lazy dog"`, ``, `12`,},
}

for _, test := range table {
v, e := c.Convert(getTestData(), []byte(test.value), []byte(strconv.Quote(test.arguments)))

if e != nil {
t.Error("error running convert function")
}

if string(v) != test.expected {
t.Error("unexpected result from convert")
t.Log("Expected: {}", test.expected)
t.Log("Actual: {}", string(v))
}
}

}
65 changes: 65 additions & 0 deletions converter/splitn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package converter

import (
"errors"
"github.com/mbordner/kazaam/transform"
"regexp"
"strconv"
"strings"
)

type Splitn struct {
ConverterBase
}

// |substr start end , end is optional, and will be the last char sliced's index + 1,
// start is the start index and required
func (c *Splitn) Convert(jsonData []byte, value []byte, args []byte) (newValue []byte, err error) {
newValue = value

var jsonValue, argsValue *transform.JSONValue
jsonValue, err = c.NewJSONValue(value)
if err != nil {
return
}

argsValue, err = transform.NewJSONValue(args)
if err != nil {
return
}

if jsonValue.IsString() == false || argsValue.IsString() == false {
err = errors.New("invalid value or arguments for splintn converter")
return
}

var re *regexp.Regexp
re, err = regexp.Compile(`(?Us)^(?:\s*)(.+)(?:\s*)(\d+)*(?:\s*)$`)
if err != nil {
return
}

argsString := argsValue.GetStringValue()
origValue := jsonValue.GetStringValue()

var n int64

newValue = []byte("null")

if matches := re.FindStringSubmatch(argsString); matches != nil {
n, err = strconv.ParseInt(matches[2], 10, 64)
if err != nil {
return
}

vals := strings.SplitN(origValue,matches[1],int(n)+1)

if len(vals) >= int(n) {
newValue = []byte(strconv.Quote(vals[int(n)-1]))
}

}


return
}
38 changes: 38 additions & 0 deletions converter/splitn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package converter

import (
"github.com/mbordner/kazaam/registry"
"strconv"
"testing"
)

func TestSplitn_Convert(t *testing.T) {

registry.RegisterConverter("splitn", &Splitn{})
c := registry.GetConverter("splitn")

table := []struct {
value string
arguments string
expected string
}{
{`"aazbbzcczdd""`, `z 4`, `"dd"`,},
{`"abc|def|ghi|jkl|mno"`, `| 2`, `"def"`,},
{"\"abc\\ndef\\nghi\\njkl\\nmno\"", "\n 5", `"mno"`,},
}

for _, test := range table {
v, e := c.Convert(getTestData(), []byte(test.value), []byte(strconv.Quote(test.arguments)))

if e != nil {
t.Error("error running convert function")
}

if string(v) != test.expected {
t.Error("unexpected result from convert")
t.Log("Expected: {}", test.expected)
t.Log("Actual: {}", string(v))
}
}

}
Loading