From d757f0fb85fe571a32e790ac7671a190c9281992 Mon Sep 17 00:00:00 2001 From: Stepan Pyzhov Date: Tue, 22 Oct 2024 14:52:02 +0200 Subject: [PATCH 1/5] #67 Add `is_*type*` functions --- README.md | 11 ++++- cmd/ajson/main.go | 2 +- math.go | 114 ++++++++++++++++++++++++++++++++++++---------- math_test.go | 76 +++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 5f0adf0..496aab8 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ func main() { You can download `ajson` cli from the [release page](https://github.com/spyzhov/ajson/releases), or install from the source: ```shell script -go get github.com/spyzhov/ajson/cmd/ajson@v0.9.4 +go get github.com/spyzhov/ajson/cmd/ajson@v0.9.5 ``` Usage: @@ -321,6 +321,15 @@ Package has several predefined functions. first Get first element any floor math.Floor integers, floats gamma math.Gamma integers, floats + is_array Is type Array any + is_bool Is type Bool any + is_float Is type Float any + is_int Is type Int any + is_null Is type Null any + is_numeric Is type Numeric any + is_object Is type Object any + is_string Is type String any + is_uint Is type Uint any j0 math.J0 integers, floats j1 math.J1 integers, floats key Key of element string diff --git a/cmd/ajson/main.go b/cmd/ajson/main.go index a29f918..f99179e 100644 --- a/cmd/ajson/main.go +++ b/cmd/ajson/main.go @@ -13,7 +13,7 @@ import ( "github.com/spyzhov/ajson" ) -var version = "v0.9.4" +var version = "v0.9.5" func usage() { text := `` diff --git a/math.go b/math.go index 7087000..5dfa480 100644 --- a/math.go +++ b/math.go @@ -97,21 +97,21 @@ var ( "**": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _floats(left, right) if err != nil { - return + return nil, err } return valueNode(nil, "power", Numeric, math.Pow(lnum, rnum)), nil }, "*": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _floats(left, right) if err != nil { - return + return nil, err } return valueNode(nil, "multiply", Numeric, float64(lnum*rnum)), nil }, "/": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _floats(left, right) if err != nil { - return + return nil, err } if rnum == 0 { return nil, errorRequest("division by zero") @@ -121,47 +121,47 @@ var ( "%": func(left *Node, right *Node) (result *Node, err error) { lnum, err := left.getInteger() if err != nil { - return + return nil, err } rnum, err := right.getInteger() if err != nil { - return + return nil, err } return valueNode(nil, "remainder", Numeric, float64(lnum%rnum)), nil }, "<<": func(left *Node, right *Node) (result *Node, err error) { lnum, err := left.getInteger() if err != nil { - return + return nil, err } rnum, err := right.getUInteger() if err != nil { - return + return nil, err } return valueNode(nil, "left shift", Numeric, float64(lnum<>": func(left *Node, right *Node) (result *Node, err error) { lnum, err := left.getInteger() if err != nil { - return + return nil, err } rnum, err := right.getUInteger() if err != nil { - return + return nil, err } return valueNode(nil, "right shift", Numeric, float64(lnum>>rnum)), nil }, "&": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _ints(left, right) if err != nil { - return + return nil, err } return valueNode(nil, "bitwise AND", Numeric, float64(lnum&rnum)), nil }, "&^": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _ints(left, right) if err != nil { - return + return nil, err } return valueNode(nil, "bit clear (AND NOT)", Numeric, float64(lnum&^rnum)), nil }, @@ -182,14 +182,14 @@ var ( "-": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _floats(left, right) if err != nil { - return + return nil, err } return valueNode(nil, "sub", Numeric, float64(lnum-rnum)), nil }, "|": func(left *Node, right *Node) (result *Node, err error) { lnum, rnum, err := _ints(left, right) if err != nil { - return + return nil, err } return valueNode(nil, "bitwise OR", Numeric, float64(lnum|rnum)), nil }, @@ -355,7 +355,7 @@ var ( } num, err := node.getInteger() if err != nil { - return + return nil, err } return valueNode(nil, "Pow10", Numeric, float64(math.Pow10(num))), nil }, @@ -384,7 +384,7 @@ var ( } num, err := node.getUInteger() if err != nil { - return + return nil, err } return valueNode(nil, "factorial", Numeric, float64(mathFactorial(num))), nil }, @@ -445,9 +445,9 @@ var ( if remainder != 0 { size += 1 + remainder } - var result []byte = make([]byte, size) - base64.StdEncoding.WithPadding(base64.NoPadding).Encode(result, []byte(sourceString)) - return valueNode(nil, "b64encoden", String, string(result)), nil + var bytes = make([]byte, size) + base64.StdEncoding.WithPadding(base64.NoPadding).Encode(bytes, []byte(sourceString)) + return valueNode(nil, "b64encoden", String, string(bytes)), nil } } return valueNode(nil, "b64encoden", Null, nil), nil @@ -462,9 +462,9 @@ var ( if remainder != 0 { size += 4 } - var result []byte = make([]byte, size) - base64.StdEncoding.WithPadding(base64.StdPadding).Encode(result, []byte(sourceString)) - return valueNode(nil, "b64encode", String, string(result)), nil + var bytes = make([]byte, size) + base64.StdEncoding.WithPadding(base64.StdPadding).Encode(bytes, []byte(sourceString)) + return valueNode(nil, "b64encode", String, string(bytes)), nil } } return valueNode(nil, "b64encode", Null, nil), nil @@ -510,7 +510,7 @@ var ( } num, err := node.GetNumeric() if err != nil { - return + return nil, err } return valueNode(nil, "Rand", Numeric, randFunc()*num), nil }, @@ -520,7 +520,7 @@ var ( } num, err := node.getInteger() if err != nil { - return + return nil, err } return valueNode(nil, "RandInt", Numeric, float64(randIntFunc(num))), nil }, @@ -572,6 +572,74 @@ var ( } return valueNode(nil, "key", Null, nil), nil }, + "is_null": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_null", Null, nil), nil + } + return valueNode(nil, "is_null", Bool, node.IsNull()), nil + }, + "is_numeric": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_numeric", Null, nil), nil + } + return valueNode(nil, "is_numeric", Bool, node.IsNumeric()), nil + }, + "is_int": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_int", Null, nil), nil + } + _, err = node.getInteger() + if err != nil { + return valueNode(nil, "is_int", Bool, false), nil + } + return valueNode(nil, "is_int", Bool, true), nil + }, + "is_uint": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_uint", Null, nil), nil + } + _, err = node.getUInteger() + if err != nil { + return valueNode(nil, "is_uint", Bool, false), nil + } + return valueNode(nil, "is_uint", Bool, true), nil + }, + "is_float": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_float", Null, nil), nil + } + if node.IsNumeric() { + _, err = node.getInteger() + if err != nil { + return valueNode(nil, "is_float", Bool, true), nil + } + } + return valueNode(nil, "is_float", Bool, false), nil + }, + "is_string": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_string", Null, nil), nil + } + return valueNode(nil, "is_string", Bool, node.IsString()), nil + }, + "is_bool": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_bool", Null, nil), nil + } + return valueNode(nil, "is_bool", Bool, node.IsBool()), nil + }, + "is_array": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_array", Null, nil), nil + } + return valueNode(nil, "is_array", Bool, node.IsArray()), nil + }, + "is_object": func(node *Node) (result *Node, err error) { + if node == nil { + return valueNode(nil, "is_object", Null, nil), nil + } + return valueNode(nil, "is_object", Bool, node.IsObject()), nil + }, } constants = map[string]*Node{ diff --git a/math_test.go b/math_test.go index 73bf747..beee6e0 100644 --- a/math_test.go +++ b/math_test.go @@ -565,6 +565,82 @@ func TestFunctions2(t *testing.T) { {name: "key", fname: "key", value: key, result: StringNode("", "t"), fail: false}, {name: "key: none", fname: "key", value: StringNode("", "value"), result: NullNode(""), fail: false}, {name: "key nil", fname: "key", value: nil, result: NullNode("")}, + + {name: "is_null nil", fname: "is_null", value: nil, result: NullNode("")}, + {name: "is_null null", fname: "is_null", value: NullNode(""), result: BoolNode("", true)}, + {name: "is_null str", fname: "is_null", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_numeric nil", fname: "is_numeric", value: nil, result: NullNode("")}, + {name: "is_numeric null", fname: "is_numeric", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_numeric int", fname: "is_numeric", value: NumericNode("", -123), result: BoolNode("", true)}, + {name: "is_numeric uint", fname: "is_numeric", value: NumericNode("", 123), result: BoolNode("", true)}, + {name: "is_numeric float", fname: "is_numeric", value: NumericNode("", -12.34), result: BoolNode("", true)}, + {name: "is_numeric string", fname: "is_numeric", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_numeric bool", fname: "is_numeric", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_numeric array", fname: "is_numeric", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_numeric object", fname: "is_numeric", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_int nil", fname: "is_int", value: nil, result: NullNode("")}, + {name: "is_int null", fname: "is_int", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_int int", fname: "is_int", value: NumericNode("", -123), result: BoolNode("", true)}, + {name: "is_int uint", fname: "is_int", value: NumericNode("", 123), result: BoolNode("", true)}, + {name: "is_int float", fname: "is_int", value: NumericNode("", -12.34), result: BoolNode("", false)}, + {name: "is_int string", fname: "is_int", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_int bool", fname: "is_int", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_int array", fname: "is_int", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_int object", fname: "is_int", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_uint nil", fname: "is_uint", value: nil, result: NullNode("")}, + {name: "is_uint null", fname: "is_uint", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_uint int", fname: "is_uint", value: NumericNode("", -123), result: BoolNode("", false)}, + {name: "is_uint uint", fname: "is_uint", value: NumericNode("", 123), result: BoolNode("", true)}, + {name: "is_uint float", fname: "is_uint", value: NumericNode("", -12.34), result: BoolNode("", false)}, + {name: "is_uint string", fname: "is_uint", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_uint bool", fname: "is_uint", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_uint array", fname: "is_uint", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_uint object", fname: "is_uint", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_float nil", fname: "is_float", value: nil, result: NullNode("")}, + {name: "is_float null", fname: "is_float", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_float int", fname: "is_float", value: NumericNode("", -123), result: BoolNode("", false)}, + {name: "is_float uint", fname: "is_float", value: NumericNode("", 123), result: BoolNode("", false)}, + {name: "is_float float", fname: "is_float", value: NumericNode("", -12.34), result: BoolNode("", true)}, + {name: "is_float string", fname: "is_float", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_float bool", fname: "is_float", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_float array", fname: "is_float", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_float object", fname: "is_float", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_string nil", fname: "is_string", value: nil, result: NullNode("")}, + {name: "is_string null", fname: "is_string", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_string int", fname: "is_string", value: NumericNode("", -123), result: BoolNode("", false)}, + {name: "is_string uint", fname: "is_string", value: NumericNode("", 123), result: BoolNode("", false)}, + {name: "is_string float", fname: "is_string", value: NumericNode("", -12.34), result: BoolNode("", false)}, + {name: "is_string string", fname: "is_string", value: StringNode("", ""), result: BoolNode("", true)}, + {name: "is_string bool", fname: "is_string", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_string array", fname: "is_string", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_string object", fname: "is_string", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_bool nil", fname: "is_bool", value: nil, result: NullNode("")}, + {name: "is_bool null", fname: "is_bool", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_bool int", fname: "is_bool", value: NumericNode("", -123), result: BoolNode("", false)}, + {name: "is_bool uint", fname: "is_bool", value: NumericNode("", 123), result: BoolNode("", false)}, + {name: "is_bool float", fname: "is_bool", value: NumericNode("", -12.34), result: BoolNode("", false)}, + {name: "is_bool string", fname: "is_bool", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_bool bool", fname: "is_bool", value: BoolNode("", true), result: BoolNode("", true)}, + {name: "is_bool array", fname: "is_bool", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_bool object", fname: "is_bool", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_array nil", fname: "is_array", value: nil, result: NullNode("")}, + {name: "is_array null", fname: "is_array", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_array int", fname: "is_array", value: NumericNode("", -123), result: BoolNode("", false)}, + {name: "is_array uint", fname: "is_array", value: NumericNode("", 123), result: BoolNode("", false)}, + {name: "is_array float", fname: "is_array", value: NumericNode("", -12.34), result: BoolNode("", false)}, + {name: "is_array string", fname: "is_array", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_array bool", fname: "is_array", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_array array", fname: "is_array", value: ArrayNode("", nil), result: BoolNode("", true)}, + {name: "is_array object", fname: "is_array", value: ObjectNode("", nil), result: BoolNode("", false)}, + {name: "is_object nil", fname: "is_object", value: nil, result: NullNode("")}, + {name: "is_object null", fname: "is_object", value: NullNode(""), result: BoolNode("", false)}, + {name: "is_object int", fname: "is_object", value: NumericNode("", -123), result: BoolNode("", false)}, + {name: "is_object uint", fname: "is_object", value: NumericNode("", 123), result: BoolNode("", false)}, + {name: "is_object float", fname: "is_object", value: NumericNode("", -12.34), result: BoolNode("", false)}, + {name: "is_object string", fname: "is_object", value: StringNode("", ""), result: BoolNode("", false)}, + {name: "is_object bool", fname: "is_object", value: BoolNode("", true), result: BoolNode("", false)}, + {name: "is_object array", fname: "is_object", value: ArrayNode("", nil), result: BoolNode("", false)}, + {name: "is_object object", fname: "is_object", value: ObjectNode("", nil), result: BoolNode("", true)}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { From f01cdb269441a91f58f29750f3e36312ab459ef4 Mon Sep 17 00:00:00 2001 From: Stepan Pyzhov Date: Tue, 22 Oct 2024 14:55:06 +0200 Subject: [PATCH 2/5] Fix versions --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a709e9..5b228f9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,13 +20,13 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v3.7.0 with: - version: v1.56.2 + version: v1.61.1 args: -v test: strategy: matrix: - go-version: [ '1.16.x', '1.17.x', '1.18.x', '1.19.x', '1.20.x' , '1.21.x' , '1.22.x' ] + go-version: [ '1.16.x', '1.17.x', '1.18.x', '1.19.x', '1.20.x' , '1.21.x' , '1.22.x' , '1.23.x' ] os: [ ubuntu-latest, macos-latest ] runs-on: ${{ matrix.os }} steps: @@ -47,10 +47,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Setup Go 1.22.x on ubuntu-latest + - name: Setup Go 1.23.x on ubuntu-latest uses: actions/setup-go@v3 with: - go-version: '1.22.x' + go-version: '1.23.x' - name: Setup Dependencies run: | go get golang.org/x/tools/cmd/cover From ee8b903904876589dee928052387e9874aa81474 Mon Sep 17 00:00:00 2001 From: Stepan Pyzhov Date: Tue, 22 Oct 2024 14:56:45 +0200 Subject: [PATCH 3/5] Fix versions --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5b228f9..3778a3e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v3.7.0 + uses: golangci/golangci-lint-action@v6.1.1 with: version: v1.61.1 args: -v From 756e129949a407e05306df473e51925976ad296d Mon Sep 17 00:00:00 2001 From: Stepan Pyzhov Date: Tue, 22 Oct 2024 14:58:07 +0200 Subject: [PATCH 4/5] Fix versions --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3778a3e..4f3055b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v6.1.1 with: - version: v1.61.1 + version: v1.61.0 args: -v test: From 18b2be3214092b687a66c0541ee7bf7b9d9a3a75 Mon Sep 17 00:00:00 2001 From: Stepan Pyzhov Date: Tue, 22 Oct 2024 15:06:55 +0200 Subject: [PATCH 5/5] Fix overflow --- buffer.go | 24 ++++++++++++------------ node_test.go | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/buffer.go b/buffer.go index e332877..9fcad46 100644 --- a/buffer.go +++ b/buffer.go @@ -41,14 +41,14 @@ const ( asterisk byte = '*' plus byte = '+' minus byte = '-' - //division byte = '/' - //exclamation byte = '!' - //caret byte = '^' - //signL byte = '<' - //signG byte = '>' - //signE byte = '=' - //ampersand byte = '&' - //pipe byte = '|' + // division byte = '/' + // exclamation byte = '!' + // caret byte = '^' + // signL byte = '<' + // signG byte = '>' + // signE byte = '=' + // ampersand byte = '&' + // pipe byte = '|' question byte = '?' ) @@ -88,11 +88,11 @@ func (b *buffer) next() (c byte, err error) { return b.data[b.index], nil } -func (b *buffer) slice(delta uint) ([]byte, error) { - if b.index+int(delta) > b.length { +func (b *buffer) slice(delta int) ([]byte, error) { + if delta < 0 || b.index+delta > b.length { return nil, io.EOF } - return b.data[b.index : b.index+int(delta)], nil + return b.data[b.index : b.index+delta], nil } func (b *buffer) move(delta int) error { @@ -648,7 +648,7 @@ func (b *buffer) operation() string { // fixme: add additional order for comparison for _, operation := range comparisonOperationsOrder() { - if bytes, ok := b.slice(uint(len(operation))); ok == nil { + if bytes, ok := b.slice(len(operation)); ok == nil { if string(bytes) == operation { current = operation _ = b.move(len(operation) - 1) // error can't occupy here because of b.slice result diff --git a/node_test.go b/node_test.go index 6486b2d..3d1ebc1 100644 --- a/node_test.go +++ b/node_test.go @@ -117,7 +117,7 @@ func TestNode_getValue(t *testing.T) { keys := []string{"category", "author", "title", "price", "ordered", "tags", "sub"} for _, key := range keys { if _, ok := value[key]; !ok { - t.Errorf("Object map has no field: " + key) + t.Errorf("Object map has no field: %s", key) } } }