├── .codeclimate.yml
├── .github
├── CODE_OF_CONDUCT.md
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ └── go.yml
├── .gitignore
├── LICENSE
├── README.md
├── Taskfile.yml
├── accessors.go
├── accessors_test.go
├── codegen
├── array-access.txt
├── index.html
├── template.txt
├── template_test.txt
└── types_list.txt
├── conversions.go
├── conversions_test.go
├── doc.go
├── fixture_test.go
├── go.mod
├── go.sum
├── map.go
├── map_test.go
├── mutations.go
├── mutations_test.go
├── security.go
├── security_test.go
├── simple_example_test.go
├── tests.go
├── tests_test.go
├── type_specific.go
├── type_specific_codegen.go
├── type_specific_codegen_test.go
├── type_specific_test.go
├── value.go
└── value_test.go
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | gofmt:
3 | enabled: true
4 | golint:
5 | enabled: true
6 | govet:
7 | enabled: true
8 |
9 | exclude_patterns:
10 | - ".github/"
11 | - "vendor/"
12 | - "codegen/"
13 | - "*.yml"
14 | - ".*.yml"
15 | - "*.md"
16 | - "Gopkg.*"
17 | - "doc.go"
18 | - "type_specific_codegen_test.go"
19 | - "type_specific_codegen.go"
20 | - ".gitignore"
21 | - "LICENSE"
22 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hanzei@mailbox.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | #### Summary
4 |
5 |
6 | #### Checklist
7 | [Place an '[x]' (no spaces) in all applicable fields. Please remove unrelated fields.]
8 | - [ ] Tests are passing: `task test`
9 | - [ ] Code style is correct: `task lint`
10 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gomod
4 | directory: /
5 | schedule:
6 | interval: daily
7 | - package-ecosystem: github-actions
8 | directory: /
9 | schedule:
10 | interval: daily
11 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 |
11 | build:
12 | env:
13 | CC_TEST_REPORTER_ID: 68feaa3410049ce73e145287acbcdacc525087a30627f96f04e579e75bd71c00
14 | runs-on: ubuntu-latest
15 | strategy:
16 | matrix:
17 | go: [ '1.22', '1.21', '1.20' ]
18 | steps:
19 | - uses: actions/checkout@v4
20 |
21 | - name: Pre-run
22 | run: |
23 | curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
24 | chmod +x ./cc-test-reporter
25 | ./cc-test-reporter before-build
26 | curl -sL https://taskfile.dev/install.sh | sh
27 |
28 | - name: Set up Go
29 | uses: actions/setup-go@v5
30 | with:
31 | go-version: ${{ matrix.go }}
32 |
33 | - name: Setup go module cache
34 | uses: actions/cache@v4
35 | with:
36 | path: |
37 | ~/.cache/go-build
38 | ~/go/pkg/mod
39 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
40 | restore-keys: |
41 | ${{ runner.os }}-go-
42 |
43 | - name: Lint
44 | run: diff -u <(echo -n) <(./bin/task lint)
45 |
46 | - name: Test
47 | run: ./bin/task test-coverage
48 |
49 | - name: Post run
50 | run: ./cc-test-reporter after-build format-coverage -t gocov --prefix github.com/stretchr/objx .cover/c.out --exit-code $?
51 |
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.dll
4 | *.so
5 | *.dylib
6 |
7 | # Test binary, build with `go test -c`
8 | *.test
9 |
10 | # Output of the go coverage tool, specifically when used with LiteIDE
11 | *.out
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2014 Stretchr, Inc.
4 | Copyright (c) 2017-2018 objx contributors
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Objx
2 | [](https://travis-ci.org/stretchr/objx)
3 | [](https://goreportcard.com/report/github.com/stretchr/objx)
4 | [](https://codeclimate.com/github/stretchr/objx/maintainability)
5 | [](https://codeclimate.com/github/stretchr/objx/test_coverage)
6 | [](https://sourcegraph.com/github.com/stretchr/objx)
7 | [](https://pkg.go.dev/github.com/stretchr/objx)
8 |
9 | Objx - Go package for dealing with maps, slices, JSON and other data.
10 |
11 | Get started:
12 |
13 | - Install Objx with [one line of code](#installation), or [update it with another](#staying-up-to-date)
14 | - Check out the API Documentation http://pkg.go.dev/github.com/stretchr/objx
15 |
16 | ## Overview
17 | Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes a powerful `Get` method (among others) that allows you to easily and quickly get access to data within the map, without having to worry too much about type assertions, missing data, default values etc.
18 |
19 | ### Pattern
20 | Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy. Call one of the `objx.` functions to create your `objx.Map` to get going:
21 |
22 | ```go
23 | m, err := objx.FromJSON(json)
24 | ```
25 |
26 | NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong, the rest will be optimistic and try to figure things out without panicking.
27 |
28 | Use `Get` to access the value you're interested in. You can use dot and array
29 | notation too:
30 |
31 | ```go
32 | m.Get("places[0].latlng")
33 | ```
34 |
35 | Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
36 |
37 | ```go
38 | if m.Get("code").IsStr() { // Your code... }
39 | ```
40 |
41 | Or you can just assume the type, and use one of the strong type methods to extract the real value:
42 |
43 | ```go
44 | m.Get("code").Int()
45 | ```
46 |
47 | If there's no value there (or if it's the wrong type) then a default value will be returned, or you can be explicit about the default value.
48 |
49 | ```go
50 | Get("code").Int(-1)
51 | ```
52 | If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating, manipulating and selecting that data. You can find out more by exploring the index below.
53 |
54 | ### Reading data
55 | A simple example of how to use Objx:
56 |
57 | ```go
58 | // Use MustFromJSON to make an objx.Map from some JSON
59 | m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
60 |
61 | // Get the details
62 | name := m.Get("name").Str()
63 | age := m.Get("age").Int()
64 |
65 | // Get their nickname (or use their name if they don't have one)
66 | nickname := m.Get("nickname").Str(name)
67 | ```
68 |
69 | ### Ranging
70 | Since `objx.Map` is a `map[string]interface{}` you can treat it as such. For example, to `range` the data, do what you would expect:
71 |
72 | ```go
73 | m := objx.MustFromJSON(json)
74 | for key, value := range m {
75 | // Your code...
76 | }
77 | ```
78 |
79 | ## Installation
80 | To install Objx, use go get:
81 |
82 | go get github.com/stretchr/objx
83 |
84 | ### Staying up to date
85 | To update Objx to the latest version, run:
86 |
87 | go get -u github.com/stretchr/objx
88 |
89 | ### Supported go versions
90 | We currently support the three recent major Go versions.
91 |
92 | ## Contributing
93 | Please feel free to submit issues, fork the repository and send pull requests!
94 |
--------------------------------------------------------------------------------
/Taskfile.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | tasks:
4 | default:
5 | deps: [test]
6 |
7 | lint:
8 | desc: Checks code style
9 | cmds:
10 | - gofmt -d -s *.go
11 | - go vet ./...
12 | silent: true
13 |
14 | lint-fix:
15 | desc: Fixes code style
16 | cmds:
17 | - gofmt -w -s *.go
18 |
19 | test:
20 | desc: Runs go tests
21 | cmds:
22 | - go test -race ./...
23 |
24 | test-coverage:
25 | desc: Runs go tests and calculates test coverage
26 | cmds:
27 | - go test -race -coverprofile=c.out ./...
28 |
--------------------------------------------------------------------------------
/accessors.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | import (
4 | "reflect"
5 | "regexp"
6 | "strconv"
7 | "strings"
8 | )
9 |
10 | const (
11 | // PathSeparator is the character used to separate the elements
12 | // of the keypath.
13 | //
14 | // For example, `location.address.city`
15 | PathSeparator string = "."
16 |
17 | // arrayAccessRegexString is the regex used to extract the array number
18 | // from the access path
19 | arrayAccessRegexString = `^(.+)\[([0-9]+)\]$`
20 |
21 | // mapAccessRegexString is the regex used to extract the map key
22 | // from the access path
23 | mapAccessRegexString = `^([^\[]*)\[([^\]]+)\](.*)$`
24 | )
25 |
26 | // arrayAccessRegex is the compiled arrayAccessRegexString
27 | var arrayAccessRegex = regexp.MustCompile(arrayAccessRegexString)
28 |
29 | // mapAccessRegex is the compiled mapAccessRegexString
30 | var mapAccessRegex = regexp.MustCompile(mapAccessRegexString)
31 |
32 | // Get gets the value using the specified selector and
33 | // returns it inside a new Obj object.
34 | //
35 | // If it cannot find the value, Get will return a nil
36 | // value inside an instance of Obj.
37 | //
38 | // Get can only operate directly on map[string]interface{} and []interface.
39 | //
40 | // # Example
41 | //
42 | // To access the title of the third chapter of the second book, do:
43 | //
44 | // o.Get("books[1].chapters[2].title")
45 | func (m Map) Get(selector string) *Value {
46 | rawObj := access(m, selector, nil, false)
47 | return &Value{data: rawObj}
48 | }
49 |
50 | // Set sets the value using the specified selector and
51 | // returns the object on which Set was called.
52 | //
53 | // Set can only operate directly on map[string]interface{} and []interface
54 | //
55 | // # Example
56 | //
57 | // To set the title of the third chapter of the second book, do:
58 | //
59 | // o.Set("books[1].chapters[2].title","Time to Go")
60 | func (m Map) Set(selector string, value interface{}) Map {
61 | access(m, selector, value, true)
62 | return m
63 | }
64 |
65 | // getIndex returns the index, which is hold in s by two branches.
66 | // It also returns s without the index part, e.g. name[1] will return (1, name).
67 | // If no index is found, -1 is returned
68 | func getIndex(s string) (int, string) {
69 | arrayMatches := arrayAccessRegex.FindStringSubmatch(s)
70 | if len(arrayMatches) > 0 {
71 | // Get the key into the map
72 | selector := arrayMatches[1]
73 | // Get the index into the array at the key
74 | // We know this can't fail because arrayMatches[2] is an int for sure
75 | index, _ := strconv.Atoi(arrayMatches[2])
76 | return index, selector
77 | }
78 | return -1, s
79 | }
80 |
81 | // getKey returns the key which is held in s by two brackets.
82 | // It also returns the next selector.
83 | func getKey(s string) (string, string) {
84 | selSegs := strings.SplitN(s, PathSeparator, 2)
85 | thisSel := selSegs[0]
86 | nextSel := ""
87 |
88 | if len(selSegs) > 1 {
89 | nextSel = selSegs[1]
90 | }
91 |
92 | mapMatches := mapAccessRegex.FindStringSubmatch(s)
93 | if len(mapMatches) > 0 {
94 | if _, err := strconv.Atoi(mapMatches[2]); err != nil {
95 | thisSel = mapMatches[1]
96 | nextSel = "[" + mapMatches[2] + "]" + mapMatches[3]
97 |
98 | if thisSel == "" {
99 | thisSel = mapMatches[2]
100 | nextSel = mapMatches[3]
101 | }
102 |
103 | if nextSel == "" {
104 | selSegs = []string{"", ""}
105 | } else if nextSel[0] == '.' {
106 | nextSel = nextSel[1:]
107 | }
108 | }
109 | }
110 |
111 | return thisSel, nextSel
112 | }
113 |
114 | // access accesses the object using the selector and performs the
115 | // appropriate action.
116 | func access(current interface{}, selector string, value interface{}, isSet bool) interface{} {
117 | thisSel, nextSel := getKey(selector)
118 |
119 | indexes := []int{}
120 | for strings.Contains(thisSel, "[") {
121 | prevSel := thisSel
122 | index := -1
123 | index, thisSel = getIndex(thisSel)
124 | indexes = append(indexes, index)
125 | if prevSel == thisSel {
126 | break
127 | }
128 | }
129 |
130 | if curMap, ok := current.(Map); ok {
131 | current = map[string]interface{}(curMap)
132 | }
133 | // get the object in question
134 | switch current.(type) {
135 | case map[string]interface{}:
136 | curMSI := current.(map[string]interface{})
137 | if nextSel == "" && isSet {
138 | curMSI[thisSel] = value
139 | return nil
140 | }
141 |
142 | _, ok := curMSI[thisSel].(map[string]interface{})
143 | if !ok {
144 | _, ok = curMSI[thisSel].(Map)
145 | }
146 |
147 | if (curMSI[thisSel] == nil || !ok) && len(indexes) == 0 && isSet {
148 | curMSI[thisSel] = map[string]interface{}{}
149 | }
150 |
151 | current = curMSI[thisSel]
152 | default:
153 | current = nil
154 | }
155 |
156 | // do we need to access the item of an array?
157 | if len(indexes) > 0 {
158 | num := len(indexes)
159 | for num > 0 {
160 | num--
161 | index := indexes[num]
162 | indexes = indexes[:num]
163 | if array, ok := interSlice(current); ok {
164 | if index < len(array) {
165 | current = array[index]
166 | } else {
167 | current = nil
168 | break
169 | }
170 | }
171 | }
172 | }
173 |
174 | if nextSel != "" {
175 | current = access(current, nextSel, value, isSet)
176 | }
177 | return current
178 | }
179 |
180 | func interSlice(slice interface{}) ([]interface{}, bool) {
181 | if array, ok := slice.([]interface{}); ok {
182 | return array, ok
183 | }
184 |
185 | s := reflect.ValueOf(slice)
186 | if s.Kind() != reflect.Slice {
187 | return nil, false
188 | }
189 |
190 | ret := make([]interface{}, s.Len())
191 |
192 | for i := 0; i < s.Len(); i++ {
193 | ret[i] = s.Index(i).Interface()
194 | }
195 |
196 | return ret, true
197 | }
198 |
--------------------------------------------------------------------------------
/accessors_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestAccessorsAccessGetSingleField(t *testing.T) {
11 | m := objx.Map{"name": "Tyler"}
12 |
13 | assert.Equal(t, "Tyler", m.Get("name").Data())
14 | }
15 |
16 | func TestAccessorsAccessGetSingleFieldInt(t *testing.T) {
17 | m := objx.Map{"name": 10}
18 |
19 | assert.Equal(t, 10, m.Get("name").Data())
20 | }
21 |
22 | func TestAccessorsAccessGetDeep(t *testing.T) {
23 | m := objx.Map{
24 | "name": objx.Map{
25 | "first": "Tyler",
26 | "last": "Bunnell",
27 | "friends": []string{
28 | "Capitol",
29 | "Bollocks",
30 | },
31 | "ifriends": []interface{}{
32 | "Capitol",
33 | "Bollocks",
34 | },
35 | },
36 | }
37 |
38 | assert.Equal(t, "Tyler", m.Get("name.first").Data())
39 | assert.Equal(t, "Bunnell", m.Get("name.last").Data())
40 | assert.Equal(t, "Capitol", m.Get("name.friends[0]").Data())
41 | assert.Equal(t, "Capitol", m.Get("name.ifriends[0]").Data())
42 | }
43 |
44 | func TestAccessorsAccessGetDeepDeep(t *testing.T) {
45 | m := objx.Map{
46 | "one": objx.Map{
47 | "two": objx.Map{
48 | "three": objx.Map{
49 | "four": 4,
50 | },
51 | },
52 | },
53 | }
54 |
55 | assert.Equal(t, 4, m.Get("one.two.three.four").Data())
56 | assert.Equal(t, 4, m.Get("one[two][three][four]").Data())
57 | }
58 |
59 | func TestAccessorsGetWithComplexKey(t *testing.T) {
60 | m := objx.Map{
61 | "domains": objx.Map{
62 | "example-dot-com": objx.Map{
63 | "apex": "example",
64 | },
65 | "example.com": objx.Map{
66 | "apex": "example",
67 | },
68 | },
69 | }
70 |
71 | assert.Equal(t, "example", m.Get("domains.example-dot-com.apex").Data())
72 |
73 | assert.Equal(t, "example", m.Get("domains[example.com].apex").Data())
74 | assert.Equal(t, "example", m.Get("domains[example.com][apex]").Data())
75 | }
76 |
77 | func TestAccessorsAccessGetInsideArray(t *testing.T) {
78 | m := objx.Map{
79 | "names": []interface{}{
80 | objx.Map{
81 | "first": "Tyler",
82 | "last": "Bunnell",
83 | },
84 | objx.Map{
85 | "first": "Capitol",
86 | "last": "Bollocks",
87 | },
88 | },
89 | }
90 |
91 | assert.Equal(t, "Tyler", m.Get("names[0].first").Data())
92 | assert.Equal(t, "Bunnell", m.Get("names[0].last").Data())
93 | assert.Equal(t, "Capitol", m.Get("names[1].first").Data())
94 | assert.Equal(t, "Bollocks", m.Get("names[1].last").Data())
95 |
96 | assert.Nil(t, m.Get("names[2]").Data())
97 | assert.Nil(t, m.Get("names[]").Data())
98 | assert.Nil(t, m.Get("names1]]").Data())
99 | assert.Nil(t, m.Get("names[1]]").Data())
100 | assert.Nil(t, m.Get("names[[1]]").Data())
101 | assert.Nil(t, m.Get("names[[1]").Data())
102 | assert.Nil(t, m.Get("names[[1").Data())
103 | }
104 |
105 | func TestAccessorsGet(t *testing.T) {
106 | m := objx.Map{"name": "Tyler"}
107 |
108 | assert.Equal(t, "Tyler", m.Get("name").Data())
109 | }
110 |
111 | func TestAccessorsAccessSetSingleField(t *testing.T) {
112 | m := objx.Map{"name": "Tyler"}
113 |
114 | m.Set("name", "Mat")
115 | m.Set("age", 29)
116 |
117 | assert.Equal(t, m.Get("name").Data(), "Mat")
118 | assert.Equal(t, m.Get("age").Data(), 29)
119 | }
120 |
121 | func TestAccessorsAccessSetSingleFieldNotExisting(t *testing.T) {
122 | m := objx.Map{
123 | "first": "Tyler",
124 | "last": "Bunnell",
125 | }
126 |
127 | m.Set("name", "Mat")
128 |
129 | assert.Equal(t, m.Get("name").Data(), "Mat")
130 | }
131 |
132 | func TestAccessorsAccessSetDeep(t *testing.T) {
133 | m := objx.Map{
134 | "name": objx.Map{
135 | "first": "Tyler",
136 | "last": "Bunnell",
137 | },
138 | }
139 |
140 | m.Set("name.first", "Mat")
141 | m.Set("name.last", "Ryer")
142 |
143 | assert.Equal(t, "Mat", m.Get("name.first").Data())
144 | assert.Equal(t, "Ryer", m.Get("name.last").Data())
145 | }
146 |
147 | func TestAccessorsAccessSetDeepDeep(t *testing.T) {
148 | m := objx.Map{
149 | "one": objx.Map{
150 | "two": objx.Map{
151 | "three": objx.Map{
152 | "four": 4,
153 | },
154 | },
155 | },
156 | }
157 |
158 | m.Set("one.two.three.four", 5)
159 |
160 | assert.Equal(t, 5, m.Get("one.two.three.four").Data())
161 | }
162 |
163 | func TestAccessorsAccessSetDeepDeepWithoutExisting(t *testing.T) {
164 | m := objx.Map{}
165 |
166 | m.Set("one.two.three.four", 5)
167 | m.Set("one.two.three.five", 6)
168 |
169 | assert.Equal(t, 5, m.Get("one.two.three.four").Data())
170 | assert.Equal(t, 6, m.Get("one.two.three.five").Data())
171 |
172 | m.Set("one.two", 7)
173 | assert.Equal(t, 7, m.Get("one.two").Data())
174 | assert.Equal(t, nil, m.Get("one.two.three.four").Data())
175 |
176 | m.Set("one.two.three", 8)
177 | assert.Equal(t, 8, m.Get("one.two.three").Data())
178 | }
179 |
180 | func TestAccessorsAccessSetArray(t *testing.T) {
181 | m := objx.Map{
182 | "names": []interface{}{"Tyler"},
183 | }
184 | m.Set("names[0]", "Mat")
185 |
186 | assert.Equal(t, "Mat", m.Get("names[0]").Data())
187 | }
188 |
189 | func TestAccessorsAccessSetInsideArray(t *testing.T) {
190 | m := objx.Map{
191 | "names": []interface{}{
192 | objx.Map{
193 | "first": "Tyler",
194 | "last": "Bunnell",
195 | },
196 | objx.Map{
197 | "first": "Capitol",
198 | "last": "Bollocks",
199 | },
200 | },
201 | }
202 |
203 | m.Set("names[0].first", "Mat")
204 | m.Set("names[0].last", "Ryer")
205 | m.Set("names[1].first", "Captain")
206 | m.Set("names[1].last", "Underpants")
207 |
208 | assert.Equal(t, "Mat", m.Get("names[0].first").Data())
209 | assert.Equal(t, "Ryer", m.Get("names[0].last").Data())
210 | assert.Equal(t, "Captain", m.Get("names[1].first").Data())
211 | assert.Equal(t, "Underpants", m.Get("names[1].last").Data())
212 | }
213 |
214 | func TestAccessorsSet(t *testing.T) {
215 | m := objx.Map{"name": "Tyler"}
216 |
217 | m.Set("name", "Mat")
218 |
219 | assert.Equal(t, "Mat", m.Get("name").Data())
220 | }
221 |
222 | func TestAccessorsSetWithinObjxMapChild(t *testing.T) {
223 | m, err := objx.FromJSON(`{"a": {"b": 1}}`)
224 | assert.NoError(t, err)
225 |
226 | m.Set("a.c", 2)
227 | jsonConverted, err := m.JSON()
228 | assert.NoError(t, err)
229 |
230 | m = objx.New(map[string]interface{}{
231 | "a": map[string]interface{}{
232 | "b": 1,
233 | },
234 | })
235 | m.Set("a.c", 2)
236 | jsonNewObj, err := m.JSON()
237 |
238 | assert.NoError(t, err)
239 | assert.Equal(t, jsonConverted, jsonNewObj)
240 | }
241 |
242 | func TestAccessorsNested(t *testing.T) {
243 | d := objx.MustFromJSON(`{"values":[["test", "test1"], ["test2", {"name":"Mat"}, {"names": ["Captain", "Mat"]}]]}`)
244 |
245 | value := d.Get("values[0][0]").String()
246 | assert.Equal(t, "test", value)
247 |
248 | value = d.Get("values[0][1]").String()
249 | assert.Equal(t, "test1", value)
250 |
251 | value = d.Get("values[1][0]").String()
252 | assert.Equal(t, "test2", value)
253 |
254 | value = d.Get("values[1][1].name").String()
255 | assert.Equal(t, "Mat", value)
256 |
257 | value = d.Get("values[1][2].names[0]").String()
258 | assert.Equal(t, "Captain", value)
259 | }
260 |
--------------------------------------------------------------------------------
/codegen/array-access.txt:
--------------------------------------------------------------------------------
1 | case []{1}:
2 | a := object.([]{1})
3 | if isSet {
4 | a[index] = value.({1})
5 | } else {
6 | if index >= len(a) {
7 | if panics {
8 | panic(fmt.Sprintf("objx: Index %d is out of range because the []{1} only contains %d items.", index, len(a)))
9 | }
10 | return nil
11 | } else {
12 | return a[index]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/codegen/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Codegen
5 |
6 |
17 |
18 |
19 |
20 |
21 | Template
22 |
23 |
24 | Use {x}
as a placeholder for each argument.
25 |
26 |
27 |
28 |
29 | Arguments (comma separated)
30 |
31 |
32 | One block per line
33 |
34 |
35 |
36 |
37 | Output
38 |
39 |
40 |
41 |
42 |
43 |
44 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/codegen/template.txt:
--------------------------------------------------------------------------------
1 | /*
2 | {4} ({1} and []{1})
3 | */
4 |
5 | // {4} gets the value as a {1}, returns the optionalDefault
6 | // value or a system default object if the value is the wrong type.
7 | func (v *Value) {4}(optionalDefault ...{1}) {1} {
8 | if s, ok := v.data.({1}); ok {
9 | return s
10 | }
11 | if len(optionalDefault) == 1 {
12 | return optionalDefault[0]
13 | }
14 | return {3}
15 | }
16 |
17 | // Must{4} gets the value as a {1}.
18 | //
19 | // Panics if the object is not a {1}.
20 | func (v *Value) Must{4}() {1} {
21 | return v.data.({1})
22 | }
23 |
24 | // {4}Slice gets the value as a []{1}, returns the optionalDefault
25 | // value or nil if the value is not a []{1}.
26 | func (v *Value) {4}Slice(optionalDefault ...[]{1}) []{1} {
27 | if s, ok := v.data.([]{1}); ok {
28 | return s
29 | }
30 | if len(optionalDefault) == 1 {
31 | return optionalDefault[0]
32 | }
33 | return nil
34 | }
35 |
36 | // Must{4}Slice gets the value as a []{1}.
37 | //
38 | // Panics if the object is not a []{1}.
39 | func (v *Value) Must{4}Slice() []{1} {
40 | return v.data.([]{1})
41 | }
42 |
43 | // Is{4} gets whether the object contained is a {1} or not.
44 | func (v *Value) Is{4}() bool {
45 | _, ok := v.data.({1})
46 | return ok
47 | }
48 |
49 | // Is{4}Slice gets whether the object contained is a []{1} or not.
50 | func (v *Value) Is{4}Slice() bool {
51 | _, ok := v.data.([]{1})
52 | return ok
53 | }
54 |
55 | // Each{4} calls the specified callback for each object
56 | // in the []{1}.
57 | //
58 | // Panics if the object is the wrong type.
59 | func (v *Value) Each{4}(callback func(int, {1}) bool) *Value {
60 | for index, val := range v.Must{4}Slice() {
61 | carryon := callback(index, val)
62 | if !carryon {
63 | break
64 | }
65 | }
66 | return v
67 | }
68 |
69 | // Where{4} uses the specified decider function to select items
70 | // from the []{1}. The object contained in the result will contain
71 | // only the selected items.
72 | func (v *Value) Where{4}(decider func(int, {1}) bool) *Value {
73 | var selected []{1}
74 | v.Each{4}(func(index int, val {1}) bool {
75 | shouldSelect := decider(index, val)
76 | if !shouldSelect {
77 | selected = append(selected, val)
78 | }
79 | return true
80 | })
81 | return &Value{data:selected}
82 | }
83 |
84 | // Group{4} uses the specified grouper function to group the items
85 | // keyed by the return of the grouper. The object contained in the
86 | // result will contain a map[string][]{1}.
87 | func (v *Value) Group{4}(grouper func(int, {1}) string) *Value {
88 | groups := make(map[string][]{1})
89 | v.Each{4}(func(index int, val {1}) bool {
90 | group := grouper(index, val)
91 | if _, ok := groups[group]; !ok {
92 | groups[group] = make([]{1}, 0)
93 | }
94 | groups[group] = append(groups[group], val)
95 | return true
96 | })
97 | return &Value{data:groups}
98 | }
99 |
100 | // Replace{4} uses the specified function to replace each {1}s
101 | // by iterating each item. The data in the returned result will be a
102 | // []{1} containing the replaced items.
103 | func (v *Value) Replace{4}(replacer func(int, {1}) {1}) *Value {
104 | arr := v.Must{4}Slice()
105 | replaced := make([]{1}, len(arr))
106 | v.Each{4}(func(index int, val {1}) bool {
107 | replaced[index] = replacer(index, val)
108 | return true
109 | })
110 | return &Value{data:replaced}
111 | }
112 |
113 | // Collect{4} uses the specified collector function to collect a value
114 | // for each of the {1}s in the slice. The data returned will be a
115 | // []interface{}.
116 | func (v *Value) Collect{4}(collector func(int, {1}) interface{}) *Value {
117 | arr := v.Must{4}Slice()
118 | collected := make([]interface{}, len(arr))
119 | v.Each{4}(func(index int, val {1}) bool {
120 | collected[index] = collector(index, val)
121 | return true
122 | })
123 | return &Value{data:collected}
124 | }
125 |
--------------------------------------------------------------------------------
/codegen/template_test.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Tests for {4} ({1} and []{1})
3 | */
4 | func Test{4}(t *testing.T) {
5 | val := {1}({2})
6 | m := objx.Map{"value": val, "nothing": nil}
7 |
8 | assert.Equal(t, val, m.Get("value").{4}())
9 | assert.Equal(t, val, m.Get("value").Must{4}())
10 | assert.Equal(t, {1}({3}), m.Get("nothing").{4}())
11 | assert.Equal(t, val, m.Get("nothing").{4}({2}))
12 | assert.Panics(t, func() {
13 | m.Get("age").Must{4}()
14 | })
15 | }
16 |
17 | func Test{4}Slice(t *testing.T) {
18 | val := {1}({2})
19 | m := objx.Map{"value": []{1}{ val }, "nothing": nil}
20 |
21 | assert.Equal(t, val, m.Get("value").{4}Slice()[0])
22 | assert.Equal(t, val, m.Get("value").Must{4}Slice()[0])
23 | assert.Equal(t, []{1}(nil), m.Get("nothing").{4}Slice())
24 | assert.Equal(t, val, m.Get("nothing").{4}Slice([]{1}{{1}({2})})[0])
25 | assert.Panics(t, func() {
26 | m.Get("nothing").Must{4}Slice()
27 | })
28 | }
29 |
30 | func TestIs{4}(t *testing.T) {
31 | m := objx.Map{"data": {1}({2})}
32 |
33 | assert.True(t, m.Get("data").Is{4}())
34 | }
35 |
36 | func TestIs{4}Slice(t *testing.T) {
37 | m := objx.Map{"data": []{1}{{1}({2})}}
38 |
39 | assert.True(t, m.Get("data").Is{4}Slice())
40 | }
41 |
42 | func TestEach{4}(t *testing.T) {
43 | m := objx.Map{"data": []{1}{{1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2})}}
44 | count := 0
45 | replacedVals := make([]{1}, 0)
46 | assert.Equal(t, m.Get("data"), m.Get("data").Each{4}(func(i int, val {1}) bool {
47 | count++
48 | replacedVals = append(replacedVals, val)
49 |
50 | // abort early
51 | return i != 2
52 | }))
53 |
54 | assert.Equal(t, count, 3)
55 | assert.Equal(t, replacedVals[0], m.Get("data").Must{4}Slice()[0])
56 | assert.Equal(t, replacedVals[1], m.Get("data").Must{4}Slice()[1])
57 | assert.Equal(t, replacedVals[2], m.Get("data").Must{4}Slice()[2])
58 | }
59 |
60 | func TestWhere{4}(t *testing.T) {
61 | m := objx.Map{"data": []{1}{{1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2})}}
62 |
63 | selected := m.Get("data").Where{4}(func(i int, val {1}) bool {
64 | return i%2 == 0
65 | }).Must{4}Slice()
66 |
67 | assert.Equal(t, 3, len(selected))
68 | }
69 |
70 | func TestGroup{4}(t *testing.T) {
71 | m := objx.Map{"data": []{1}{{1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2})}}
72 |
73 | grouped := m.Get("data").Group{4}(func(i int, val {1}) string {
74 | return fmt.Sprintf("%v", i%2==0)
75 | }).Data().(map[string][]{1})
76 |
77 | assert.Equal(t, 2, len(grouped))
78 | assert.Equal(t, 3, len(grouped["true"]))
79 | assert.Equal(t, 3, len(grouped["false"]))
80 | }
81 |
82 | func TestReplace{4}(t *testing.T) {
83 | m := objx.Map{"data": []{1}{{1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2})}}
84 | rawArr := m.Get("data").Must{4}Slice()
85 |
86 | replaced := m.Get("data").Replace{4}(func(index int, val {1}) {1} {
87 | if index < len(rawArr)-1 {
88 | return rawArr[index+1]
89 | }
90 | return rawArr[0]
91 | })
92 | replacedArr := replaced.Must{4}Slice()
93 |
94 | if assert.Equal(t, 6, len(replacedArr)) {
95 | assert.Equal(t, replacedArr[0], rawArr[1])
96 | assert.Equal(t, replacedArr[1], rawArr[2])
97 | assert.Equal(t, replacedArr[2], rawArr[3])
98 | assert.Equal(t, replacedArr[3], rawArr[4])
99 | assert.Equal(t, replacedArr[4], rawArr[5])
100 | assert.Equal(t, replacedArr[5], rawArr[0])
101 | }
102 | }
103 |
104 | func TestCollect{4}(t *testing.T) {
105 | m := objx.Map{"data": []{1}{{1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2}), {1}({2})}}
106 |
107 | collected := m.Get("data").Collect{4}(func(index int, val {1}) interface{} {
108 | return index
109 | })
110 | collectedArr := collected.MustInterSlice()
111 |
112 | if assert.Equal(t, 6, len(collectedArr)) {
113 | assert.Equal(t, collectedArr[0], 0)
114 | assert.Equal(t, collectedArr[1], 1)
115 | assert.Equal(t, collectedArr[2], 2)
116 | assert.Equal(t, collectedArr[3], 3)
117 | assert.Equal(t, collectedArr[4], 4)
118 | assert.Equal(t, collectedArr[5], 5)
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/codegen/types_list.txt:
--------------------------------------------------------------------------------
1 | Interface,interface{},"something",nil,Inter
2 | ObjxMap,(objx.Map),objx.New(1),objx.New(nil),ObjxMap
3 | Bool,bool,true,false,Bool
4 | String,string,"hello","",Str
5 | Int,int,1,0,Int
6 | Int8,int8,1,0,Int8
7 | Int16,int16,1,0,Int16
8 | Int32,int32,1,0,Int32
9 | Int64,int64,1,0,Int64
10 | Uint,uint,1,0,Uint
11 | Uint8,uint8,1,0,Uint8
12 | Uint16,uint16,1,0,Uint16
13 | Uint32,uint32,1,0,Uint32
14 | Uint64,uint64,1,0,Uint64
15 | Uintptr,uintptr,1,0,Uintptr
16 | Float32,float32,1,0,Float32
17 | Float64,float64,1,0,Float64
18 | Complex64,complex64,1,0,Complex64
19 | Complex128,complex128,1,0,Complex128
20 |
--------------------------------------------------------------------------------
/conversions.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | import (
4 | "bytes"
5 | "encoding/base64"
6 | "encoding/json"
7 | "errors"
8 | "fmt"
9 | "net/url"
10 | "strconv"
11 | )
12 |
13 | // SignatureSeparator is the character that is used to
14 | // separate the Base64 string from the security signature.
15 | const SignatureSeparator = "_"
16 |
17 | // URLValuesSliceKeySuffix is the character that is used to
18 | // specify a suffix for slices parsed by URLValues.
19 | // If the suffix is set to "[i]", then the index of the slice
20 | // is used in place of i
21 | // Ex: Suffix "[]" would have the form a[]=b&a[]=c
22 | // OR Suffix "[i]" would have the form a[0]=b&a[1]=c
23 | // OR Suffix "" would have the form a=b&a=c
24 | var urlValuesSliceKeySuffix = "[]"
25 |
26 | const (
27 | URLValuesSliceKeySuffixEmpty = ""
28 | URLValuesSliceKeySuffixArray = "[]"
29 | URLValuesSliceKeySuffixIndex = "[i]"
30 | )
31 |
32 | // SetURLValuesSliceKeySuffix sets the character that is used to
33 | // specify a suffix for slices parsed by URLValues.
34 | // If the suffix is set to "[i]", then the index of the slice
35 | // is used in place of i
36 | // Ex: Suffix "[]" would have the form a[]=b&a[]=c
37 | // OR Suffix "[i]" would have the form a[0]=b&a[1]=c
38 | // OR Suffix "" would have the form a=b&a=c
39 | func SetURLValuesSliceKeySuffix(s string) error {
40 | if s == URLValuesSliceKeySuffixEmpty || s == URLValuesSliceKeySuffixArray || s == URLValuesSliceKeySuffixIndex {
41 | urlValuesSliceKeySuffix = s
42 | return nil
43 | }
44 |
45 | return errors.New("objx: Invalid URLValuesSliceKeySuffix provided.")
46 | }
47 |
48 | // JSON converts the contained object to a JSON string
49 | // representation
50 | func (m Map) JSON() (string, error) {
51 | for k, v := range m {
52 | m[k] = cleanUp(v)
53 | }
54 |
55 | result, err := json.Marshal(m)
56 | if err != nil {
57 | err = errors.New("objx: JSON encode failed with: " + err.Error())
58 | }
59 | return string(result), err
60 | }
61 |
62 | func cleanUpInterfaceArray(in []interface{}) []interface{} {
63 | result := make([]interface{}, len(in))
64 | for i, v := range in {
65 | result[i] = cleanUp(v)
66 | }
67 | return result
68 | }
69 |
70 | func cleanUpInterfaceMap(in map[interface{}]interface{}) Map {
71 | result := Map{}
72 | for k, v := range in {
73 | result[fmt.Sprintf("%v", k)] = cleanUp(v)
74 | }
75 | return result
76 | }
77 |
78 | func cleanUpStringMap(in map[string]interface{}) Map {
79 | result := Map{}
80 | for k, v := range in {
81 | result[k] = cleanUp(v)
82 | }
83 | return result
84 | }
85 |
86 | func cleanUpMSIArray(in []map[string]interface{}) []Map {
87 | result := make([]Map, len(in))
88 | for i, v := range in {
89 | result[i] = cleanUpStringMap(v)
90 | }
91 | return result
92 | }
93 |
94 | func cleanUpMapArray(in []Map) []Map {
95 | result := make([]Map, len(in))
96 | for i, v := range in {
97 | result[i] = cleanUpStringMap(v)
98 | }
99 | return result
100 | }
101 |
102 | func cleanUp(v interface{}) interface{} {
103 | switch v := v.(type) {
104 | case []interface{}:
105 | return cleanUpInterfaceArray(v)
106 | case []map[string]interface{}:
107 | return cleanUpMSIArray(v)
108 | case map[interface{}]interface{}:
109 | return cleanUpInterfaceMap(v)
110 | case Map:
111 | return cleanUpStringMap(v)
112 | case []Map:
113 | return cleanUpMapArray(v)
114 | default:
115 | return v
116 | }
117 | }
118 |
119 | // MustJSON converts the contained object to a JSON string
120 | // representation and panics if there is an error
121 | func (m Map) MustJSON() string {
122 | result, err := m.JSON()
123 | if err != nil {
124 | panic(err.Error())
125 | }
126 | return result
127 | }
128 |
129 | // Base64 converts the contained object to a Base64 string
130 | // representation of the JSON string representation
131 | func (m Map) Base64() (string, error) {
132 | var buf bytes.Buffer
133 |
134 | jsonData, err := m.JSON()
135 | if err != nil {
136 | return "", err
137 | }
138 |
139 | encoder := base64.NewEncoder(base64.StdEncoding, &buf)
140 | _, _ = encoder.Write([]byte(jsonData))
141 | _ = encoder.Close()
142 |
143 | return buf.String(), nil
144 | }
145 |
146 | // MustBase64 converts the contained object to a Base64 string
147 | // representation of the JSON string representation and panics
148 | // if there is an error
149 | func (m Map) MustBase64() string {
150 | result, err := m.Base64()
151 | if err != nil {
152 | panic(err.Error())
153 | }
154 | return result
155 | }
156 |
157 | // SignedBase64 converts the contained object to a Base64 string
158 | // representation of the JSON string representation and signs it
159 | // using the provided key.
160 | func (m Map) SignedBase64(key string) (string, error) {
161 | base64, err := m.Base64()
162 | if err != nil {
163 | return "", err
164 | }
165 |
166 | sig := HashWithKey(base64, key)
167 | return base64 + SignatureSeparator + sig, nil
168 | }
169 |
170 | // MustSignedBase64 converts the contained object to a Base64 string
171 | // representation of the JSON string representation and signs it
172 | // using the provided key and panics if there is an error
173 | func (m Map) MustSignedBase64(key string) string {
174 | result, err := m.SignedBase64(key)
175 | if err != nil {
176 | panic(err.Error())
177 | }
178 | return result
179 | }
180 |
181 | /*
182 | URL Query
183 | ------------------------------------------------
184 | */
185 |
186 | // URLValues creates a url.Values object from an Obj. This
187 | // function requires that the wrapped object be a map[string]interface{}
188 | func (m Map) URLValues() url.Values {
189 | vals := make(url.Values)
190 |
191 | m.parseURLValues(m, vals, "")
192 |
193 | return vals
194 | }
195 |
196 | func (m Map) parseURLValues(queryMap Map, vals url.Values, key string) {
197 | useSliceIndex := false
198 | if urlValuesSliceKeySuffix == "[i]" {
199 | useSliceIndex = true
200 | }
201 |
202 | for k, v := range queryMap {
203 | val := &Value{data: v}
204 | switch {
205 | case val.IsObjxMap():
206 | if key == "" {
207 | m.parseURLValues(val.ObjxMap(), vals, k)
208 | } else {
209 | m.parseURLValues(val.ObjxMap(), vals, key+"["+k+"]")
210 | }
211 | case val.IsObjxMapSlice():
212 | sliceKey := k
213 | if key != "" {
214 | sliceKey = key + "[" + k + "]"
215 | }
216 |
217 | if useSliceIndex {
218 | for i, sv := range val.MustObjxMapSlice() {
219 | sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
220 | m.parseURLValues(sv, vals, sk)
221 | }
222 | } else {
223 | sliceKey = sliceKey + urlValuesSliceKeySuffix
224 | for _, sv := range val.MustObjxMapSlice() {
225 | m.parseURLValues(sv, vals, sliceKey)
226 | }
227 | }
228 | case val.IsMSISlice():
229 | sliceKey := k
230 | if key != "" {
231 | sliceKey = key + "[" + k + "]"
232 | }
233 |
234 | if useSliceIndex {
235 | for i, sv := range val.MustMSISlice() {
236 | sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
237 | m.parseURLValues(New(sv), vals, sk)
238 | }
239 | } else {
240 | sliceKey = sliceKey + urlValuesSliceKeySuffix
241 | for _, sv := range val.MustMSISlice() {
242 | m.parseURLValues(New(sv), vals, sliceKey)
243 | }
244 | }
245 | case val.IsStrSlice(), val.IsBoolSlice(),
246 | val.IsFloat32Slice(), val.IsFloat64Slice(),
247 | val.IsIntSlice(), val.IsInt8Slice(), val.IsInt16Slice(), val.IsInt32Slice(), val.IsInt64Slice(),
248 | val.IsUintSlice(), val.IsUint8Slice(), val.IsUint16Slice(), val.IsUint32Slice(), val.IsUint64Slice():
249 |
250 | sliceKey := k
251 | if key != "" {
252 | sliceKey = key + "[" + k + "]"
253 | }
254 |
255 | if useSliceIndex {
256 | for i, sv := range val.StringSlice() {
257 | sk := sliceKey + "[" + strconv.FormatInt(int64(i), 10) + "]"
258 | vals.Set(sk, sv)
259 | }
260 | } else {
261 | sliceKey = sliceKey + urlValuesSliceKeySuffix
262 | vals[sliceKey] = val.StringSlice()
263 | }
264 |
265 | default:
266 | if key == "" {
267 | vals.Set(k, val.String())
268 | } else {
269 | vals.Set(key+"["+k+"]", val.String())
270 | }
271 | }
272 | }
273 | }
274 |
275 | // URLQuery gets an encoded URL query representing the given
276 | // Obj. This function requires that the wrapped object be a
277 | // map[string]interface{}
278 | func (m Map) URLQuery() (string, error) {
279 | return m.URLValues().Encode(), nil
280 | }
281 |
--------------------------------------------------------------------------------
/conversions_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "net/url"
5 | "testing"
6 |
7 | "github.com/stretchr/objx"
8 | "github.com/stretchr/testify/assert"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestConversionJSON(t *testing.T) {
13 | jsonString := `{"name":"Mat"}`
14 | o := objx.MustFromJSON(jsonString)
15 |
16 | result, err := o.JSON()
17 |
18 | require.NoError(t, err)
19 | assert.Equal(t, jsonString, result)
20 | assert.Equal(t, jsonString, o.MustJSON())
21 |
22 | i := objx.Map{
23 | "a": map[interface{}]interface{}{"b": objx.Map{"c": map[interface{}]interface{}{"d": "e"}},
24 | "f": []objx.Map{{"g": map[interface{}]interface{}{"h": "i"}}},
25 | "j": []map[string]interface{}{{"k": map[interface{}]interface{}{"l": "m"}}},
26 | "n": []interface{}{objx.Map{"o": "p"}},
27 | },
28 | }
29 |
30 | jsonString = `{"a":{"b":{"c":{"d":"e"}},"f":[{"g":{"h":"i"}}],"j":[{"k":{"l":"m"}}],"n":[{"o":"p"}]}}`
31 | result, err = i.JSON()
32 | require.NoError(t, err)
33 | assert.Equal(t, jsonString, result)
34 | assert.Equal(t, jsonString, i.MustJSON())
35 | }
36 |
37 | func TestConversionJSONWithError(t *testing.T) {
38 | o := objx.MSI()
39 | o["test"] = func() {}
40 |
41 | assert.Panics(t, func() {
42 | o.MustJSON()
43 | })
44 |
45 | _, err := o.JSON()
46 |
47 | assert.Error(t, err)
48 | }
49 |
50 | func TestConversionBase64(t *testing.T) {
51 | o := objx.Map{"name": "Mat"}
52 |
53 | result, err := o.Base64()
54 |
55 | require.NoError(t, err)
56 | assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", result)
57 | assert.Equal(t, "eyJuYW1lIjoiTWF0In0=", o.MustBase64())
58 | }
59 |
60 | func TestConversionBase64WithError(t *testing.T) {
61 | o := objx.MSI()
62 | o["test"] = func() {}
63 |
64 | assert.Panics(t, func() {
65 | o.MustBase64()
66 | })
67 |
68 | _, err := o.Base64()
69 |
70 | assert.Error(t, err)
71 | }
72 |
73 | func TestConversionSignedBase64(t *testing.T) {
74 | o := objx.Map{"name": "Mat"}
75 |
76 | result, err := o.SignedBase64("key")
77 |
78 | require.NoError(t, err)
79 | assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", result)
80 | assert.Equal(t, "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6", o.MustSignedBase64("key"))
81 | }
82 |
83 | func TestConversionSignedBase64WithError(t *testing.T) {
84 | o := objx.MSI()
85 | o["test"] = func() {}
86 |
87 | assert.Panics(t, func() {
88 | o.MustSignedBase64("key")
89 | })
90 |
91 | _, err := o.SignedBase64("key")
92 |
93 | assert.Error(t, err)
94 | }
95 |
96 | func TestConversionURLValues(t *testing.T) {
97 | m := getURLQueryMap()
98 | u := m.URLValues()
99 |
100 | assert.Equal(t, url.Values{
101 | "abc": []string{"123"},
102 | "name": []string{"Mat"},
103 | "data[age]": []string{"30"},
104 | "data[height]": []string{"162"},
105 | "data[arr][]": []string{"1", "2"},
106 | "stats[]": []string{"1", "2"},
107 | "bools[]": []string{"true", "false"},
108 | "mapSlice[][age]": []string{"40"},
109 | "mapSlice[][height]": []string{"152"},
110 | "msiData[age]": []string{"30"},
111 | "msiData[height]": []string{"162"},
112 | "msiData[arr][]": []string{"1", "2"},
113 | "msiSlice[][age]": []string{"40"},
114 | "msiSlice[][height]": []string{"152"},
115 | }, u)
116 | }
117 |
118 | func TestConversionURLQuery(t *testing.T) {
119 | m := getURLQueryMap()
120 | u, err := m.URLQuery()
121 |
122 | assert.Nil(t, err)
123 | require.NotNil(t, u)
124 |
125 | ue, err := url.QueryUnescape(u)
126 | assert.Nil(t, err)
127 | require.NotNil(t, ue)
128 |
129 | assert.Equal(t, "abc=123&bools[]=true&bools[]=false&data[age]=30&data[arr][]=1&data[arr][]=2&data[height]=162&mapSlice[][age]=40&mapSlice[][height]=152&msiData[age]=30&msiData[arr][]=1&msiData[arr][]=2&msiData[height]=162&msiSlice[][age]=40&msiSlice[][height]=152&name=Mat&stats[]=1&stats[]=2", ue)
130 | }
131 |
132 | func TestConversionURLQueryNoSliceKeySuffix(t *testing.T) {
133 | m := getURLQueryMap()
134 | err := objx.SetURLValuesSliceKeySuffix(objx.URLValuesSliceKeySuffixEmpty)
135 | require.Nil(t, err)
136 | u, err := m.URLQuery()
137 |
138 | assert.Nil(t, err)
139 | require.NotNil(t, u)
140 |
141 | ue, err := url.QueryUnescape(u)
142 | assert.Nil(t, err)
143 | require.NotNil(t, ue)
144 |
145 | assert.Equal(t, "abc=123&bools=true&bools=false&data[age]=30&data[arr]=1&data[arr]=2&data[height]=162&mapSlice[age]=40&mapSlice[height]=152&msiData[age]=30&msiData[arr]=1&msiData[arr]=2&msiData[height]=162&msiSlice[age]=40&msiSlice[height]=152&name=Mat&stats=1&stats=2", ue)
146 | }
147 |
148 | func TestConversionURLQueryIndexSliceKeySuffix(t *testing.T) {
149 | m := getURLQueryMap()
150 | m.Set("mapSlice", []objx.Map{{"age": 40, "sex": "male"}, {"height": 152}})
151 | err := objx.SetURLValuesSliceKeySuffix(objx.URLValuesSliceKeySuffixIndex)
152 | require.Nil(t, err)
153 | u, err := m.URLQuery()
154 |
155 | assert.Nil(t, err)
156 | require.NotNil(t, u)
157 |
158 | ue, err := url.QueryUnescape(u)
159 | assert.Nil(t, err)
160 | require.NotNil(t, ue)
161 |
162 | assert.Equal(t, "abc=123&bools[0]=true&bools[1]=false&data[age]=30&data[arr][0]=1&data[arr][1]=2&data[height]=162&mapSlice[0][age]=40&mapSlice[0][sex]=male&mapSlice[1][height]=152&msiData[age]=30&msiData[arr][0]=1&msiData[arr][1]=2&msiData[height]=162&msiSlice[0][age]=40&msiSlice[1][height]=152&name=Mat&stats[0]=1&stats[1]=2", ue)
163 | }
164 |
165 | func TestValidityURLQuerySliceKeySuffix(t *testing.T) {
166 | err := objx.SetURLValuesSliceKeySuffix("")
167 | assert.Nil(t, err)
168 | err = objx.SetURLValuesSliceKeySuffix("[]")
169 | assert.Nil(t, err)
170 | err = objx.SetURLValuesSliceKeySuffix("[i]")
171 | assert.Nil(t, err)
172 | err = objx.SetURLValuesSliceKeySuffix("{}")
173 | assert.Error(t, err)
174 | }
175 |
176 | func getURLQueryMap() objx.Map {
177 | return objx.Map{
178 | "abc": 123,
179 | "name": "Mat",
180 | "data": objx.Map{"age": 30, "height": 162, "arr": []int{1, 2}},
181 | "mapSlice": []objx.Map{{"age": 40}, {"height": 152}},
182 | "msiData": map[string]interface{}{"age": 30, "height": 162, "arr": []int{1, 2}},
183 | "msiSlice": []map[string]interface{}{{"age": 40}, {"height": 152}},
184 | "stats": []string{"1", "2"},
185 | "bools": []bool{true, false},
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package objx provides utilities for dealing with maps, slices, JSON and other data.
3 |
4 | # Overview
5 |
6 | Objx provides the `objx.Map` type, which is a `map[string]interface{}` that exposes
7 | a powerful `Get` method (among others) that allows you to easily and quickly get
8 | access to data within the map, without having to worry too much about type assertions,
9 | missing data, default values etc.
10 |
11 | # Pattern
12 |
13 | Objx uses a predictable pattern to make access data from within `map[string]interface{}` easy.
14 | Call one of the `objx.` functions to create your `objx.Map` to get going:
15 |
16 | m, err := objx.FromJSON(json)
17 |
18 | NOTE: Any methods or functions with the `Must` prefix will panic if something goes wrong,
19 | the rest will be optimistic and try to figure things out without panicking.
20 |
21 | Use `Get` to access the value you're interested in. You can use dot and array
22 | notation too:
23 |
24 | m.Get("places[0].latlng")
25 |
26 | Once you have sought the `Value` you're interested in, you can use the `Is*` methods to determine its type.
27 |
28 | if m.Get("code").IsStr() { // Your code... }
29 |
30 | Or you can just assume the type, and use one of the strong type methods to extract the real value:
31 |
32 | m.Get("code").Int()
33 |
34 | If there's no value there (or if it's the wrong type) then a default value will be returned,
35 | or you can be explicit about the default value.
36 |
37 | Get("code").Int(-1)
38 |
39 | If you're dealing with a slice of data as a value, Objx provides many useful methods for iterating,
40 | manipulating and selecting that data. You can find out more by exploring the index below.
41 |
42 | # Reading data
43 |
44 | A simple example of how to use Objx:
45 |
46 | // Use MustFromJSON to make an objx.Map from some JSON
47 | m := objx.MustFromJSON(`{"name": "Mat", "age": 30}`)
48 |
49 | // Get the details
50 | name := m.Get("name").Str()
51 | age := m.Get("age").Int()
52 |
53 | // Get their nickname (or use their name if they don't have one)
54 | nickname := m.Get("nickname").Str(name)
55 |
56 | # Ranging
57 |
58 | Since `objx.Map` is a `map[string]interface{}` you can treat it as such.
59 | For example, to `range` the data, do what you would expect:
60 |
61 | m := objx.MustFromJSON(json)
62 | for key, value := range m {
63 | // Your code...
64 | }
65 | */
66 | package objx
67 |
--------------------------------------------------------------------------------
/fixture_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | var fixtures = []struct {
11 | // name is the name of the fixture (used for reporting
12 | // failures)
13 | name string
14 | // data is the JSON data to be worked on
15 | data string
16 | // get is the argument(s) to pass to Get
17 | get interface{}
18 | // output is the expected output
19 | output interface{}
20 | }{
21 | {
22 | name: "Simple get",
23 | data: `{"name": "Mat"}`,
24 | get: "name",
25 | output: "Mat",
26 | },
27 | {
28 | name: "Get with dot notation",
29 | data: `{"address": {"city": "Boulder"}}`,
30 | get: "address.city",
31 | output: "Boulder",
32 | },
33 | {
34 | name: "Deep get with dot notation",
35 | data: `{"one": {"two": {"three": {"four": "hello"}}}}`,
36 | get: "one.two.three.four",
37 | output: "hello",
38 | },
39 | {
40 | name: "Get missing with dot notation",
41 | data: `{"one": {"two": {"three": {"four": "hello"}}}}`,
42 | get: "one.ten",
43 | output: nil,
44 | },
45 | {
46 | name: "Get with array notation",
47 | data: `{"tags": ["one", "two", "three"]}`,
48 | get: "tags[1]",
49 | output: "two",
50 | },
51 | {
52 | name: "Get with array and dot notation",
53 | data: `{"types": { "tags": ["one", "two", "three"]}}`,
54 | get: "types.tags[1]",
55 | output: "two",
56 | },
57 | {
58 | name: "Get with array and dot notation - field after array",
59 | data: `{"tags": [{"name":"one"}, {"name":"two"}, {"name":"three"}]}`,
60 | get: "tags[1].name",
61 | output: "two",
62 | },
63 | {
64 | name: "Complex get with array and dot notation",
65 | data: `{"tags": [{"list": [{"one":"pizza"}]}]}`,
66 | get: "tags[0].list[0].one",
67 | output: "pizza",
68 | },
69 | {
70 | name: "Get field from within string should be nil",
71 | data: `{"name":"Tyler"}`,
72 | get: "name.something",
73 | output: nil,
74 | },
75 | {
76 | name: "Get field from within string (using array accessor) should be nil",
77 | data: `{"numbers":["one", "two", "three"]}`,
78 | get: "numbers[0].nope",
79 | output: nil,
80 | },
81 | }
82 |
83 | func TestFixtures(t *testing.T) {
84 | for _, fixture := range fixtures {
85 | m := objx.MustFromJSON(fixture.data)
86 |
87 | // get the value
88 | t.Logf("Running get fixture: \"%s\" (%v)", fixture.name, fixture)
89 | value := m.Get(fixture.get.(string))
90 |
91 | // make sure it matches
92 | assert.Equal(t, fixture.output, value.Data(),
93 | "Get fixture \"%s\" failed: %v", fixture.name, fixture,
94 | )
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/stretchr/objx
2 |
3 | go 1.20
4 |
5 | require github.com/stretchr/testify v1.10.0
6 |
7 | require (
8 | github.com/davecgh/go-spew v1.1.1 // indirect
9 | github.com/pmezard/go-difflib v1.0.0 // indirect
10 | gopkg.in/yaml.v3 v3.0.1 // indirect
11 | )
12 |
13 | exclude github.com/stretchr/testify v1.8.0
14 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 |
--------------------------------------------------------------------------------
/map.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | import (
4 | "encoding/base64"
5 | "encoding/json"
6 | "errors"
7 | "io/ioutil"
8 | "net/url"
9 | "strings"
10 | )
11 |
12 | // MSIConvertable is an interface that defines methods for converting your
13 | // custom types to a map[string]interface{} representation.
14 | type MSIConvertable interface {
15 | // MSI gets a map[string]interface{} (msi) representing the
16 | // object.
17 | MSI() map[string]interface{}
18 | }
19 |
20 | // Map provides extended functionality for working with
21 | // untyped data, in particular map[string]interface (msi).
22 | type Map map[string]interface{}
23 |
24 | // Value returns the internal value instance
25 | func (m Map) Value() *Value {
26 | return &Value{data: m}
27 | }
28 |
29 | // Nil represents a nil Map.
30 | var Nil = New(nil)
31 |
32 | // New creates a new Map containing the map[string]interface{} in the data argument.
33 | // If the data argument is not a map[string]interface, New attempts to call the
34 | // MSI() method on the MSIConvertable interface to create one.
35 | func New(data interface{}) Map {
36 | if _, ok := data.(map[string]interface{}); !ok {
37 | if converter, ok := data.(MSIConvertable); ok {
38 | data = converter.MSI()
39 | } else {
40 | return nil
41 | }
42 | }
43 | return Map(data.(map[string]interface{}))
44 | }
45 |
46 | // MSI creates a map[string]interface{} and puts it inside a new Map.
47 | //
48 | // The arguments follow a key, value pattern.
49 | //
50 | // Returns nil if any key argument is non-string or if there are an odd number of arguments.
51 | //
52 | // # Example
53 | //
54 | // To easily create Maps:
55 | //
56 | // m := objx.MSI("name", "Mat", "age", 29, "subobj", objx.MSI("active", true))
57 | //
58 | // // creates an Map equivalent to
59 | // m := objx.Map{"name": "Mat", "age": 29, "subobj": objx.Map{"active": true}}
60 | func MSI(keyAndValuePairs ...interface{}) Map {
61 | newMap := Map{}
62 | keyAndValuePairsLen := len(keyAndValuePairs)
63 | if keyAndValuePairsLen%2 != 0 {
64 | return nil
65 | }
66 | for i := 0; i < keyAndValuePairsLen; i = i + 2 {
67 | key := keyAndValuePairs[i]
68 | value := keyAndValuePairs[i+1]
69 |
70 | // make sure the key is a string
71 | keyString, keyStringOK := key.(string)
72 | if !keyStringOK {
73 | return nil
74 | }
75 | newMap[keyString] = value
76 | }
77 | return newMap
78 | }
79 |
80 | // ****** Conversion Constructors
81 |
82 | // MustFromJSON creates a new Map containing the data specified in the
83 | // jsonString.
84 | //
85 | // Panics if the JSON is invalid.
86 | func MustFromJSON(jsonString string) Map {
87 | o, err := FromJSON(jsonString)
88 | if err != nil {
89 | panic("objx: MustFromJSON failed with error: " + err.Error())
90 | }
91 | return o
92 | }
93 |
94 | // MustFromJSONSlice creates a new slice of Map containing the data specified in the
95 | // jsonString. Works with jsons with a top level array
96 | //
97 | // Panics if the JSON is invalid.
98 | func MustFromJSONSlice(jsonString string) []Map {
99 | slice, err := FromJSONSlice(jsonString)
100 | if err != nil {
101 | panic("objx: MustFromJSONSlice failed with error: " + err.Error())
102 | }
103 | return slice
104 | }
105 |
106 | // FromJSON creates a new Map containing the data specified in the
107 | // jsonString.
108 | //
109 | // Returns an error if the JSON is invalid.
110 | func FromJSON(jsonString string) (Map, error) {
111 | var m Map
112 | err := json.Unmarshal([]byte(jsonString), &m)
113 | if err != nil {
114 | return Nil, err
115 | }
116 | return m, nil
117 | }
118 |
119 | // FromJSONSlice creates a new slice of Map containing the data specified in the
120 | // jsonString. Works with jsons with a top level array
121 | //
122 | // Returns an error if the JSON is invalid.
123 | func FromJSONSlice(jsonString string) ([]Map, error) {
124 | var slice []Map
125 | err := json.Unmarshal([]byte(jsonString), &slice)
126 | if err != nil {
127 | return nil, err
128 | }
129 | return slice, nil
130 | }
131 |
132 | // FromBase64 creates a new Obj containing the data specified
133 | // in the Base64 string.
134 | //
135 | // The string is an encoded JSON string returned by Base64
136 | func FromBase64(base64String string) (Map, error) {
137 | decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64String))
138 | decoded, err := ioutil.ReadAll(decoder)
139 | if err != nil {
140 | return nil, err
141 | }
142 | return FromJSON(string(decoded))
143 | }
144 |
145 | // MustFromBase64 creates a new Obj containing the data specified
146 | // in the Base64 string and panics if there is an error.
147 | //
148 | // The string is an encoded JSON string returned by Base64
149 | func MustFromBase64(base64String string) Map {
150 | result, err := FromBase64(base64String)
151 | if err != nil {
152 | panic("objx: MustFromBase64 failed with error: " + err.Error())
153 | }
154 | return result
155 | }
156 |
157 | // FromSignedBase64 creates a new Obj containing the data specified
158 | // in the Base64 string.
159 | //
160 | // The string is an encoded JSON string returned by SignedBase64
161 | func FromSignedBase64(base64String, key string) (Map, error) {
162 | parts := strings.Split(base64String, SignatureSeparator)
163 | if len(parts) != 2 {
164 | return nil, errors.New("objx: Signed base64 string is malformed")
165 | }
166 |
167 | sig := HashWithKey(parts[0], key)
168 | if parts[1] != sig {
169 | return nil, errors.New("objx: Signature for base64 data does not match")
170 | }
171 | return FromBase64(parts[0])
172 | }
173 |
174 | // MustFromSignedBase64 creates a new Obj containing the data specified
175 | // in the Base64 string and panics if there is an error.
176 | //
177 | // The string is an encoded JSON string returned by Base64
178 | func MustFromSignedBase64(base64String, key string) Map {
179 | result, err := FromSignedBase64(base64String, key)
180 | if err != nil {
181 | panic("objx: MustFromSignedBase64 failed with error: " + err.Error())
182 | }
183 | return result
184 | }
185 |
186 | // FromURLQuery generates a new Obj by parsing the specified
187 | // query.
188 | //
189 | // For queries with multiple values, the first value is selected.
190 | func FromURLQuery(query string) (Map, error) {
191 | vals, err := url.ParseQuery(query)
192 | if err != nil {
193 | return nil, err
194 | }
195 | m := Map{}
196 | for k, vals := range vals {
197 | m[k] = vals[0]
198 | }
199 | return m, nil
200 | }
201 |
202 | // MustFromURLQuery generates a new Obj by parsing the specified
203 | // query.
204 | //
205 | // For queries with multiple values, the first value is selected.
206 | //
207 | // Panics if it encounters an error
208 | func MustFromURLQuery(query string) Map {
209 | o, err := FromURLQuery(query)
210 | if err != nil {
211 | panic("objx: MustFromURLQuery failed with error: " + err.Error())
212 | }
213 | return o
214 | }
215 |
--------------------------------------------------------------------------------
/map_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | var TestMap = objx.Map{
12 | "name": "Tyler",
13 | "address": objx.Map{
14 | "city": "Salt Lake City",
15 | "state": "UT",
16 | },
17 | "numbers": []interface{}{"one", "two", "three", "four", "five"},
18 | }
19 |
20 | type Convertable struct {
21 | name string
22 | }
23 |
24 | type Unconvertable struct {
25 | name string
26 | }
27 |
28 | func (c *Convertable) MSI() map[string]interface{} {
29 | return objx.Map{"name": c.name}
30 | }
31 |
32 | func TestMapCreation(t *testing.T) {
33 | o := objx.New(nil)
34 | assert.Nil(t, o)
35 |
36 | o = objx.New("Tyler")
37 | assert.Nil(t, o)
38 |
39 | unconvertable := &Unconvertable{name: "Tyler"}
40 | o = objx.New(unconvertable)
41 | assert.Nil(t, o)
42 |
43 | convertable := &Convertable{name: "Tyler"}
44 | o = objx.New(convertable)
45 | require.NotNil(t, convertable)
46 | assert.Equal(t, "Tyler", o["name"])
47 |
48 | o = objx.MSI()
49 | assert.NotNil(t, o)
50 |
51 | o = objx.MSI("name", "Tyler")
52 | require.NotNil(t, o)
53 | assert.Equal(t, o["name"], "Tyler")
54 |
55 | o = objx.MSI(1, "a")
56 | assert.Nil(t, o)
57 |
58 | o = objx.MSI("a")
59 | assert.Nil(t, o)
60 |
61 | o = objx.MSI("a", "b", "c")
62 | assert.Nil(t, o)
63 | }
64 |
65 | func TestMapValue(t *testing.T) {
66 | m := objx.Map{
67 | "a": 1,
68 | }
69 | v := m.Value()
70 |
71 | assert.Equal(t, m, v.ObjxMap())
72 | }
73 |
74 | func TestMapMustFromJSONWithError(t *testing.T) {
75 | _, err := objx.FromJSON(`"name":"Mat"}`)
76 | assert.Error(t, err)
77 | }
78 |
79 | func TestMapFromJSON(t *testing.T) {
80 | o := objx.MustFromJSON(`{"name":"Mat"}`)
81 |
82 | require.NotNil(t, o)
83 | assert.Equal(t, "Mat", o["name"])
84 | }
85 |
86 | func TestMapFromJSONWithError(t *testing.T) {
87 | var m objx.Map
88 |
89 | assert.Panics(t, func() {
90 | m = objx.MustFromJSON(`"name":"Mat"}`)
91 | })
92 | assert.Nil(t, m)
93 | }
94 |
95 | func TestConversionJSONInt(t *testing.T) {
96 | jsonString :=
97 | `{
98 | "a": 1,
99 | "b": {
100 | "data": 1
101 | },
102 | "c": [1],
103 | "d": [[1]]
104 | }`
105 | m, err := objx.FromJSON(jsonString)
106 |
107 | assert.Nil(t, err)
108 | require.NotNil(t, m)
109 | assert.Equal(t, 1, m.Get("a").Int())
110 | assert.Equal(t, 1, m.Get("b.data").Int())
111 |
112 | assert.True(t, m.Get("c").IsInterSlice())
113 | assert.Equal(t, float64(1), m.Get("c").InterSlice()[0])
114 |
115 | assert.True(t, m.Get("d").IsInterSlice())
116 | assert.Equal(t, []interface{}{float64(1)}, m.Get("d").InterSlice()[0])
117 | }
118 |
119 | func TestJSONSliceInt(t *testing.T) {
120 | jsonString :=
121 | `{
122 | "a": [
123 | {"b": 1},
124 | {"c": 2}
125 | ]
126 | }`
127 | m, err := objx.FromJSON(jsonString)
128 |
129 | assert.Nil(t, err)
130 | require.NotNil(t, m)
131 | assert.Equal(t, []objx.Map{{"b": float64(1)}, {"c": float64(2)}}, m.Get("a").ObjxMapSlice())
132 | }
133 |
134 | func TestJSONSliceMixed(t *testing.T) {
135 | jsonString :=
136 | `{
137 | "a": [
138 | {"b": 1},
139 | "a"
140 | ]
141 | }`
142 | m, err := objx.FromJSON(jsonString)
143 |
144 | assert.Nil(t, err)
145 | require.NotNil(t, m)
146 |
147 | assert.Nil(t, m.Get("a").ObjxMapSlice())
148 | }
149 |
150 | func TestMapFromBase64String(t *testing.T) {
151 | base64String := "eyJuYW1lIjoiTWF0In0="
152 | o, err := objx.FromBase64(base64String)
153 |
154 | require.NoError(t, err)
155 | assert.Equal(t, o.Get("name").Str(), "Mat")
156 | assert.Equal(t, objx.MustFromBase64(base64String).Get("name").Str(), "Mat")
157 | }
158 |
159 | func TestMapFromBase64StringWithError(t *testing.T) {
160 | base64String := "eyJuYW1lIjoiTWFasd0In0="
161 | _, err := objx.FromBase64(base64String)
162 |
163 | assert.Error(t, err)
164 | assert.Panics(t, func() {
165 | objx.MustFromBase64(base64String)
166 | })
167 | }
168 |
169 | func TestMapFromSignedBase64String(t *testing.T) {
170 | base64String := "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
171 |
172 | o, err := objx.FromSignedBase64(base64String, "key")
173 |
174 | require.NoError(t, err)
175 | assert.Equal(t, o.Get("name").Str(), "Mat")
176 | assert.Equal(t, objx.MustFromSignedBase64(base64String, "key").Get("name").Str(), "Mat")
177 | }
178 |
179 | func TestMapFromSignedBase64StringWithError(t *testing.T) {
180 | base64String := "eyJuYW1lasdIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
181 | _, err := objx.FromSignedBase64(base64String, "key")
182 | assert.Error(t, err)
183 | assert.Panics(t, func() {
184 | objx.MustFromSignedBase64(base64String, "key")
185 | })
186 |
187 | base64String = "eyJuYW1lasdIjoiTWF0In0=67ee82916f90b2c0d68c903266e8998c9ef0c3d6"
188 | _, err = objx.FromSignedBase64(base64String, "key")
189 | assert.Error(t, err)
190 | assert.Panics(t, func() {
191 | objx.MustFromSignedBase64(base64String, "key")
192 | })
193 |
194 | base64String = "eyJuYW1lIjoiTWF0In0=_67ee82916f90b2c0d68c903266e8998c9ef0c3d6_junk"
195 | _, err = objx.FromSignedBase64(base64String, "key")
196 | assert.Error(t, err)
197 | assert.Panics(t, func() {
198 | objx.MustFromSignedBase64(base64String, "key")
199 | })
200 | }
201 |
202 | func TestMapFromURLQuery(t *testing.T) {
203 | m, err := objx.FromURLQuery("name=tyler&state=UT")
204 |
205 | assert.NoError(t, err)
206 | require.NotNil(t, m)
207 | assert.Equal(t, "tyler", m.Get("name").Str())
208 | assert.Equal(t, "UT", m.Get("state").Str())
209 | }
210 |
211 | func TestMapMustFromURLQuery(t *testing.T) {
212 | m := objx.MustFromURLQuery("name=tyler&state=UT")
213 |
214 | require.NotNil(t, m)
215 | assert.Equal(t, "tyler", m.Get("name").Str())
216 | assert.Equal(t, "UT", m.Get("state").Str())
217 | }
218 |
219 | func TestMapFromURLQueryWithError(t *testing.T) {
220 | m, err := objx.FromURLQuery("%")
221 |
222 | assert.Error(t, err)
223 | assert.Nil(t, m)
224 | assert.Panics(t, func() {
225 | objx.MustFromURLQuery("%")
226 | })
227 | }
228 |
229 | func TestJSONTopLevelSlice(t *testing.T) {
230 | slice, err := objx.FromJSONSlice(`[{"id": 10000001}, {"id": 42}]`)
231 |
232 | assert.NoError(t, err)
233 | require.Len(t, slice, 2)
234 | assert.Equal(t, 10000001, slice[0].Get("id").MustInt())
235 | assert.Equal(t, 42, slice[1].Get("id").MustInt())
236 | }
237 |
238 | func TestJSONTopLevelSliceWithError(t *testing.T) {
239 | slice, err := objx.FromJSONSlice(`{"id": 10000001}`)
240 |
241 | assert.Error(t, err)
242 | assert.Nil(t, slice)
243 | assert.Panics(t, func() {
244 | _ = objx.MustFromJSONSlice(`{"id": 10000001}`)
245 | })
246 | }
247 |
--------------------------------------------------------------------------------
/mutations.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | // Exclude returns a new Map with the keys in the specified []string
4 | // excluded.
5 | func (m Map) Exclude(exclude []string) Map {
6 | excluded := make(Map)
7 | for k, v := range m {
8 | if !contains(exclude, k) {
9 | excluded[k] = v
10 | }
11 | }
12 | return excluded
13 | }
14 |
15 | // Copy creates a shallow copy of the Obj.
16 | func (m Map) Copy() Map {
17 | copied := Map{}
18 | for k, v := range m {
19 | copied[k] = v
20 | }
21 | return copied
22 | }
23 |
24 | // Merge blends the specified map with a copy of this map and returns the result.
25 | //
26 | // Keys that appear in both will be selected from the specified map.
27 | // This method requires that the wrapped object be a map[string]interface{}
28 | func (m Map) Merge(merge Map) Map {
29 | return m.Copy().MergeHere(merge)
30 | }
31 |
32 | // MergeHere blends the specified map with this map and returns the current map.
33 | //
34 | // Keys that appear in both will be selected from the specified map. The original map
35 | // will be modified. This method requires that
36 | // the wrapped object be a map[string]interface{}
37 | func (m Map) MergeHere(merge Map) Map {
38 | for k, v := range merge {
39 | m[k] = v
40 | }
41 | return m
42 | }
43 |
44 | // Transform builds a new Obj giving the transformer a chance
45 | // to change the keys and values as it goes. This method requires that
46 | // the wrapped object be a map[string]interface{}
47 | func (m Map) Transform(transformer func(key string, value interface{}) (string, interface{})) Map {
48 | newMap := Map{}
49 | for k, v := range m {
50 | modifiedKey, modifiedVal := transformer(k, v)
51 | newMap[modifiedKey] = modifiedVal
52 | }
53 | return newMap
54 | }
55 |
56 | // TransformKeys builds a new map using the specified key mapping.
57 | //
58 | // Unspecified keys will be unaltered.
59 | // This method requires that the wrapped object be a map[string]interface{}
60 | func (m Map) TransformKeys(mapping map[string]string) Map {
61 | return m.Transform(func(key string, value interface{}) (string, interface{}) {
62 | if newKey, ok := mapping[key]; ok {
63 | return newKey, value
64 | }
65 | return key, value
66 | })
67 | }
68 |
69 | // Checks if a string slice contains a string
70 | func contains(s []string, e string) bool {
71 | for _, a := range s {
72 | if a == e {
73 | return true
74 | }
75 | }
76 | return false
77 | }
78 |
--------------------------------------------------------------------------------
/mutations_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/stretchr/objx"
8 | "github.com/stretchr/testify/assert"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestExclude(t *testing.T) {
13 | m := objx.Map{
14 | "name": "Mat",
15 | "age": 29,
16 | "secret": "ABC",
17 | }
18 |
19 | excluded := m.Exclude([]string{"secret"})
20 |
21 | assert.Equal(t, m["name"], excluded["name"])
22 | assert.Equal(t, m["age"], excluded["age"])
23 | assert.False(t, excluded.Has("secret"), "secret should be excluded")
24 | }
25 |
26 | func TestCopy(t *testing.T) {
27 | m1 := objx.Map{
28 | "name": "Tyler",
29 | "location": "UT",
30 | }
31 |
32 | m2 := m1.Copy()
33 | require.NotNil(t, m2)
34 | m2["name"] = "Mat"
35 |
36 | assert.Equal(t, m1.Get("name").Str(), "Tyler")
37 | assert.Equal(t, m2.Get("name").Str(), "Mat")
38 |
39 | }
40 |
41 | func TestMerge(t *testing.T) {
42 | m1 := objx.Map{
43 | "name": "Mat",
44 | }
45 | m2 := objx.Map{
46 | "name": "Tyler",
47 | "location": "UT",
48 | }
49 |
50 | merged := m1.Merge(m2)
51 |
52 | assert.Equal(t, merged.Get("name").Str(), m2.Get("name").Str())
53 | assert.Equal(t, merged.Get("location").Str(), m2.Get("location").Str())
54 | assert.Empty(t, m1.Get("location").Str())
55 | }
56 |
57 | func TestMergeHere(t *testing.T) {
58 | m1 := objx.Map{
59 | "name": "Mat",
60 | }
61 | m2 := objx.Map{
62 | "name": "Tyler",
63 | "location": "UT",
64 | }
65 |
66 | merged := m1.MergeHere(m2)
67 |
68 | assert.Equal(t, m1, merged, "With MergeHere, it should return the first modified map")
69 | assert.Equal(t, merged.Get("name").Str(), m2.Get("name").Str())
70 | assert.Equal(t, merged.Get("location").Str(), m2.Get("location").Str())
71 | assert.Equal(t, merged.Get("location").Str(), m1.Get("location").Str())
72 | }
73 |
74 | func TestTransform(t *testing.T) {
75 | m := objx.Map{
76 | "name": "Mat",
77 | "location": "UK",
78 | }
79 | r := m.Transform(keyToUpper)
80 | assert.Equal(t, objx.Map{
81 | "NAME": "Mat",
82 | "LOCATION": "UK",
83 | }, r)
84 | }
85 |
86 | func TestTransformKeys(t *testing.T) {
87 | m := objx.Map{
88 | "a": "1",
89 | "b": "2",
90 | "c": "3",
91 | }
92 | mapping := map[string]string{
93 | "a": "d",
94 | "b": "e",
95 | }
96 | r := m.TransformKeys(mapping)
97 | assert.Equal(t, objx.Map{
98 | "c": "3",
99 | "d": "1",
100 | "e": "2",
101 | }, r)
102 | }
103 |
104 | func keyToUpper(s string, v interface{}) (string, interface{}) {
105 | return strings.ToUpper(s), v
106 | }
107 |
--------------------------------------------------------------------------------
/security.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | import (
4 | "crypto/sha1"
5 | "encoding/hex"
6 | )
7 |
8 | // HashWithKey hashes the specified string using the security key
9 | func HashWithKey(data, key string) string {
10 | d := sha1.Sum([]byte(data + ":" + key))
11 | return hex.EncodeToString(d[:])
12 | }
13 |
--------------------------------------------------------------------------------
/security_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestHashWithKey(t *testing.T) {
11 | assert.Equal(t, "0ce84d8d01f2c7b6e0882b784429c54d280ea2d9", objx.HashWithKey("abc", "def"))
12 | }
13 |
--------------------------------------------------------------------------------
/simple_example_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestSimpleExample(t *testing.T) {
12 | // build a map from a JSON object
13 | o := objx.MustFromJSON(`{"name":"Mat","foods":["indian","chinese"], "location":{"county":"hobbiton","city":"the shire"}}`)
14 |
15 | // Map can be used as a straight map[string]interface{}
16 | assert.Equal(t, o["name"], "Mat")
17 |
18 | // Get an Value object
19 | v := o.Get("name")
20 | require.NotNil(t, v)
21 |
22 | // Test the contained value
23 | assert.False(t, v.IsInt())
24 | assert.False(t, v.IsBool())
25 | assert.True(t, v.IsStr())
26 |
27 | // Get the contained value
28 | assert.Equal(t, v.Str(), "Mat")
29 |
30 | // Get a default value if the contained value is not of the expected type or does not exist
31 | assert.Equal(t, 1, v.Int(1))
32 |
33 | // Get a value by using array notation
34 | assert.Equal(t, "indian", o.Get("foods[0]").Data())
35 |
36 | // Set a value by using array notation
37 | o.Set("foods[0]", "italian")
38 | assert.Equal(t, "italian", o.Get("foods[0]").Str())
39 |
40 | // Get a value by using dot notation
41 | assert.Equal(t, "hobbiton", o.Get("location.county").Str())
42 | }
43 |
--------------------------------------------------------------------------------
/tests.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | // Has gets whether there is something at the specified selector
4 | // or not.
5 | //
6 | // If m is nil, Has will always return false.
7 | func (m Map) Has(selector string) bool {
8 | if m == nil {
9 | return false
10 | }
11 | return !m.Get(selector).IsNil()
12 | }
13 |
14 | // IsNil gets whether the data is nil or not.
15 | func (v *Value) IsNil() bool {
16 | return v == nil || v.data == nil
17 | }
18 |
--------------------------------------------------------------------------------
/tests_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestHas(t *testing.T) {
11 | m := objx.Map(TestMap)
12 |
13 | assert.True(t, m.Has("name"))
14 | assert.True(t, m.Has("address.state"))
15 | assert.True(t, m.Has("numbers[4]"))
16 |
17 | assert.False(t, m.Has("address.state.nope"))
18 | assert.False(t, m.Has("address.nope"))
19 | assert.False(t, m.Has("nope"))
20 | assert.False(t, m.Has("numbers[5]"))
21 |
22 | m = nil
23 |
24 | assert.False(t, m.Has("nothing"))
25 | }
26 |
--------------------------------------------------------------------------------
/type_specific.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | /*
4 | MSI (map[string]interface{} and []map[string]interface{})
5 | */
6 |
7 | // MSI gets the value as a map[string]interface{}, returns the optionalDefault
8 | // value or a system default object if the value is the wrong type.
9 | func (v *Value) MSI(optionalDefault ...map[string]interface{}) map[string]interface{} {
10 | if s, ok := v.data.(map[string]interface{}); ok {
11 | return s
12 | }
13 | if s, ok := v.data.(Map); ok {
14 | return map[string]interface{}(s)
15 | }
16 | if len(optionalDefault) == 1 {
17 | return optionalDefault[0]
18 | }
19 | return nil
20 | }
21 |
22 | // MustMSI gets the value as a map[string]interface{}.
23 | //
24 | // Panics if the object is not a map[string]interface{}.
25 | func (v *Value) MustMSI() map[string]interface{} {
26 | if s, ok := v.data.(Map); ok {
27 | return map[string]interface{}(s)
28 | }
29 | return v.data.(map[string]interface{})
30 | }
31 |
32 | // MSISlice gets the value as a []map[string]interface{}, returns the optionalDefault
33 | // value or nil if the value is not a []map[string]interface{}.
34 | func (v *Value) MSISlice(optionalDefault ...[]map[string]interface{}) []map[string]interface{} {
35 | if s, ok := v.data.([]map[string]interface{}); ok {
36 | return s
37 | }
38 |
39 | s := v.ObjxMapSlice()
40 | if s == nil {
41 | if len(optionalDefault) == 1 {
42 | return optionalDefault[0]
43 | }
44 | return nil
45 | }
46 |
47 | result := make([]map[string]interface{}, len(s))
48 | for i := range s {
49 | result[i] = s[i].Value().MSI()
50 | }
51 | return result
52 | }
53 |
54 | // MustMSISlice gets the value as a []map[string]interface{}.
55 | //
56 | // Panics if the object is not a []map[string]interface{}.
57 | func (v *Value) MustMSISlice() []map[string]interface{} {
58 | if s := v.MSISlice(); s != nil {
59 | return s
60 | }
61 |
62 | return v.data.([]map[string]interface{})
63 | }
64 |
65 | // IsMSI gets whether the object contained is a map[string]interface{} or not.
66 | func (v *Value) IsMSI() bool {
67 | _, ok := v.data.(map[string]interface{})
68 | if !ok {
69 | _, ok = v.data.(Map)
70 | }
71 | return ok
72 | }
73 |
74 | // IsMSISlice gets whether the object contained is a []map[string]interface{} or not.
75 | func (v *Value) IsMSISlice() bool {
76 | _, ok := v.data.([]map[string]interface{})
77 | if !ok {
78 | _, ok = v.data.([]Map)
79 | if !ok {
80 | s, ok := v.data.([]interface{})
81 | if ok {
82 | for i := range s {
83 | switch s[i].(type) {
84 | case Map:
85 | case map[string]interface{}:
86 | default:
87 | return false
88 | }
89 | }
90 | return true
91 | }
92 | }
93 | }
94 | return ok
95 | }
96 |
97 | // EachMSI calls the specified callback for each object
98 | // in the []map[string]interface{}.
99 | //
100 | // Panics if the object is the wrong type.
101 | func (v *Value) EachMSI(callback func(int, map[string]interface{}) bool) *Value {
102 | for index, val := range v.MustMSISlice() {
103 | carryon := callback(index, val)
104 | if !carryon {
105 | break
106 | }
107 | }
108 | return v
109 | }
110 |
111 | // WhereMSI uses the specified decider function to select items
112 | // from the []map[string]interface{}. The object contained in the result will contain
113 | // only the selected items.
114 | func (v *Value) WhereMSI(decider func(int, map[string]interface{}) bool) *Value {
115 | var selected []map[string]interface{}
116 | v.EachMSI(func(index int, val map[string]interface{}) bool {
117 | shouldSelect := decider(index, val)
118 | if !shouldSelect {
119 | selected = append(selected, val)
120 | }
121 | return true
122 | })
123 | return &Value{data: selected}
124 | }
125 |
126 | // GroupMSI uses the specified grouper function to group the items
127 | // keyed by the return of the grouper. The object contained in the
128 | // result will contain a map[string][]map[string]interface{}.
129 | func (v *Value) GroupMSI(grouper func(int, map[string]interface{}) string) *Value {
130 | groups := make(map[string][]map[string]interface{})
131 | v.EachMSI(func(index int, val map[string]interface{}) bool {
132 | group := grouper(index, val)
133 | if _, ok := groups[group]; !ok {
134 | groups[group] = make([]map[string]interface{}, 0)
135 | }
136 | groups[group] = append(groups[group], val)
137 | return true
138 | })
139 | return &Value{data: groups}
140 | }
141 |
142 | // ReplaceMSI uses the specified function to replace each map[string]interface{}s
143 | // by iterating each item. The data in the returned result will be a
144 | // []map[string]interface{} containing the replaced items.
145 | func (v *Value) ReplaceMSI(replacer func(int, map[string]interface{}) map[string]interface{}) *Value {
146 | arr := v.MustMSISlice()
147 | replaced := make([]map[string]interface{}, len(arr))
148 | v.EachMSI(func(index int, val map[string]interface{}) bool {
149 | replaced[index] = replacer(index, val)
150 | return true
151 | })
152 | return &Value{data: replaced}
153 | }
154 |
155 | // CollectMSI uses the specified collector function to collect a value
156 | // for each of the map[string]interface{}s in the slice. The data returned will be a
157 | // []interface{}.
158 | func (v *Value) CollectMSI(collector func(int, map[string]interface{}) interface{}) *Value {
159 | arr := v.MustMSISlice()
160 | collected := make([]interface{}, len(arr))
161 | v.EachMSI(func(index int, val map[string]interface{}) bool {
162 | collected[index] = collector(index, val)
163 | return true
164 | })
165 | return &Value{data: collected}
166 | }
167 |
168 | /*
169 | ObjxMap ((Map) and [](Map))
170 | */
171 |
172 | // ObjxMap gets the value as a (Map), returns the optionalDefault
173 | // value or a system default object if the value is the wrong type.
174 | func (v *Value) ObjxMap(optionalDefault ...(Map)) Map {
175 | if s, ok := v.data.((Map)); ok {
176 | return s
177 | }
178 | if s, ok := v.data.(map[string]interface{}); ok {
179 | return s
180 | }
181 | if len(optionalDefault) == 1 {
182 | return optionalDefault[0]
183 | }
184 | return New(nil)
185 | }
186 |
187 | // MustObjxMap gets the value as a (Map).
188 | //
189 | // Panics if the object is not a (Map).
190 | func (v *Value) MustObjxMap() Map {
191 | if s, ok := v.data.(map[string]interface{}); ok {
192 | return s
193 | }
194 | return v.data.((Map))
195 | }
196 |
197 | // ObjxMapSlice gets the value as a [](Map), returns the optionalDefault
198 | // value or nil if the value is not a [](Map).
199 | func (v *Value) ObjxMapSlice(optionalDefault ...[](Map)) [](Map) {
200 | if s, ok := v.data.([]Map); ok {
201 | return s
202 | }
203 |
204 | if s, ok := v.data.([]map[string]interface{}); ok {
205 | result := make([]Map, len(s))
206 | for i := range s {
207 | result[i] = s[i]
208 | }
209 | return result
210 | }
211 |
212 | s, ok := v.data.([]interface{})
213 | if !ok {
214 | if len(optionalDefault) == 1 {
215 | return optionalDefault[0]
216 | }
217 | return nil
218 | }
219 |
220 | result := make([]Map, len(s))
221 | for i := range s {
222 | switch s[i].(type) {
223 | case Map:
224 | result[i] = s[i].(Map)
225 | case map[string]interface{}:
226 | result[i] = New(s[i])
227 | default:
228 | return nil
229 | }
230 | }
231 | return result
232 | }
233 |
234 | // MustObjxMapSlice gets the value as a [](Map).
235 | //
236 | // Panics if the object is not a [](Map).
237 | func (v *Value) MustObjxMapSlice() [](Map) {
238 | if s := v.ObjxMapSlice(); s != nil {
239 | return s
240 | }
241 | return v.data.([](Map))
242 | }
243 |
244 | // IsObjxMap gets whether the object contained is a (Map) or not.
245 | func (v *Value) IsObjxMap() bool {
246 | _, ok := v.data.((Map))
247 | if !ok {
248 | _, ok = v.data.(map[string]interface{})
249 | }
250 | return ok
251 | }
252 |
253 | // IsObjxMapSlice gets whether the object contained is a [](Map) or not.
254 | func (v *Value) IsObjxMapSlice() bool {
255 | _, ok := v.data.([](Map))
256 | if !ok {
257 | _, ok = v.data.([]map[string]interface{})
258 | if !ok {
259 | s, ok := v.data.([]interface{})
260 | if ok {
261 | for i := range s {
262 | switch s[i].(type) {
263 | case Map:
264 | case map[string]interface{}:
265 | default:
266 | return false
267 | }
268 | }
269 | return true
270 | }
271 | }
272 | }
273 |
274 | return ok
275 | }
276 |
277 | // EachObjxMap calls the specified callback for each object
278 | // in the [](Map).
279 | //
280 | // Panics if the object is the wrong type.
281 | func (v *Value) EachObjxMap(callback func(int, Map) bool) *Value {
282 | for index, val := range v.MustObjxMapSlice() {
283 | carryon := callback(index, val)
284 | if !carryon {
285 | break
286 | }
287 | }
288 | return v
289 | }
290 |
291 | // WhereObjxMap uses the specified decider function to select items
292 | // from the [](Map). The object contained in the result will contain
293 | // only the selected items.
294 | func (v *Value) WhereObjxMap(decider func(int, Map) bool) *Value {
295 | var selected [](Map)
296 | v.EachObjxMap(func(index int, val Map) bool {
297 | shouldSelect := decider(index, val)
298 | if !shouldSelect {
299 | selected = append(selected, val)
300 | }
301 | return true
302 | })
303 | return &Value{data: selected}
304 | }
305 |
306 | // GroupObjxMap uses the specified grouper function to group the items
307 | // keyed by the return of the grouper. The object contained in the
308 | // result will contain a map[string][](Map).
309 | func (v *Value) GroupObjxMap(grouper func(int, Map) string) *Value {
310 | groups := make(map[string][](Map))
311 | v.EachObjxMap(func(index int, val Map) bool {
312 | group := grouper(index, val)
313 | if _, ok := groups[group]; !ok {
314 | groups[group] = make([](Map), 0)
315 | }
316 | groups[group] = append(groups[group], val)
317 | return true
318 | })
319 | return &Value{data: groups}
320 | }
321 |
322 | // ReplaceObjxMap uses the specified function to replace each (Map)s
323 | // by iterating each item. The data in the returned result will be a
324 | // [](Map) containing the replaced items.
325 | func (v *Value) ReplaceObjxMap(replacer func(int, Map) Map) *Value {
326 | arr := v.MustObjxMapSlice()
327 | replaced := make([](Map), len(arr))
328 | v.EachObjxMap(func(index int, val Map) bool {
329 | replaced[index] = replacer(index, val)
330 | return true
331 | })
332 | return &Value{data: replaced}
333 | }
334 |
335 | // CollectObjxMap uses the specified collector function to collect a value
336 | // for each of the (Map)s in the slice. The data returned will be a
337 | // []interface{}.
338 | func (v *Value) CollectObjxMap(collector func(int, Map) interface{}) *Value {
339 | arr := v.MustObjxMapSlice()
340 | collected := make([]interface{}, len(arr))
341 | v.EachObjxMap(func(index int, val Map) bool {
342 | collected[index] = collector(index, val)
343 | return true
344 | })
345 | return &Value{data: collected}
346 | }
347 |
--------------------------------------------------------------------------------
/type_specific_codegen.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | /*
4 | Inter (interface{} and []interface{})
5 | */
6 |
7 | // Inter gets the value as a interface{}, returns the optionalDefault
8 | // value or a system default object if the value is the wrong type.
9 | func (v *Value) Inter(optionalDefault ...interface{}) interface{} {
10 | if s, ok := v.data.(interface{}); ok {
11 | return s
12 | }
13 | if len(optionalDefault) == 1 {
14 | return optionalDefault[0]
15 | }
16 | return nil
17 | }
18 |
19 | // MustInter gets the value as a interface{}.
20 | //
21 | // Panics if the object is not a interface{}.
22 | func (v *Value) MustInter() interface{} {
23 | return v.data.(interface{})
24 | }
25 |
26 | // InterSlice gets the value as a []interface{}, returns the optionalDefault
27 | // value or nil if the value is not a []interface{}.
28 | func (v *Value) InterSlice(optionalDefault ...[]interface{}) []interface{} {
29 | if s, ok := v.data.([]interface{}); ok {
30 | return s
31 | }
32 | if len(optionalDefault) == 1 {
33 | return optionalDefault[0]
34 | }
35 | return nil
36 | }
37 |
38 | // MustInterSlice gets the value as a []interface{}.
39 | //
40 | // Panics if the object is not a []interface{}.
41 | func (v *Value) MustInterSlice() []interface{} {
42 | return v.data.([]interface{})
43 | }
44 |
45 | // IsInter gets whether the object contained is a interface{} or not.
46 | func (v *Value) IsInter() bool {
47 | _, ok := v.data.(interface{})
48 | return ok
49 | }
50 |
51 | // IsInterSlice gets whether the object contained is a []interface{} or not.
52 | func (v *Value) IsInterSlice() bool {
53 | _, ok := v.data.([]interface{})
54 | return ok
55 | }
56 |
57 | // EachInter calls the specified callback for each object
58 | // in the []interface{}.
59 | //
60 | // Panics if the object is the wrong type.
61 | func (v *Value) EachInter(callback func(int, interface{}) bool) *Value {
62 | for index, val := range v.MustInterSlice() {
63 | carryon := callback(index, val)
64 | if !carryon {
65 | break
66 | }
67 | }
68 | return v
69 | }
70 |
71 | // WhereInter uses the specified decider function to select items
72 | // from the []interface{}. The object contained in the result will contain
73 | // only the selected items.
74 | func (v *Value) WhereInter(decider func(int, interface{}) bool) *Value {
75 | var selected []interface{}
76 | v.EachInter(func(index int, val interface{}) bool {
77 | shouldSelect := decider(index, val)
78 | if !shouldSelect {
79 | selected = append(selected, val)
80 | }
81 | return true
82 | })
83 | return &Value{data: selected}
84 | }
85 |
86 | // GroupInter uses the specified grouper function to group the items
87 | // keyed by the return of the grouper. The object contained in the
88 | // result will contain a map[string][]interface{}.
89 | func (v *Value) GroupInter(grouper func(int, interface{}) string) *Value {
90 | groups := make(map[string][]interface{})
91 | v.EachInter(func(index int, val interface{}) bool {
92 | group := grouper(index, val)
93 | if _, ok := groups[group]; !ok {
94 | groups[group] = make([]interface{}, 0)
95 | }
96 | groups[group] = append(groups[group], val)
97 | return true
98 | })
99 | return &Value{data: groups}
100 | }
101 |
102 | // ReplaceInter uses the specified function to replace each interface{}s
103 | // by iterating each item. The data in the returned result will be a
104 | // []interface{} containing the replaced items.
105 | func (v *Value) ReplaceInter(replacer func(int, interface{}) interface{}) *Value {
106 | arr := v.MustInterSlice()
107 | replaced := make([]interface{}, len(arr))
108 | v.EachInter(func(index int, val interface{}) bool {
109 | replaced[index] = replacer(index, val)
110 | return true
111 | })
112 | return &Value{data: replaced}
113 | }
114 |
115 | // CollectInter uses the specified collector function to collect a value
116 | // for each of the interface{}s in the slice. The data returned will be a
117 | // []interface{}.
118 | func (v *Value) CollectInter(collector func(int, interface{}) interface{}) *Value {
119 | arr := v.MustInterSlice()
120 | collected := make([]interface{}, len(arr))
121 | v.EachInter(func(index int, val interface{}) bool {
122 | collected[index] = collector(index, val)
123 | return true
124 | })
125 | return &Value{data: collected}
126 | }
127 |
128 | /*
129 | Bool (bool and []bool)
130 | */
131 |
132 | // Bool gets the value as a bool, returns the optionalDefault
133 | // value or a system default object if the value is the wrong type.
134 | func (v *Value) Bool(optionalDefault ...bool) bool {
135 | if s, ok := v.data.(bool); ok {
136 | return s
137 | }
138 | if len(optionalDefault) == 1 {
139 | return optionalDefault[0]
140 | }
141 | return false
142 | }
143 |
144 | // MustBool gets the value as a bool.
145 | //
146 | // Panics if the object is not a bool.
147 | func (v *Value) MustBool() bool {
148 | return v.data.(bool)
149 | }
150 |
151 | // BoolSlice gets the value as a []bool, returns the optionalDefault
152 | // value or nil if the value is not a []bool.
153 | func (v *Value) BoolSlice(optionalDefault ...[]bool) []bool {
154 | if s, ok := v.data.([]bool); ok {
155 | return s
156 | }
157 | if len(optionalDefault) == 1 {
158 | return optionalDefault[0]
159 | }
160 | return nil
161 | }
162 |
163 | // MustBoolSlice gets the value as a []bool.
164 | //
165 | // Panics if the object is not a []bool.
166 | func (v *Value) MustBoolSlice() []bool {
167 | return v.data.([]bool)
168 | }
169 |
170 | // IsBool gets whether the object contained is a bool or not.
171 | func (v *Value) IsBool() bool {
172 | _, ok := v.data.(bool)
173 | return ok
174 | }
175 |
176 | // IsBoolSlice gets whether the object contained is a []bool or not.
177 | func (v *Value) IsBoolSlice() bool {
178 | _, ok := v.data.([]bool)
179 | return ok
180 | }
181 |
182 | // EachBool calls the specified callback for each object
183 | // in the []bool.
184 | //
185 | // Panics if the object is the wrong type.
186 | func (v *Value) EachBool(callback func(int, bool) bool) *Value {
187 | for index, val := range v.MustBoolSlice() {
188 | carryon := callback(index, val)
189 | if !carryon {
190 | break
191 | }
192 | }
193 | return v
194 | }
195 |
196 | // WhereBool uses the specified decider function to select items
197 | // from the []bool. The object contained in the result will contain
198 | // only the selected items.
199 | func (v *Value) WhereBool(decider func(int, bool) bool) *Value {
200 | var selected []bool
201 | v.EachBool(func(index int, val bool) bool {
202 | shouldSelect := decider(index, val)
203 | if !shouldSelect {
204 | selected = append(selected, val)
205 | }
206 | return true
207 | })
208 | return &Value{data: selected}
209 | }
210 |
211 | // GroupBool uses the specified grouper function to group the items
212 | // keyed by the return of the grouper. The object contained in the
213 | // result will contain a map[string][]bool.
214 | func (v *Value) GroupBool(grouper func(int, bool) string) *Value {
215 | groups := make(map[string][]bool)
216 | v.EachBool(func(index int, val bool) bool {
217 | group := grouper(index, val)
218 | if _, ok := groups[group]; !ok {
219 | groups[group] = make([]bool, 0)
220 | }
221 | groups[group] = append(groups[group], val)
222 | return true
223 | })
224 | return &Value{data: groups}
225 | }
226 |
227 | // ReplaceBool uses the specified function to replace each bools
228 | // by iterating each item. The data in the returned result will be a
229 | // []bool containing the replaced items.
230 | func (v *Value) ReplaceBool(replacer func(int, bool) bool) *Value {
231 | arr := v.MustBoolSlice()
232 | replaced := make([]bool, len(arr))
233 | v.EachBool(func(index int, val bool) bool {
234 | replaced[index] = replacer(index, val)
235 | return true
236 | })
237 | return &Value{data: replaced}
238 | }
239 |
240 | // CollectBool uses the specified collector function to collect a value
241 | // for each of the bools in the slice. The data returned will be a
242 | // []interface{}.
243 | func (v *Value) CollectBool(collector func(int, bool) interface{}) *Value {
244 | arr := v.MustBoolSlice()
245 | collected := make([]interface{}, len(arr))
246 | v.EachBool(func(index int, val bool) bool {
247 | collected[index] = collector(index, val)
248 | return true
249 | })
250 | return &Value{data: collected}
251 | }
252 |
253 | /*
254 | Str (string and []string)
255 | */
256 |
257 | // Str gets the value as a string, returns the optionalDefault
258 | // value or a system default object if the value is the wrong type.
259 | func (v *Value) Str(optionalDefault ...string) string {
260 | if s, ok := v.data.(string); ok {
261 | return s
262 | }
263 | if len(optionalDefault) == 1 {
264 | return optionalDefault[0]
265 | }
266 | return ""
267 | }
268 |
269 | // MustStr gets the value as a string.
270 | //
271 | // Panics if the object is not a string.
272 | func (v *Value) MustStr() string {
273 | return v.data.(string)
274 | }
275 |
276 | // StrSlice gets the value as a []string, returns the optionalDefault
277 | // value or nil if the value is not a []string.
278 | func (v *Value) StrSlice(optionalDefault ...[]string) []string {
279 | if s, ok := v.data.([]string); ok {
280 | return s
281 | }
282 | if len(optionalDefault) == 1 {
283 | return optionalDefault[0]
284 | }
285 | return nil
286 | }
287 |
288 | // MustStrSlice gets the value as a []string.
289 | //
290 | // Panics if the object is not a []string.
291 | func (v *Value) MustStrSlice() []string {
292 | return v.data.([]string)
293 | }
294 |
295 | // IsStr gets whether the object contained is a string or not.
296 | func (v *Value) IsStr() bool {
297 | _, ok := v.data.(string)
298 | return ok
299 | }
300 |
301 | // IsStrSlice gets whether the object contained is a []string or not.
302 | func (v *Value) IsStrSlice() bool {
303 | _, ok := v.data.([]string)
304 | return ok
305 | }
306 |
307 | // EachStr calls the specified callback for each object
308 | // in the []string.
309 | //
310 | // Panics if the object is the wrong type.
311 | func (v *Value) EachStr(callback func(int, string) bool) *Value {
312 | for index, val := range v.MustStrSlice() {
313 | carryon := callback(index, val)
314 | if !carryon {
315 | break
316 | }
317 | }
318 | return v
319 | }
320 |
321 | // WhereStr uses the specified decider function to select items
322 | // from the []string. The object contained in the result will contain
323 | // only the selected items.
324 | func (v *Value) WhereStr(decider func(int, string) bool) *Value {
325 | var selected []string
326 | v.EachStr(func(index int, val string) bool {
327 | shouldSelect := decider(index, val)
328 | if !shouldSelect {
329 | selected = append(selected, val)
330 | }
331 | return true
332 | })
333 | return &Value{data: selected}
334 | }
335 |
336 | // GroupStr uses the specified grouper function to group the items
337 | // keyed by the return of the grouper. The object contained in the
338 | // result will contain a map[string][]string.
339 | func (v *Value) GroupStr(grouper func(int, string) string) *Value {
340 | groups := make(map[string][]string)
341 | v.EachStr(func(index int, val string) bool {
342 | group := grouper(index, val)
343 | if _, ok := groups[group]; !ok {
344 | groups[group] = make([]string, 0)
345 | }
346 | groups[group] = append(groups[group], val)
347 | return true
348 | })
349 | return &Value{data: groups}
350 | }
351 |
352 | // ReplaceStr uses the specified function to replace each strings
353 | // by iterating each item. The data in the returned result will be a
354 | // []string containing the replaced items.
355 | func (v *Value) ReplaceStr(replacer func(int, string) string) *Value {
356 | arr := v.MustStrSlice()
357 | replaced := make([]string, len(arr))
358 | v.EachStr(func(index int, val string) bool {
359 | replaced[index] = replacer(index, val)
360 | return true
361 | })
362 | return &Value{data: replaced}
363 | }
364 |
365 | // CollectStr uses the specified collector function to collect a value
366 | // for each of the strings in the slice. The data returned will be a
367 | // []interface{}.
368 | func (v *Value) CollectStr(collector func(int, string) interface{}) *Value {
369 | arr := v.MustStrSlice()
370 | collected := make([]interface{}, len(arr))
371 | v.EachStr(func(index int, val string) bool {
372 | collected[index] = collector(index, val)
373 | return true
374 | })
375 | return &Value{data: collected}
376 | }
377 |
378 | /*
379 | Int (int and []int)
380 | */
381 |
382 | // Int gets the value as a int, returns the optionalDefault
383 | // value or a system default object if the value is the wrong type.
384 | func (v *Value) Int(optionalDefault ...int) int {
385 | if s, ok := v.data.(int); ok {
386 | return s
387 | }
388 | if s, ok := v.data.(float64); ok {
389 | if float64(int(s)) == s {
390 | return int(s)
391 | }
392 | }
393 | if len(optionalDefault) == 1 {
394 | return optionalDefault[0]
395 | }
396 | return 0
397 | }
398 |
399 | // MustInt gets the value as a int.
400 | //
401 | // Panics if the object is not a int.
402 | func (v *Value) MustInt() int {
403 | if s, ok := v.data.(float64); ok {
404 | if float64(int(s)) == s {
405 | return int(s)
406 | }
407 | }
408 | return v.data.(int)
409 | }
410 |
411 | // IntSlice gets the value as a []int, returns the optionalDefault
412 | // value or nil if the value is not a []int.
413 | func (v *Value) IntSlice(optionalDefault ...[]int) []int {
414 | if s, ok := v.data.([]int); ok {
415 | return s
416 | }
417 | if len(optionalDefault) == 1 {
418 | return optionalDefault[0]
419 | }
420 | return nil
421 | }
422 |
423 | // MustIntSlice gets the value as a []int.
424 | //
425 | // Panics if the object is not a []int.
426 | func (v *Value) MustIntSlice() []int {
427 | return v.data.([]int)
428 | }
429 |
430 | // IsInt gets whether the object contained is a int or not.
431 | func (v *Value) IsInt() bool {
432 | _, ok := v.data.(int)
433 | return ok
434 | }
435 |
436 | // IsIntSlice gets whether the object contained is a []int or not.
437 | func (v *Value) IsIntSlice() bool {
438 | _, ok := v.data.([]int)
439 | return ok
440 | }
441 |
442 | // EachInt calls the specified callback for each object
443 | // in the []int.
444 | //
445 | // Panics if the object is the wrong type.
446 | func (v *Value) EachInt(callback func(int, int) bool) *Value {
447 | for index, val := range v.MustIntSlice() {
448 | carryon := callback(index, val)
449 | if !carryon {
450 | break
451 | }
452 | }
453 | return v
454 | }
455 |
456 | // WhereInt uses the specified decider function to select items
457 | // from the []int. The object contained in the result will contain
458 | // only the selected items.
459 | func (v *Value) WhereInt(decider func(int, int) bool) *Value {
460 | var selected []int
461 | v.EachInt(func(index int, val int) bool {
462 | shouldSelect := decider(index, val)
463 | if !shouldSelect {
464 | selected = append(selected, val)
465 | }
466 | return true
467 | })
468 | return &Value{data: selected}
469 | }
470 |
471 | // GroupInt uses the specified grouper function to group the items
472 | // keyed by the return of the grouper. The object contained in the
473 | // result will contain a map[string][]int.
474 | func (v *Value) GroupInt(grouper func(int, int) string) *Value {
475 | groups := make(map[string][]int)
476 | v.EachInt(func(index int, val int) bool {
477 | group := grouper(index, val)
478 | if _, ok := groups[group]; !ok {
479 | groups[group] = make([]int, 0)
480 | }
481 | groups[group] = append(groups[group], val)
482 | return true
483 | })
484 | return &Value{data: groups}
485 | }
486 |
487 | // ReplaceInt uses the specified function to replace each ints
488 | // by iterating each item. The data in the returned result will be a
489 | // []int containing the replaced items.
490 | func (v *Value) ReplaceInt(replacer func(int, int) int) *Value {
491 | arr := v.MustIntSlice()
492 | replaced := make([]int, len(arr))
493 | v.EachInt(func(index int, val int) bool {
494 | replaced[index] = replacer(index, val)
495 | return true
496 | })
497 | return &Value{data: replaced}
498 | }
499 |
500 | // CollectInt uses the specified collector function to collect a value
501 | // for each of the ints in the slice. The data returned will be a
502 | // []interface{}.
503 | func (v *Value) CollectInt(collector func(int, int) interface{}) *Value {
504 | arr := v.MustIntSlice()
505 | collected := make([]interface{}, len(arr))
506 | v.EachInt(func(index int, val int) bool {
507 | collected[index] = collector(index, val)
508 | return true
509 | })
510 | return &Value{data: collected}
511 | }
512 |
513 | /*
514 | Int8 (int8 and []int8)
515 | */
516 |
517 | // Int8 gets the value as a int8, returns the optionalDefault
518 | // value or a system default object if the value is the wrong type.
519 | func (v *Value) Int8(optionalDefault ...int8) int8 {
520 | if s, ok := v.data.(int8); ok {
521 | return s
522 | }
523 | if len(optionalDefault) == 1 {
524 | return optionalDefault[0]
525 | }
526 | return 0
527 | }
528 |
529 | // MustInt8 gets the value as a int8.
530 | //
531 | // Panics if the object is not a int8.
532 | func (v *Value) MustInt8() int8 {
533 | return v.data.(int8)
534 | }
535 |
536 | // Int8Slice gets the value as a []int8, returns the optionalDefault
537 | // value or nil if the value is not a []int8.
538 | func (v *Value) Int8Slice(optionalDefault ...[]int8) []int8 {
539 | if s, ok := v.data.([]int8); ok {
540 | return s
541 | }
542 | if len(optionalDefault) == 1 {
543 | return optionalDefault[0]
544 | }
545 | return nil
546 | }
547 |
548 | // MustInt8Slice gets the value as a []int8.
549 | //
550 | // Panics if the object is not a []int8.
551 | func (v *Value) MustInt8Slice() []int8 {
552 | return v.data.([]int8)
553 | }
554 |
555 | // IsInt8 gets whether the object contained is a int8 or not.
556 | func (v *Value) IsInt8() bool {
557 | _, ok := v.data.(int8)
558 | return ok
559 | }
560 |
561 | // IsInt8Slice gets whether the object contained is a []int8 or not.
562 | func (v *Value) IsInt8Slice() bool {
563 | _, ok := v.data.([]int8)
564 | return ok
565 | }
566 |
567 | // EachInt8 calls the specified callback for each object
568 | // in the []int8.
569 | //
570 | // Panics if the object is the wrong type.
571 | func (v *Value) EachInt8(callback func(int, int8) bool) *Value {
572 | for index, val := range v.MustInt8Slice() {
573 | carryon := callback(index, val)
574 | if !carryon {
575 | break
576 | }
577 | }
578 | return v
579 | }
580 |
581 | // WhereInt8 uses the specified decider function to select items
582 | // from the []int8. The object contained in the result will contain
583 | // only the selected items.
584 | func (v *Value) WhereInt8(decider func(int, int8) bool) *Value {
585 | var selected []int8
586 | v.EachInt8(func(index int, val int8) bool {
587 | shouldSelect := decider(index, val)
588 | if !shouldSelect {
589 | selected = append(selected, val)
590 | }
591 | return true
592 | })
593 | return &Value{data: selected}
594 | }
595 |
596 | // GroupInt8 uses the specified grouper function to group the items
597 | // keyed by the return of the grouper. The object contained in the
598 | // result will contain a map[string][]int8.
599 | func (v *Value) GroupInt8(grouper func(int, int8) string) *Value {
600 | groups := make(map[string][]int8)
601 | v.EachInt8(func(index int, val int8) bool {
602 | group := grouper(index, val)
603 | if _, ok := groups[group]; !ok {
604 | groups[group] = make([]int8, 0)
605 | }
606 | groups[group] = append(groups[group], val)
607 | return true
608 | })
609 | return &Value{data: groups}
610 | }
611 |
612 | // ReplaceInt8 uses the specified function to replace each int8s
613 | // by iterating each item. The data in the returned result will be a
614 | // []int8 containing the replaced items.
615 | func (v *Value) ReplaceInt8(replacer func(int, int8) int8) *Value {
616 | arr := v.MustInt8Slice()
617 | replaced := make([]int8, len(arr))
618 | v.EachInt8(func(index int, val int8) bool {
619 | replaced[index] = replacer(index, val)
620 | return true
621 | })
622 | return &Value{data: replaced}
623 | }
624 |
625 | // CollectInt8 uses the specified collector function to collect a value
626 | // for each of the int8s in the slice. The data returned will be a
627 | // []interface{}.
628 | func (v *Value) CollectInt8(collector func(int, int8) interface{}) *Value {
629 | arr := v.MustInt8Slice()
630 | collected := make([]interface{}, len(arr))
631 | v.EachInt8(func(index int, val int8) bool {
632 | collected[index] = collector(index, val)
633 | return true
634 | })
635 | return &Value{data: collected}
636 | }
637 |
638 | /*
639 | Int16 (int16 and []int16)
640 | */
641 |
642 | // Int16 gets the value as a int16, returns the optionalDefault
643 | // value or a system default object if the value is the wrong type.
644 | func (v *Value) Int16(optionalDefault ...int16) int16 {
645 | if s, ok := v.data.(int16); ok {
646 | return s
647 | }
648 | if len(optionalDefault) == 1 {
649 | return optionalDefault[0]
650 | }
651 | return 0
652 | }
653 |
654 | // MustInt16 gets the value as a int16.
655 | //
656 | // Panics if the object is not a int16.
657 | func (v *Value) MustInt16() int16 {
658 | return v.data.(int16)
659 | }
660 |
661 | // Int16Slice gets the value as a []int16, returns the optionalDefault
662 | // value or nil if the value is not a []int16.
663 | func (v *Value) Int16Slice(optionalDefault ...[]int16) []int16 {
664 | if s, ok := v.data.([]int16); ok {
665 | return s
666 | }
667 | if len(optionalDefault) == 1 {
668 | return optionalDefault[0]
669 | }
670 | return nil
671 | }
672 |
673 | // MustInt16Slice gets the value as a []int16.
674 | //
675 | // Panics if the object is not a []int16.
676 | func (v *Value) MustInt16Slice() []int16 {
677 | return v.data.([]int16)
678 | }
679 |
680 | // IsInt16 gets whether the object contained is a int16 or not.
681 | func (v *Value) IsInt16() bool {
682 | _, ok := v.data.(int16)
683 | return ok
684 | }
685 |
686 | // IsInt16Slice gets whether the object contained is a []int16 or not.
687 | func (v *Value) IsInt16Slice() bool {
688 | _, ok := v.data.([]int16)
689 | return ok
690 | }
691 |
692 | // EachInt16 calls the specified callback for each object
693 | // in the []int16.
694 | //
695 | // Panics if the object is the wrong type.
696 | func (v *Value) EachInt16(callback func(int, int16) bool) *Value {
697 | for index, val := range v.MustInt16Slice() {
698 | carryon := callback(index, val)
699 | if !carryon {
700 | break
701 | }
702 | }
703 | return v
704 | }
705 |
706 | // WhereInt16 uses the specified decider function to select items
707 | // from the []int16. The object contained in the result will contain
708 | // only the selected items.
709 | func (v *Value) WhereInt16(decider func(int, int16) bool) *Value {
710 | var selected []int16
711 | v.EachInt16(func(index int, val int16) bool {
712 | shouldSelect := decider(index, val)
713 | if !shouldSelect {
714 | selected = append(selected, val)
715 | }
716 | return true
717 | })
718 | return &Value{data: selected}
719 | }
720 |
721 | // GroupInt16 uses the specified grouper function to group the items
722 | // keyed by the return of the grouper. The object contained in the
723 | // result will contain a map[string][]int16.
724 | func (v *Value) GroupInt16(grouper func(int, int16) string) *Value {
725 | groups := make(map[string][]int16)
726 | v.EachInt16(func(index int, val int16) bool {
727 | group := grouper(index, val)
728 | if _, ok := groups[group]; !ok {
729 | groups[group] = make([]int16, 0)
730 | }
731 | groups[group] = append(groups[group], val)
732 | return true
733 | })
734 | return &Value{data: groups}
735 | }
736 |
737 | // ReplaceInt16 uses the specified function to replace each int16s
738 | // by iterating each item. The data in the returned result will be a
739 | // []int16 containing the replaced items.
740 | func (v *Value) ReplaceInt16(replacer func(int, int16) int16) *Value {
741 | arr := v.MustInt16Slice()
742 | replaced := make([]int16, len(arr))
743 | v.EachInt16(func(index int, val int16) bool {
744 | replaced[index] = replacer(index, val)
745 | return true
746 | })
747 | return &Value{data: replaced}
748 | }
749 |
750 | // CollectInt16 uses the specified collector function to collect a value
751 | // for each of the int16s in the slice. The data returned will be a
752 | // []interface{}.
753 | func (v *Value) CollectInt16(collector func(int, int16) interface{}) *Value {
754 | arr := v.MustInt16Slice()
755 | collected := make([]interface{}, len(arr))
756 | v.EachInt16(func(index int, val int16) bool {
757 | collected[index] = collector(index, val)
758 | return true
759 | })
760 | return &Value{data: collected}
761 | }
762 |
763 | /*
764 | Int32 (int32 and []int32)
765 | */
766 |
767 | // Int32 gets the value as a int32, returns the optionalDefault
768 | // value or a system default object if the value is the wrong type.
769 | func (v *Value) Int32(optionalDefault ...int32) int32 {
770 | if s, ok := v.data.(int32); ok {
771 | return s
772 | }
773 | if len(optionalDefault) == 1 {
774 | return optionalDefault[0]
775 | }
776 | return 0
777 | }
778 |
779 | // MustInt32 gets the value as a int32.
780 | //
781 | // Panics if the object is not a int32.
782 | func (v *Value) MustInt32() int32 {
783 | return v.data.(int32)
784 | }
785 |
786 | // Int32Slice gets the value as a []int32, returns the optionalDefault
787 | // value or nil if the value is not a []int32.
788 | func (v *Value) Int32Slice(optionalDefault ...[]int32) []int32 {
789 | if s, ok := v.data.([]int32); ok {
790 | return s
791 | }
792 | if len(optionalDefault) == 1 {
793 | return optionalDefault[0]
794 | }
795 | return nil
796 | }
797 |
798 | // MustInt32Slice gets the value as a []int32.
799 | //
800 | // Panics if the object is not a []int32.
801 | func (v *Value) MustInt32Slice() []int32 {
802 | return v.data.([]int32)
803 | }
804 |
805 | // IsInt32 gets whether the object contained is a int32 or not.
806 | func (v *Value) IsInt32() bool {
807 | _, ok := v.data.(int32)
808 | return ok
809 | }
810 |
811 | // IsInt32Slice gets whether the object contained is a []int32 or not.
812 | func (v *Value) IsInt32Slice() bool {
813 | _, ok := v.data.([]int32)
814 | return ok
815 | }
816 |
817 | // EachInt32 calls the specified callback for each object
818 | // in the []int32.
819 | //
820 | // Panics if the object is the wrong type.
821 | func (v *Value) EachInt32(callback func(int, int32) bool) *Value {
822 | for index, val := range v.MustInt32Slice() {
823 | carryon := callback(index, val)
824 | if !carryon {
825 | break
826 | }
827 | }
828 | return v
829 | }
830 |
831 | // WhereInt32 uses the specified decider function to select items
832 | // from the []int32. The object contained in the result will contain
833 | // only the selected items.
834 | func (v *Value) WhereInt32(decider func(int, int32) bool) *Value {
835 | var selected []int32
836 | v.EachInt32(func(index int, val int32) bool {
837 | shouldSelect := decider(index, val)
838 | if !shouldSelect {
839 | selected = append(selected, val)
840 | }
841 | return true
842 | })
843 | return &Value{data: selected}
844 | }
845 |
846 | // GroupInt32 uses the specified grouper function to group the items
847 | // keyed by the return of the grouper. The object contained in the
848 | // result will contain a map[string][]int32.
849 | func (v *Value) GroupInt32(grouper func(int, int32) string) *Value {
850 | groups := make(map[string][]int32)
851 | v.EachInt32(func(index int, val int32) bool {
852 | group := grouper(index, val)
853 | if _, ok := groups[group]; !ok {
854 | groups[group] = make([]int32, 0)
855 | }
856 | groups[group] = append(groups[group], val)
857 | return true
858 | })
859 | return &Value{data: groups}
860 | }
861 |
862 | // ReplaceInt32 uses the specified function to replace each int32s
863 | // by iterating each item. The data in the returned result will be a
864 | // []int32 containing the replaced items.
865 | func (v *Value) ReplaceInt32(replacer func(int, int32) int32) *Value {
866 | arr := v.MustInt32Slice()
867 | replaced := make([]int32, len(arr))
868 | v.EachInt32(func(index int, val int32) bool {
869 | replaced[index] = replacer(index, val)
870 | return true
871 | })
872 | return &Value{data: replaced}
873 | }
874 |
875 | // CollectInt32 uses the specified collector function to collect a value
876 | // for each of the int32s in the slice. The data returned will be a
877 | // []interface{}.
878 | func (v *Value) CollectInt32(collector func(int, int32) interface{}) *Value {
879 | arr := v.MustInt32Slice()
880 | collected := make([]interface{}, len(arr))
881 | v.EachInt32(func(index int, val int32) bool {
882 | collected[index] = collector(index, val)
883 | return true
884 | })
885 | return &Value{data: collected}
886 | }
887 |
888 | /*
889 | Int64 (int64 and []int64)
890 | */
891 |
892 | // Int64 gets the value as a int64, returns the optionalDefault
893 | // value or a system default object if the value is the wrong type.
894 | func (v *Value) Int64(optionalDefault ...int64) int64 {
895 | if s, ok := v.data.(int64); ok {
896 | return s
897 | }
898 | if len(optionalDefault) == 1 {
899 | return optionalDefault[0]
900 | }
901 | return 0
902 | }
903 |
904 | // MustInt64 gets the value as a int64.
905 | //
906 | // Panics if the object is not a int64.
907 | func (v *Value) MustInt64() int64 {
908 | return v.data.(int64)
909 | }
910 |
911 | // Int64Slice gets the value as a []int64, returns the optionalDefault
912 | // value or nil if the value is not a []int64.
913 | func (v *Value) Int64Slice(optionalDefault ...[]int64) []int64 {
914 | if s, ok := v.data.([]int64); ok {
915 | return s
916 | }
917 | if len(optionalDefault) == 1 {
918 | return optionalDefault[0]
919 | }
920 | return nil
921 | }
922 |
923 | // MustInt64Slice gets the value as a []int64.
924 | //
925 | // Panics if the object is not a []int64.
926 | func (v *Value) MustInt64Slice() []int64 {
927 | return v.data.([]int64)
928 | }
929 |
930 | // IsInt64 gets whether the object contained is a int64 or not.
931 | func (v *Value) IsInt64() bool {
932 | _, ok := v.data.(int64)
933 | return ok
934 | }
935 |
936 | // IsInt64Slice gets whether the object contained is a []int64 or not.
937 | func (v *Value) IsInt64Slice() bool {
938 | _, ok := v.data.([]int64)
939 | return ok
940 | }
941 |
942 | // EachInt64 calls the specified callback for each object
943 | // in the []int64.
944 | //
945 | // Panics if the object is the wrong type.
946 | func (v *Value) EachInt64(callback func(int, int64) bool) *Value {
947 | for index, val := range v.MustInt64Slice() {
948 | carryon := callback(index, val)
949 | if !carryon {
950 | break
951 | }
952 | }
953 | return v
954 | }
955 |
956 | // WhereInt64 uses the specified decider function to select items
957 | // from the []int64. The object contained in the result will contain
958 | // only the selected items.
959 | func (v *Value) WhereInt64(decider func(int, int64) bool) *Value {
960 | var selected []int64
961 | v.EachInt64(func(index int, val int64) bool {
962 | shouldSelect := decider(index, val)
963 | if !shouldSelect {
964 | selected = append(selected, val)
965 | }
966 | return true
967 | })
968 | return &Value{data: selected}
969 | }
970 |
971 | // GroupInt64 uses the specified grouper function to group the items
972 | // keyed by the return of the grouper. The object contained in the
973 | // result will contain a map[string][]int64.
974 | func (v *Value) GroupInt64(grouper func(int, int64) string) *Value {
975 | groups := make(map[string][]int64)
976 | v.EachInt64(func(index int, val int64) bool {
977 | group := grouper(index, val)
978 | if _, ok := groups[group]; !ok {
979 | groups[group] = make([]int64, 0)
980 | }
981 | groups[group] = append(groups[group], val)
982 | return true
983 | })
984 | return &Value{data: groups}
985 | }
986 |
987 | // ReplaceInt64 uses the specified function to replace each int64s
988 | // by iterating each item. The data in the returned result will be a
989 | // []int64 containing the replaced items.
990 | func (v *Value) ReplaceInt64(replacer func(int, int64) int64) *Value {
991 | arr := v.MustInt64Slice()
992 | replaced := make([]int64, len(arr))
993 | v.EachInt64(func(index int, val int64) bool {
994 | replaced[index] = replacer(index, val)
995 | return true
996 | })
997 | return &Value{data: replaced}
998 | }
999 |
1000 | // CollectInt64 uses the specified collector function to collect a value
1001 | // for each of the int64s in the slice. The data returned will be a
1002 | // []interface{}.
1003 | func (v *Value) CollectInt64(collector func(int, int64) interface{}) *Value {
1004 | arr := v.MustInt64Slice()
1005 | collected := make([]interface{}, len(arr))
1006 | v.EachInt64(func(index int, val int64) bool {
1007 | collected[index] = collector(index, val)
1008 | return true
1009 | })
1010 | return &Value{data: collected}
1011 | }
1012 |
1013 | /*
1014 | Uint (uint and []uint)
1015 | */
1016 |
1017 | // Uint gets the value as a uint, returns the optionalDefault
1018 | // value or a system default object if the value is the wrong type.
1019 | func (v *Value) Uint(optionalDefault ...uint) uint {
1020 | if s, ok := v.data.(uint); ok {
1021 | return s
1022 | }
1023 | if len(optionalDefault) == 1 {
1024 | return optionalDefault[0]
1025 | }
1026 | return 0
1027 | }
1028 |
1029 | // MustUint gets the value as a uint.
1030 | //
1031 | // Panics if the object is not a uint.
1032 | func (v *Value) MustUint() uint {
1033 | return v.data.(uint)
1034 | }
1035 |
1036 | // UintSlice gets the value as a []uint, returns the optionalDefault
1037 | // value or nil if the value is not a []uint.
1038 | func (v *Value) UintSlice(optionalDefault ...[]uint) []uint {
1039 | if s, ok := v.data.([]uint); ok {
1040 | return s
1041 | }
1042 | if len(optionalDefault) == 1 {
1043 | return optionalDefault[0]
1044 | }
1045 | return nil
1046 | }
1047 |
1048 | // MustUintSlice gets the value as a []uint.
1049 | //
1050 | // Panics if the object is not a []uint.
1051 | func (v *Value) MustUintSlice() []uint {
1052 | return v.data.([]uint)
1053 | }
1054 |
1055 | // IsUint gets whether the object contained is a uint or not.
1056 | func (v *Value) IsUint() bool {
1057 | _, ok := v.data.(uint)
1058 | return ok
1059 | }
1060 |
1061 | // IsUintSlice gets whether the object contained is a []uint or not.
1062 | func (v *Value) IsUintSlice() bool {
1063 | _, ok := v.data.([]uint)
1064 | return ok
1065 | }
1066 |
1067 | // EachUint calls the specified callback for each object
1068 | // in the []uint.
1069 | //
1070 | // Panics if the object is the wrong type.
1071 | func (v *Value) EachUint(callback func(int, uint) bool) *Value {
1072 | for index, val := range v.MustUintSlice() {
1073 | carryon := callback(index, val)
1074 | if !carryon {
1075 | break
1076 | }
1077 | }
1078 | return v
1079 | }
1080 |
1081 | // WhereUint uses the specified decider function to select items
1082 | // from the []uint. The object contained in the result will contain
1083 | // only the selected items.
1084 | func (v *Value) WhereUint(decider func(int, uint) bool) *Value {
1085 | var selected []uint
1086 | v.EachUint(func(index int, val uint) bool {
1087 | shouldSelect := decider(index, val)
1088 | if !shouldSelect {
1089 | selected = append(selected, val)
1090 | }
1091 | return true
1092 | })
1093 | return &Value{data: selected}
1094 | }
1095 |
1096 | // GroupUint uses the specified grouper function to group the items
1097 | // keyed by the return of the grouper. The object contained in the
1098 | // result will contain a map[string][]uint.
1099 | func (v *Value) GroupUint(grouper func(int, uint) string) *Value {
1100 | groups := make(map[string][]uint)
1101 | v.EachUint(func(index int, val uint) bool {
1102 | group := grouper(index, val)
1103 | if _, ok := groups[group]; !ok {
1104 | groups[group] = make([]uint, 0)
1105 | }
1106 | groups[group] = append(groups[group], val)
1107 | return true
1108 | })
1109 | return &Value{data: groups}
1110 | }
1111 |
1112 | // ReplaceUint uses the specified function to replace each uints
1113 | // by iterating each item. The data in the returned result will be a
1114 | // []uint containing the replaced items.
1115 | func (v *Value) ReplaceUint(replacer func(int, uint) uint) *Value {
1116 | arr := v.MustUintSlice()
1117 | replaced := make([]uint, len(arr))
1118 | v.EachUint(func(index int, val uint) bool {
1119 | replaced[index] = replacer(index, val)
1120 | return true
1121 | })
1122 | return &Value{data: replaced}
1123 | }
1124 |
1125 | // CollectUint uses the specified collector function to collect a value
1126 | // for each of the uints in the slice. The data returned will be a
1127 | // []interface{}.
1128 | func (v *Value) CollectUint(collector func(int, uint) interface{}) *Value {
1129 | arr := v.MustUintSlice()
1130 | collected := make([]interface{}, len(arr))
1131 | v.EachUint(func(index int, val uint) bool {
1132 | collected[index] = collector(index, val)
1133 | return true
1134 | })
1135 | return &Value{data: collected}
1136 | }
1137 |
1138 | /*
1139 | Uint8 (uint8 and []uint8)
1140 | */
1141 |
1142 | // Uint8 gets the value as a uint8, returns the optionalDefault
1143 | // value or a system default object if the value is the wrong type.
1144 | func (v *Value) Uint8(optionalDefault ...uint8) uint8 {
1145 | if s, ok := v.data.(uint8); ok {
1146 | return s
1147 | }
1148 | if len(optionalDefault) == 1 {
1149 | return optionalDefault[0]
1150 | }
1151 | return 0
1152 | }
1153 |
1154 | // MustUint8 gets the value as a uint8.
1155 | //
1156 | // Panics if the object is not a uint8.
1157 | func (v *Value) MustUint8() uint8 {
1158 | return v.data.(uint8)
1159 | }
1160 |
1161 | // Uint8Slice gets the value as a []uint8, returns the optionalDefault
1162 | // value or nil if the value is not a []uint8.
1163 | func (v *Value) Uint8Slice(optionalDefault ...[]uint8) []uint8 {
1164 | if s, ok := v.data.([]uint8); ok {
1165 | return s
1166 | }
1167 | if len(optionalDefault) == 1 {
1168 | return optionalDefault[0]
1169 | }
1170 | return nil
1171 | }
1172 |
1173 | // MustUint8Slice gets the value as a []uint8.
1174 | //
1175 | // Panics if the object is not a []uint8.
1176 | func (v *Value) MustUint8Slice() []uint8 {
1177 | return v.data.([]uint8)
1178 | }
1179 |
1180 | // IsUint8 gets whether the object contained is a uint8 or not.
1181 | func (v *Value) IsUint8() bool {
1182 | _, ok := v.data.(uint8)
1183 | return ok
1184 | }
1185 |
1186 | // IsUint8Slice gets whether the object contained is a []uint8 or not.
1187 | func (v *Value) IsUint8Slice() bool {
1188 | _, ok := v.data.([]uint8)
1189 | return ok
1190 | }
1191 |
1192 | // EachUint8 calls the specified callback for each object
1193 | // in the []uint8.
1194 | //
1195 | // Panics if the object is the wrong type.
1196 | func (v *Value) EachUint8(callback func(int, uint8) bool) *Value {
1197 | for index, val := range v.MustUint8Slice() {
1198 | carryon := callback(index, val)
1199 | if !carryon {
1200 | break
1201 | }
1202 | }
1203 | return v
1204 | }
1205 |
1206 | // WhereUint8 uses the specified decider function to select items
1207 | // from the []uint8. The object contained in the result will contain
1208 | // only the selected items.
1209 | func (v *Value) WhereUint8(decider func(int, uint8) bool) *Value {
1210 | var selected []uint8
1211 | v.EachUint8(func(index int, val uint8) bool {
1212 | shouldSelect := decider(index, val)
1213 | if !shouldSelect {
1214 | selected = append(selected, val)
1215 | }
1216 | return true
1217 | })
1218 | return &Value{data: selected}
1219 | }
1220 |
1221 | // GroupUint8 uses the specified grouper function to group the items
1222 | // keyed by the return of the grouper. The object contained in the
1223 | // result will contain a map[string][]uint8.
1224 | func (v *Value) GroupUint8(grouper func(int, uint8) string) *Value {
1225 | groups := make(map[string][]uint8)
1226 | v.EachUint8(func(index int, val uint8) bool {
1227 | group := grouper(index, val)
1228 | if _, ok := groups[group]; !ok {
1229 | groups[group] = make([]uint8, 0)
1230 | }
1231 | groups[group] = append(groups[group], val)
1232 | return true
1233 | })
1234 | return &Value{data: groups}
1235 | }
1236 |
1237 | // ReplaceUint8 uses the specified function to replace each uint8s
1238 | // by iterating each item. The data in the returned result will be a
1239 | // []uint8 containing the replaced items.
1240 | func (v *Value) ReplaceUint8(replacer func(int, uint8) uint8) *Value {
1241 | arr := v.MustUint8Slice()
1242 | replaced := make([]uint8, len(arr))
1243 | v.EachUint8(func(index int, val uint8) bool {
1244 | replaced[index] = replacer(index, val)
1245 | return true
1246 | })
1247 | return &Value{data: replaced}
1248 | }
1249 |
1250 | // CollectUint8 uses the specified collector function to collect a value
1251 | // for each of the uint8s in the slice. The data returned will be a
1252 | // []interface{}.
1253 | func (v *Value) CollectUint8(collector func(int, uint8) interface{}) *Value {
1254 | arr := v.MustUint8Slice()
1255 | collected := make([]interface{}, len(arr))
1256 | v.EachUint8(func(index int, val uint8) bool {
1257 | collected[index] = collector(index, val)
1258 | return true
1259 | })
1260 | return &Value{data: collected}
1261 | }
1262 |
1263 | /*
1264 | Uint16 (uint16 and []uint16)
1265 | */
1266 |
1267 | // Uint16 gets the value as a uint16, returns the optionalDefault
1268 | // value or a system default object if the value is the wrong type.
1269 | func (v *Value) Uint16(optionalDefault ...uint16) uint16 {
1270 | if s, ok := v.data.(uint16); ok {
1271 | return s
1272 | }
1273 | if len(optionalDefault) == 1 {
1274 | return optionalDefault[0]
1275 | }
1276 | return 0
1277 | }
1278 |
1279 | // MustUint16 gets the value as a uint16.
1280 | //
1281 | // Panics if the object is not a uint16.
1282 | func (v *Value) MustUint16() uint16 {
1283 | return v.data.(uint16)
1284 | }
1285 |
1286 | // Uint16Slice gets the value as a []uint16, returns the optionalDefault
1287 | // value or nil if the value is not a []uint16.
1288 | func (v *Value) Uint16Slice(optionalDefault ...[]uint16) []uint16 {
1289 | if s, ok := v.data.([]uint16); ok {
1290 | return s
1291 | }
1292 | if len(optionalDefault) == 1 {
1293 | return optionalDefault[0]
1294 | }
1295 | return nil
1296 | }
1297 |
1298 | // MustUint16Slice gets the value as a []uint16.
1299 | //
1300 | // Panics if the object is not a []uint16.
1301 | func (v *Value) MustUint16Slice() []uint16 {
1302 | return v.data.([]uint16)
1303 | }
1304 |
1305 | // IsUint16 gets whether the object contained is a uint16 or not.
1306 | func (v *Value) IsUint16() bool {
1307 | _, ok := v.data.(uint16)
1308 | return ok
1309 | }
1310 |
1311 | // IsUint16Slice gets whether the object contained is a []uint16 or not.
1312 | func (v *Value) IsUint16Slice() bool {
1313 | _, ok := v.data.([]uint16)
1314 | return ok
1315 | }
1316 |
1317 | // EachUint16 calls the specified callback for each object
1318 | // in the []uint16.
1319 | //
1320 | // Panics if the object is the wrong type.
1321 | func (v *Value) EachUint16(callback func(int, uint16) bool) *Value {
1322 | for index, val := range v.MustUint16Slice() {
1323 | carryon := callback(index, val)
1324 | if !carryon {
1325 | break
1326 | }
1327 | }
1328 | return v
1329 | }
1330 |
1331 | // WhereUint16 uses the specified decider function to select items
1332 | // from the []uint16. The object contained in the result will contain
1333 | // only the selected items.
1334 | func (v *Value) WhereUint16(decider func(int, uint16) bool) *Value {
1335 | var selected []uint16
1336 | v.EachUint16(func(index int, val uint16) bool {
1337 | shouldSelect := decider(index, val)
1338 | if !shouldSelect {
1339 | selected = append(selected, val)
1340 | }
1341 | return true
1342 | })
1343 | return &Value{data: selected}
1344 | }
1345 |
1346 | // GroupUint16 uses the specified grouper function to group the items
1347 | // keyed by the return of the grouper. The object contained in the
1348 | // result will contain a map[string][]uint16.
1349 | func (v *Value) GroupUint16(grouper func(int, uint16) string) *Value {
1350 | groups := make(map[string][]uint16)
1351 | v.EachUint16(func(index int, val uint16) bool {
1352 | group := grouper(index, val)
1353 | if _, ok := groups[group]; !ok {
1354 | groups[group] = make([]uint16, 0)
1355 | }
1356 | groups[group] = append(groups[group], val)
1357 | return true
1358 | })
1359 | return &Value{data: groups}
1360 | }
1361 |
1362 | // ReplaceUint16 uses the specified function to replace each uint16s
1363 | // by iterating each item. The data in the returned result will be a
1364 | // []uint16 containing the replaced items.
1365 | func (v *Value) ReplaceUint16(replacer func(int, uint16) uint16) *Value {
1366 | arr := v.MustUint16Slice()
1367 | replaced := make([]uint16, len(arr))
1368 | v.EachUint16(func(index int, val uint16) bool {
1369 | replaced[index] = replacer(index, val)
1370 | return true
1371 | })
1372 | return &Value{data: replaced}
1373 | }
1374 |
1375 | // CollectUint16 uses the specified collector function to collect a value
1376 | // for each of the uint16s in the slice. The data returned will be a
1377 | // []interface{}.
1378 | func (v *Value) CollectUint16(collector func(int, uint16) interface{}) *Value {
1379 | arr := v.MustUint16Slice()
1380 | collected := make([]interface{}, len(arr))
1381 | v.EachUint16(func(index int, val uint16) bool {
1382 | collected[index] = collector(index, val)
1383 | return true
1384 | })
1385 | return &Value{data: collected}
1386 | }
1387 |
1388 | /*
1389 | Uint32 (uint32 and []uint32)
1390 | */
1391 |
1392 | // Uint32 gets the value as a uint32, returns the optionalDefault
1393 | // value or a system default object if the value is the wrong type.
1394 | func (v *Value) Uint32(optionalDefault ...uint32) uint32 {
1395 | if s, ok := v.data.(uint32); ok {
1396 | return s
1397 | }
1398 | if len(optionalDefault) == 1 {
1399 | return optionalDefault[0]
1400 | }
1401 | return 0
1402 | }
1403 |
1404 | // MustUint32 gets the value as a uint32.
1405 | //
1406 | // Panics if the object is not a uint32.
1407 | func (v *Value) MustUint32() uint32 {
1408 | return v.data.(uint32)
1409 | }
1410 |
1411 | // Uint32Slice gets the value as a []uint32, returns the optionalDefault
1412 | // value or nil if the value is not a []uint32.
1413 | func (v *Value) Uint32Slice(optionalDefault ...[]uint32) []uint32 {
1414 | if s, ok := v.data.([]uint32); ok {
1415 | return s
1416 | }
1417 | if len(optionalDefault) == 1 {
1418 | return optionalDefault[0]
1419 | }
1420 | return nil
1421 | }
1422 |
1423 | // MustUint32Slice gets the value as a []uint32.
1424 | //
1425 | // Panics if the object is not a []uint32.
1426 | func (v *Value) MustUint32Slice() []uint32 {
1427 | return v.data.([]uint32)
1428 | }
1429 |
1430 | // IsUint32 gets whether the object contained is a uint32 or not.
1431 | func (v *Value) IsUint32() bool {
1432 | _, ok := v.data.(uint32)
1433 | return ok
1434 | }
1435 |
1436 | // IsUint32Slice gets whether the object contained is a []uint32 or not.
1437 | func (v *Value) IsUint32Slice() bool {
1438 | _, ok := v.data.([]uint32)
1439 | return ok
1440 | }
1441 |
1442 | // EachUint32 calls the specified callback for each object
1443 | // in the []uint32.
1444 | //
1445 | // Panics if the object is the wrong type.
1446 | func (v *Value) EachUint32(callback func(int, uint32) bool) *Value {
1447 | for index, val := range v.MustUint32Slice() {
1448 | carryon := callback(index, val)
1449 | if !carryon {
1450 | break
1451 | }
1452 | }
1453 | return v
1454 | }
1455 |
1456 | // WhereUint32 uses the specified decider function to select items
1457 | // from the []uint32. The object contained in the result will contain
1458 | // only the selected items.
1459 | func (v *Value) WhereUint32(decider func(int, uint32) bool) *Value {
1460 | var selected []uint32
1461 | v.EachUint32(func(index int, val uint32) bool {
1462 | shouldSelect := decider(index, val)
1463 | if !shouldSelect {
1464 | selected = append(selected, val)
1465 | }
1466 | return true
1467 | })
1468 | return &Value{data: selected}
1469 | }
1470 |
1471 | // GroupUint32 uses the specified grouper function to group the items
1472 | // keyed by the return of the grouper. The object contained in the
1473 | // result will contain a map[string][]uint32.
1474 | func (v *Value) GroupUint32(grouper func(int, uint32) string) *Value {
1475 | groups := make(map[string][]uint32)
1476 | v.EachUint32(func(index int, val uint32) bool {
1477 | group := grouper(index, val)
1478 | if _, ok := groups[group]; !ok {
1479 | groups[group] = make([]uint32, 0)
1480 | }
1481 | groups[group] = append(groups[group], val)
1482 | return true
1483 | })
1484 | return &Value{data: groups}
1485 | }
1486 |
1487 | // ReplaceUint32 uses the specified function to replace each uint32s
1488 | // by iterating each item. The data in the returned result will be a
1489 | // []uint32 containing the replaced items.
1490 | func (v *Value) ReplaceUint32(replacer func(int, uint32) uint32) *Value {
1491 | arr := v.MustUint32Slice()
1492 | replaced := make([]uint32, len(arr))
1493 | v.EachUint32(func(index int, val uint32) bool {
1494 | replaced[index] = replacer(index, val)
1495 | return true
1496 | })
1497 | return &Value{data: replaced}
1498 | }
1499 |
1500 | // CollectUint32 uses the specified collector function to collect a value
1501 | // for each of the uint32s in the slice. The data returned will be a
1502 | // []interface{}.
1503 | func (v *Value) CollectUint32(collector func(int, uint32) interface{}) *Value {
1504 | arr := v.MustUint32Slice()
1505 | collected := make([]interface{}, len(arr))
1506 | v.EachUint32(func(index int, val uint32) bool {
1507 | collected[index] = collector(index, val)
1508 | return true
1509 | })
1510 | return &Value{data: collected}
1511 | }
1512 |
1513 | /*
1514 | Uint64 (uint64 and []uint64)
1515 | */
1516 |
1517 | // Uint64 gets the value as a uint64, returns the optionalDefault
1518 | // value or a system default object if the value is the wrong type.
1519 | func (v *Value) Uint64(optionalDefault ...uint64) uint64 {
1520 | if s, ok := v.data.(uint64); ok {
1521 | return s
1522 | }
1523 | if len(optionalDefault) == 1 {
1524 | return optionalDefault[0]
1525 | }
1526 | return 0
1527 | }
1528 |
1529 | // MustUint64 gets the value as a uint64.
1530 | //
1531 | // Panics if the object is not a uint64.
1532 | func (v *Value) MustUint64() uint64 {
1533 | return v.data.(uint64)
1534 | }
1535 |
1536 | // Uint64Slice gets the value as a []uint64, returns the optionalDefault
1537 | // value or nil if the value is not a []uint64.
1538 | func (v *Value) Uint64Slice(optionalDefault ...[]uint64) []uint64 {
1539 | if s, ok := v.data.([]uint64); ok {
1540 | return s
1541 | }
1542 | if len(optionalDefault) == 1 {
1543 | return optionalDefault[0]
1544 | }
1545 | return nil
1546 | }
1547 |
1548 | // MustUint64Slice gets the value as a []uint64.
1549 | //
1550 | // Panics if the object is not a []uint64.
1551 | func (v *Value) MustUint64Slice() []uint64 {
1552 | return v.data.([]uint64)
1553 | }
1554 |
1555 | // IsUint64 gets whether the object contained is a uint64 or not.
1556 | func (v *Value) IsUint64() bool {
1557 | _, ok := v.data.(uint64)
1558 | return ok
1559 | }
1560 |
1561 | // IsUint64Slice gets whether the object contained is a []uint64 or not.
1562 | func (v *Value) IsUint64Slice() bool {
1563 | _, ok := v.data.([]uint64)
1564 | return ok
1565 | }
1566 |
1567 | // EachUint64 calls the specified callback for each object
1568 | // in the []uint64.
1569 | //
1570 | // Panics if the object is the wrong type.
1571 | func (v *Value) EachUint64(callback func(int, uint64) bool) *Value {
1572 | for index, val := range v.MustUint64Slice() {
1573 | carryon := callback(index, val)
1574 | if !carryon {
1575 | break
1576 | }
1577 | }
1578 | return v
1579 | }
1580 |
1581 | // WhereUint64 uses the specified decider function to select items
1582 | // from the []uint64. The object contained in the result will contain
1583 | // only the selected items.
1584 | func (v *Value) WhereUint64(decider func(int, uint64) bool) *Value {
1585 | var selected []uint64
1586 | v.EachUint64(func(index int, val uint64) bool {
1587 | shouldSelect := decider(index, val)
1588 | if !shouldSelect {
1589 | selected = append(selected, val)
1590 | }
1591 | return true
1592 | })
1593 | return &Value{data: selected}
1594 | }
1595 |
1596 | // GroupUint64 uses the specified grouper function to group the items
1597 | // keyed by the return of the grouper. The object contained in the
1598 | // result will contain a map[string][]uint64.
1599 | func (v *Value) GroupUint64(grouper func(int, uint64) string) *Value {
1600 | groups := make(map[string][]uint64)
1601 | v.EachUint64(func(index int, val uint64) bool {
1602 | group := grouper(index, val)
1603 | if _, ok := groups[group]; !ok {
1604 | groups[group] = make([]uint64, 0)
1605 | }
1606 | groups[group] = append(groups[group], val)
1607 | return true
1608 | })
1609 | return &Value{data: groups}
1610 | }
1611 |
1612 | // ReplaceUint64 uses the specified function to replace each uint64s
1613 | // by iterating each item. The data in the returned result will be a
1614 | // []uint64 containing the replaced items.
1615 | func (v *Value) ReplaceUint64(replacer func(int, uint64) uint64) *Value {
1616 | arr := v.MustUint64Slice()
1617 | replaced := make([]uint64, len(arr))
1618 | v.EachUint64(func(index int, val uint64) bool {
1619 | replaced[index] = replacer(index, val)
1620 | return true
1621 | })
1622 | return &Value{data: replaced}
1623 | }
1624 |
1625 | // CollectUint64 uses the specified collector function to collect a value
1626 | // for each of the uint64s in the slice. The data returned will be a
1627 | // []interface{}.
1628 | func (v *Value) CollectUint64(collector func(int, uint64) interface{}) *Value {
1629 | arr := v.MustUint64Slice()
1630 | collected := make([]interface{}, len(arr))
1631 | v.EachUint64(func(index int, val uint64) bool {
1632 | collected[index] = collector(index, val)
1633 | return true
1634 | })
1635 | return &Value{data: collected}
1636 | }
1637 |
1638 | /*
1639 | Uintptr (uintptr and []uintptr)
1640 | */
1641 |
1642 | // Uintptr gets the value as a uintptr, returns the optionalDefault
1643 | // value or a system default object if the value is the wrong type.
1644 | func (v *Value) Uintptr(optionalDefault ...uintptr) uintptr {
1645 | if s, ok := v.data.(uintptr); ok {
1646 | return s
1647 | }
1648 | if len(optionalDefault) == 1 {
1649 | return optionalDefault[0]
1650 | }
1651 | return 0
1652 | }
1653 |
1654 | // MustUintptr gets the value as a uintptr.
1655 | //
1656 | // Panics if the object is not a uintptr.
1657 | func (v *Value) MustUintptr() uintptr {
1658 | return v.data.(uintptr)
1659 | }
1660 |
1661 | // UintptrSlice gets the value as a []uintptr, returns the optionalDefault
1662 | // value or nil if the value is not a []uintptr.
1663 | func (v *Value) UintptrSlice(optionalDefault ...[]uintptr) []uintptr {
1664 | if s, ok := v.data.([]uintptr); ok {
1665 | return s
1666 | }
1667 | if len(optionalDefault) == 1 {
1668 | return optionalDefault[0]
1669 | }
1670 | return nil
1671 | }
1672 |
1673 | // MustUintptrSlice gets the value as a []uintptr.
1674 | //
1675 | // Panics if the object is not a []uintptr.
1676 | func (v *Value) MustUintptrSlice() []uintptr {
1677 | return v.data.([]uintptr)
1678 | }
1679 |
1680 | // IsUintptr gets whether the object contained is a uintptr or not.
1681 | func (v *Value) IsUintptr() bool {
1682 | _, ok := v.data.(uintptr)
1683 | return ok
1684 | }
1685 |
1686 | // IsUintptrSlice gets whether the object contained is a []uintptr or not.
1687 | func (v *Value) IsUintptrSlice() bool {
1688 | _, ok := v.data.([]uintptr)
1689 | return ok
1690 | }
1691 |
1692 | // EachUintptr calls the specified callback for each object
1693 | // in the []uintptr.
1694 | //
1695 | // Panics if the object is the wrong type.
1696 | func (v *Value) EachUintptr(callback func(int, uintptr) bool) *Value {
1697 | for index, val := range v.MustUintptrSlice() {
1698 | carryon := callback(index, val)
1699 | if !carryon {
1700 | break
1701 | }
1702 | }
1703 | return v
1704 | }
1705 |
1706 | // WhereUintptr uses the specified decider function to select items
1707 | // from the []uintptr. The object contained in the result will contain
1708 | // only the selected items.
1709 | func (v *Value) WhereUintptr(decider func(int, uintptr) bool) *Value {
1710 | var selected []uintptr
1711 | v.EachUintptr(func(index int, val uintptr) bool {
1712 | shouldSelect := decider(index, val)
1713 | if !shouldSelect {
1714 | selected = append(selected, val)
1715 | }
1716 | return true
1717 | })
1718 | return &Value{data: selected}
1719 | }
1720 |
1721 | // GroupUintptr uses the specified grouper function to group the items
1722 | // keyed by the return of the grouper. The object contained in the
1723 | // result will contain a map[string][]uintptr.
1724 | func (v *Value) GroupUintptr(grouper func(int, uintptr) string) *Value {
1725 | groups := make(map[string][]uintptr)
1726 | v.EachUintptr(func(index int, val uintptr) bool {
1727 | group := grouper(index, val)
1728 | if _, ok := groups[group]; !ok {
1729 | groups[group] = make([]uintptr, 0)
1730 | }
1731 | groups[group] = append(groups[group], val)
1732 | return true
1733 | })
1734 | return &Value{data: groups}
1735 | }
1736 |
1737 | // ReplaceUintptr uses the specified function to replace each uintptrs
1738 | // by iterating each item. The data in the returned result will be a
1739 | // []uintptr containing the replaced items.
1740 | func (v *Value) ReplaceUintptr(replacer func(int, uintptr) uintptr) *Value {
1741 | arr := v.MustUintptrSlice()
1742 | replaced := make([]uintptr, len(arr))
1743 | v.EachUintptr(func(index int, val uintptr) bool {
1744 | replaced[index] = replacer(index, val)
1745 | return true
1746 | })
1747 | return &Value{data: replaced}
1748 | }
1749 |
1750 | // CollectUintptr uses the specified collector function to collect a value
1751 | // for each of the uintptrs in the slice. The data returned will be a
1752 | // []interface{}.
1753 | func (v *Value) CollectUintptr(collector func(int, uintptr) interface{}) *Value {
1754 | arr := v.MustUintptrSlice()
1755 | collected := make([]interface{}, len(arr))
1756 | v.EachUintptr(func(index int, val uintptr) bool {
1757 | collected[index] = collector(index, val)
1758 | return true
1759 | })
1760 | return &Value{data: collected}
1761 | }
1762 |
1763 | /*
1764 | Float32 (float32 and []float32)
1765 | */
1766 |
1767 | // Float32 gets the value as a float32, returns the optionalDefault
1768 | // value or a system default object if the value is the wrong type.
1769 | func (v *Value) Float32(optionalDefault ...float32) float32 {
1770 | if s, ok := v.data.(float32); ok {
1771 | return s
1772 | }
1773 | if len(optionalDefault) == 1 {
1774 | return optionalDefault[0]
1775 | }
1776 | return 0
1777 | }
1778 |
1779 | // MustFloat32 gets the value as a float32.
1780 | //
1781 | // Panics if the object is not a float32.
1782 | func (v *Value) MustFloat32() float32 {
1783 | return v.data.(float32)
1784 | }
1785 |
1786 | // Float32Slice gets the value as a []float32, returns the optionalDefault
1787 | // value or nil if the value is not a []float32.
1788 | func (v *Value) Float32Slice(optionalDefault ...[]float32) []float32 {
1789 | if s, ok := v.data.([]float32); ok {
1790 | return s
1791 | }
1792 | if len(optionalDefault) == 1 {
1793 | return optionalDefault[0]
1794 | }
1795 | return nil
1796 | }
1797 |
1798 | // MustFloat32Slice gets the value as a []float32.
1799 | //
1800 | // Panics if the object is not a []float32.
1801 | func (v *Value) MustFloat32Slice() []float32 {
1802 | return v.data.([]float32)
1803 | }
1804 |
1805 | // IsFloat32 gets whether the object contained is a float32 or not.
1806 | func (v *Value) IsFloat32() bool {
1807 | _, ok := v.data.(float32)
1808 | return ok
1809 | }
1810 |
1811 | // IsFloat32Slice gets whether the object contained is a []float32 or not.
1812 | func (v *Value) IsFloat32Slice() bool {
1813 | _, ok := v.data.([]float32)
1814 | return ok
1815 | }
1816 |
1817 | // EachFloat32 calls the specified callback for each object
1818 | // in the []float32.
1819 | //
1820 | // Panics if the object is the wrong type.
1821 | func (v *Value) EachFloat32(callback func(int, float32) bool) *Value {
1822 | for index, val := range v.MustFloat32Slice() {
1823 | carryon := callback(index, val)
1824 | if !carryon {
1825 | break
1826 | }
1827 | }
1828 | return v
1829 | }
1830 |
1831 | // WhereFloat32 uses the specified decider function to select items
1832 | // from the []float32. The object contained in the result will contain
1833 | // only the selected items.
1834 | func (v *Value) WhereFloat32(decider func(int, float32) bool) *Value {
1835 | var selected []float32
1836 | v.EachFloat32(func(index int, val float32) bool {
1837 | shouldSelect := decider(index, val)
1838 | if !shouldSelect {
1839 | selected = append(selected, val)
1840 | }
1841 | return true
1842 | })
1843 | return &Value{data: selected}
1844 | }
1845 |
1846 | // GroupFloat32 uses the specified grouper function to group the items
1847 | // keyed by the return of the grouper. The object contained in the
1848 | // result will contain a map[string][]float32.
1849 | func (v *Value) GroupFloat32(grouper func(int, float32) string) *Value {
1850 | groups := make(map[string][]float32)
1851 | v.EachFloat32(func(index int, val float32) bool {
1852 | group := grouper(index, val)
1853 | if _, ok := groups[group]; !ok {
1854 | groups[group] = make([]float32, 0)
1855 | }
1856 | groups[group] = append(groups[group], val)
1857 | return true
1858 | })
1859 | return &Value{data: groups}
1860 | }
1861 |
1862 | // ReplaceFloat32 uses the specified function to replace each float32s
1863 | // by iterating each item. The data in the returned result will be a
1864 | // []float32 containing the replaced items.
1865 | func (v *Value) ReplaceFloat32(replacer func(int, float32) float32) *Value {
1866 | arr := v.MustFloat32Slice()
1867 | replaced := make([]float32, len(arr))
1868 | v.EachFloat32(func(index int, val float32) bool {
1869 | replaced[index] = replacer(index, val)
1870 | return true
1871 | })
1872 | return &Value{data: replaced}
1873 | }
1874 |
1875 | // CollectFloat32 uses the specified collector function to collect a value
1876 | // for each of the float32s in the slice. The data returned will be a
1877 | // []interface{}.
1878 | func (v *Value) CollectFloat32(collector func(int, float32) interface{}) *Value {
1879 | arr := v.MustFloat32Slice()
1880 | collected := make([]interface{}, len(arr))
1881 | v.EachFloat32(func(index int, val float32) bool {
1882 | collected[index] = collector(index, val)
1883 | return true
1884 | })
1885 | return &Value{data: collected}
1886 | }
1887 |
1888 | /*
1889 | Float64 (float64 and []float64)
1890 | */
1891 |
1892 | // Float64 gets the value as a float64, returns the optionalDefault
1893 | // value or a system default object if the value is the wrong type.
1894 | func (v *Value) Float64(optionalDefault ...float64) float64 {
1895 | if s, ok := v.data.(float64); ok {
1896 | return s
1897 | }
1898 | if len(optionalDefault) == 1 {
1899 | return optionalDefault[0]
1900 | }
1901 | return 0
1902 | }
1903 |
1904 | // MustFloat64 gets the value as a float64.
1905 | //
1906 | // Panics if the object is not a float64.
1907 | func (v *Value) MustFloat64() float64 {
1908 | return v.data.(float64)
1909 | }
1910 |
1911 | // Float64Slice gets the value as a []float64, returns the optionalDefault
1912 | // value or nil if the value is not a []float64.
1913 | func (v *Value) Float64Slice(optionalDefault ...[]float64) []float64 {
1914 | if s, ok := v.data.([]float64); ok {
1915 | return s
1916 | }
1917 | if len(optionalDefault) == 1 {
1918 | return optionalDefault[0]
1919 | }
1920 | return nil
1921 | }
1922 |
1923 | // MustFloat64Slice gets the value as a []float64.
1924 | //
1925 | // Panics if the object is not a []float64.
1926 | func (v *Value) MustFloat64Slice() []float64 {
1927 | return v.data.([]float64)
1928 | }
1929 |
1930 | // IsFloat64 gets whether the object contained is a float64 or not.
1931 | func (v *Value) IsFloat64() bool {
1932 | _, ok := v.data.(float64)
1933 | return ok
1934 | }
1935 |
1936 | // IsFloat64Slice gets whether the object contained is a []float64 or not.
1937 | func (v *Value) IsFloat64Slice() bool {
1938 | _, ok := v.data.([]float64)
1939 | return ok
1940 | }
1941 |
1942 | // EachFloat64 calls the specified callback for each object
1943 | // in the []float64.
1944 | //
1945 | // Panics if the object is the wrong type.
1946 | func (v *Value) EachFloat64(callback func(int, float64) bool) *Value {
1947 | for index, val := range v.MustFloat64Slice() {
1948 | carryon := callback(index, val)
1949 | if !carryon {
1950 | break
1951 | }
1952 | }
1953 | return v
1954 | }
1955 |
1956 | // WhereFloat64 uses the specified decider function to select items
1957 | // from the []float64. The object contained in the result will contain
1958 | // only the selected items.
1959 | func (v *Value) WhereFloat64(decider func(int, float64) bool) *Value {
1960 | var selected []float64
1961 | v.EachFloat64(func(index int, val float64) bool {
1962 | shouldSelect := decider(index, val)
1963 | if !shouldSelect {
1964 | selected = append(selected, val)
1965 | }
1966 | return true
1967 | })
1968 | return &Value{data: selected}
1969 | }
1970 |
1971 | // GroupFloat64 uses the specified grouper function to group the items
1972 | // keyed by the return of the grouper. The object contained in the
1973 | // result will contain a map[string][]float64.
1974 | func (v *Value) GroupFloat64(grouper func(int, float64) string) *Value {
1975 | groups := make(map[string][]float64)
1976 | v.EachFloat64(func(index int, val float64) bool {
1977 | group := grouper(index, val)
1978 | if _, ok := groups[group]; !ok {
1979 | groups[group] = make([]float64, 0)
1980 | }
1981 | groups[group] = append(groups[group], val)
1982 | return true
1983 | })
1984 | return &Value{data: groups}
1985 | }
1986 |
1987 | // ReplaceFloat64 uses the specified function to replace each float64s
1988 | // by iterating each item. The data in the returned result will be a
1989 | // []float64 containing the replaced items.
1990 | func (v *Value) ReplaceFloat64(replacer func(int, float64) float64) *Value {
1991 | arr := v.MustFloat64Slice()
1992 | replaced := make([]float64, len(arr))
1993 | v.EachFloat64(func(index int, val float64) bool {
1994 | replaced[index] = replacer(index, val)
1995 | return true
1996 | })
1997 | return &Value{data: replaced}
1998 | }
1999 |
2000 | // CollectFloat64 uses the specified collector function to collect a value
2001 | // for each of the float64s in the slice. The data returned will be a
2002 | // []interface{}.
2003 | func (v *Value) CollectFloat64(collector func(int, float64) interface{}) *Value {
2004 | arr := v.MustFloat64Slice()
2005 | collected := make([]interface{}, len(arr))
2006 | v.EachFloat64(func(index int, val float64) bool {
2007 | collected[index] = collector(index, val)
2008 | return true
2009 | })
2010 | return &Value{data: collected}
2011 | }
2012 |
2013 | /*
2014 | Complex64 (complex64 and []complex64)
2015 | */
2016 |
2017 | // Complex64 gets the value as a complex64, returns the optionalDefault
2018 | // value or a system default object if the value is the wrong type.
2019 | func (v *Value) Complex64(optionalDefault ...complex64) complex64 {
2020 | if s, ok := v.data.(complex64); ok {
2021 | return s
2022 | }
2023 | if len(optionalDefault) == 1 {
2024 | return optionalDefault[0]
2025 | }
2026 | return 0
2027 | }
2028 |
2029 | // MustComplex64 gets the value as a complex64.
2030 | //
2031 | // Panics if the object is not a complex64.
2032 | func (v *Value) MustComplex64() complex64 {
2033 | return v.data.(complex64)
2034 | }
2035 |
2036 | // Complex64Slice gets the value as a []complex64, returns the optionalDefault
2037 | // value or nil if the value is not a []complex64.
2038 | func (v *Value) Complex64Slice(optionalDefault ...[]complex64) []complex64 {
2039 | if s, ok := v.data.([]complex64); ok {
2040 | return s
2041 | }
2042 | if len(optionalDefault) == 1 {
2043 | return optionalDefault[0]
2044 | }
2045 | return nil
2046 | }
2047 |
2048 | // MustComplex64Slice gets the value as a []complex64.
2049 | //
2050 | // Panics if the object is not a []complex64.
2051 | func (v *Value) MustComplex64Slice() []complex64 {
2052 | return v.data.([]complex64)
2053 | }
2054 |
2055 | // IsComplex64 gets whether the object contained is a complex64 or not.
2056 | func (v *Value) IsComplex64() bool {
2057 | _, ok := v.data.(complex64)
2058 | return ok
2059 | }
2060 |
2061 | // IsComplex64Slice gets whether the object contained is a []complex64 or not.
2062 | func (v *Value) IsComplex64Slice() bool {
2063 | _, ok := v.data.([]complex64)
2064 | return ok
2065 | }
2066 |
2067 | // EachComplex64 calls the specified callback for each object
2068 | // in the []complex64.
2069 | //
2070 | // Panics if the object is the wrong type.
2071 | func (v *Value) EachComplex64(callback func(int, complex64) bool) *Value {
2072 | for index, val := range v.MustComplex64Slice() {
2073 | carryon := callback(index, val)
2074 | if !carryon {
2075 | break
2076 | }
2077 | }
2078 | return v
2079 | }
2080 |
2081 | // WhereComplex64 uses the specified decider function to select items
2082 | // from the []complex64. The object contained in the result will contain
2083 | // only the selected items.
2084 | func (v *Value) WhereComplex64(decider func(int, complex64) bool) *Value {
2085 | var selected []complex64
2086 | v.EachComplex64(func(index int, val complex64) bool {
2087 | shouldSelect := decider(index, val)
2088 | if !shouldSelect {
2089 | selected = append(selected, val)
2090 | }
2091 | return true
2092 | })
2093 | return &Value{data: selected}
2094 | }
2095 |
2096 | // GroupComplex64 uses the specified grouper function to group the items
2097 | // keyed by the return of the grouper. The object contained in the
2098 | // result will contain a map[string][]complex64.
2099 | func (v *Value) GroupComplex64(grouper func(int, complex64) string) *Value {
2100 | groups := make(map[string][]complex64)
2101 | v.EachComplex64(func(index int, val complex64) bool {
2102 | group := grouper(index, val)
2103 | if _, ok := groups[group]; !ok {
2104 | groups[group] = make([]complex64, 0)
2105 | }
2106 | groups[group] = append(groups[group], val)
2107 | return true
2108 | })
2109 | return &Value{data: groups}
2110 | }
2111 |
2112 | // ReplaceComplex64 uses the specified function to replace each complex64s
2113 | // by iterating each item. The data in the returned result will be a
2114 | // []complex64 containing the replaced items.
2115 | func (v *Value) ReplaceComplex64(replacer func(int, complex64) complex64) *Value {
2116 | arr := v.MustComplex64Slice()
2117 | replaced := make([]complex64, len(arr))
2118 | v.EachComplex64(func(index int, val complex64) bool {
2119 | replaced[index] = replacer(index, val)
2120 | return true
2121 | })
2122 | return &Value{data: replaced}
2123 | }
2124 |
2125 | // CollectComplex64 uses the specified collector function to collect a value
2126 | // for each of the complex64s in the slice. The data returned will be a
2127 | // []interface{}.
2128 | func (v *Value) CollectComplex64(collector func(int, complex64) interface{}) *Value {
2129 | arr := v.MustComplex64Slice()
2130 | collected := make([]interface{}, len(arr))
2131 | v.EachComplex64(func(index int, val complex64) bool {
2132 | collected[index] = collector(index, val)
2133 | return true
2134 | })
2135 | return &Value{data: collected}
2136 | }
2137 |
2138 | /*
2139 | Complex128 (complex128 and []complex128)
2140 | */
2141 |
2142 | // Complex128 gets the value as a complex128, returns the optionalDefault
2143 | // value or a system default object if the value is the wrong type.
2144 | func (v *Value) Complex128(optionalDefault ...complex128) complex128 {
2145 | if s, ok := v.data.(complex128); ok {
2146 | return s
2147 | }
2148 | if len(optionalDefault) == 1 {
2149 | return optionalDefault[0]
2150 | }
2151 | return 0
2152 | }
2153 |
2154 | // MustComplex128 gets the value as a complex128.
2155 | //
2156 | // Panics if the object is not a complex128.
2157 | func (v *Value) MustComplex128() complex128 {
2158 | return v.data.(complex128)
2159 | }
2160 |
2161 | // Complex128Slice gets the value as a []complex128, returns the optionalDefault
2162 | // value or nil if the value is not a []complex128.
2163 | func (v *Value) Complex128Slice(optionalDefault ...[]complex128) []complex128 {
2164 | if s, ok := v.data.([]complex128); ok {
2165 | return s
2166 | }
2167 | if len(optionalDefault) == 1 {
2168 | return optionalDefault[0]
2169 | }
2170 | return nil
2171 | }
2172 |
2173 | // MustComplex128Slice gets the value as a []complex128.
2174 | //
2175 | // Panics if the object is not a []complex128.
2176 | func (v *Value) MustComplex128Slice() []complex128 {
2177 | return v.data.([]complex128)
2178 | }
2179 |
2180 | // IsComplex128 gets whether the object contained is a complex128 or not.
2181 | func (v *Value) IsComplex128() bool {
2182 | _, ok := v.data.(complex128)
2183 | return ok
2184 | }
2185 |
2186 | // IsComplex128Slice gets whether the object contained is a []complex128 or not.
2187 | func (v *Value) IsComplex128Slice() bool {
2188 | _, ok := v.data.([]complex128)
2189 | return ok
2190 | }
2191 |
2192 | // EachComplex128 calls the specified callback for each object
2193 | // in the []complex128.
2194 | //
2195 | // Panics if the object is the wrong type.
2196 | func (v *Value) EachComplex128(callback func(int, complex128) bool) *Value {
2197 | for index, val := range v.MustComplex128Slice() {
2198 | carryon := callback(index, val)
2199 | if !carryon {
2200 | break
2201 | }
2202 | }
2203 | return v
2204 | }
2205 |
2206 | // WhereComplex128 uses the specified decider function to select items
2207 | // from the []complex128. The object contained in the result will contain
2208 | // only the selected items.
2209 | func (v *Value) WhereComplex128(decider func(int, complex128) bool) *Value {
2210 | var selected []complex128
2211 | v.EachComplex128(func(index int, val complex128) bool {
2212 | shouldSelect := decider(index, val)
2213 | if !shouldSelect {
2214 | selected = append(selected, val)
2215 | }
2216 | return true
2217 | })
2218 | return &Value{data: selected}
2219 | }
2220 |
2221 | // GroupComplex128 uses the specified grouper function to group the items
2222 | // keyed by the return of the grouper. The object contained in the
2223 | // result will contain a map[string][]complex128.
2224 | func (v *Value) GroupComplex128(grouper func(int, complex128) string) *Value {
2225 | groups := make(map[string][]complex128)
2226 | v.EachComplex128(func(index int, val complex128) bool {
2227 | group := grouper(index, val)
2228 | if _, ok := groups[group]; !ok {
2229 | groups[group] = make([]complex128, 0)
2230 | }
2231 | groups[group] = append(groups[group], val)
2232 | return true
2233 | })
2234 | return &Value{data: groups}
2235 | }
2236 |
2237 | // ReplaceComplex128 uses the specified function to replace each complex128s
2238 | // by iterating each item. The data in the returned result will be a
2239 | // []complex128 containing the replaced items.
2240 | func (v *Value) ReplaceComplex128(replacer func(int, complex128) complex128) *Value {
2241 | arr := v.MustComplex128Slice()
2242 | replaced := make([]complex128, len(arr))
2243 | v.EachComplex128(func(index int, val complex128) bool {
2244 | replaced[index] = replacer(index, val)
2245 | return true
2246 | })
2247 | return &Value{data: replaced}
2248 | }
2249 |
2250 | // CollectComplex128 uses the specified collector function to collect a value
2251 | // for each of the complex128s in the slice. The data returned will be a
2252 | // []interface{}.
2253 | func (v *Value) CollectComplex128(collector func(int, complex128) interface{}) *Value {
2254 | arr := v.MustComplex128Slice()
2255 | collected := make([]interface{}, len(arr))
2256 | v.EachComplex128(func(index int, val complex128) bool {
2257 | collected[index] = collector(index, val)
2258 | return true
2259 | })
2260 | return &Value{data: collected}
2261 | }
2262 |
--------------------------------------------------------------------------------
/type_specific_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/objx"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | /*
12 | Tests for MSI (map[string]interface{} and []map[string]interface{})
13 | */
14 | func TestMSI(t *testing.T) {
15 | val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
16 | m := objx.Map{"value": val, "nothing": nil}
17 | mVal := map[string]interface{}{"value": val, "nothing": nil}
18 |
19 | assert.Equal(t, mVal, m.Value().MSI())
20 | assert.Equal(t, val, m.Get("value").MSI())
21 | assert.Equal(t, mVal, m.Value().MustMSI())
22 | assert.Equal(t, val, m.Get("value").MustMSI())
23 | assert.Equal(t, map[string]interface{}(nil), m.Get("nothing").MSI())
24 | assert.Equal(t, val, m.Get("nothing").MSI(map[string]interface{}{"name": "Tyler"}))
25 | assert.Panics(t, func() {
26 | m.Get("age").MustMSI()
27 | })
28 | }
29 |
30 | func TestMSISlice(t *testing.T) {
31 | val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
32 | m := objx.Map{
33 | "value": []map[string]interface{}{val},
34 | "value2": []objx.Map{val},
35 | "value3": []interface{}{val},
36 | "nothing": nil,
37 | }
38 |
39 | assert.Equal(t, val, m.Get("value").MSISlice()[0])
40 | assert.Equal(t, val, m.Get("value2").MSISlice()[0])
41 | assert.Equal(t, val, m.Get("value3").MSISlice()[0])
42 | assert.Equal(t, val, m.Get("value").MustMSISlice()[0])
43 | assert.Equal(t, val, m.Get("value2").MustMSISlice()[0])
44 | assert.Equal(t, val, m.Get("value3").MustMSISlice()[0])
45 | assert.Equal(t, []map[string]interface{}(nil), m.Get("nothing").MSISlice())
46 | assert.Equal(t, val, m.Get("nothing").MSISlice([]map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"})})[0])
47 | assert.Panics(t, func() {
48 | m.Get("nothing").MustMSISlice()
49 | })
50 |
51 | o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`)
52 | assert.Equal(t, float64(9879), o.Get("d").MustMSISlice()[0]["id"])
53 | assert.Equal(t, 1, len(o.Get("d").MSISlice()))
54 |
55 | i := objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`)
56 | assert.Nil(t, i.Get("d").MSISlice())
57 | }
58 |
59 | func TestIsMSI(t *testing.T) {
60 | m := objx.Map{"data": map[string]interface{}(map[string]interface{}{"name": "Tyler"})}
61 |
62 | assert.True(t, m.Get("data").IsMSI())
63 | assert.True(t, m.Value().IsMSI())
64 | }
65 |
66 | func TestIsMSISlice(t *testing.T) {
67 | val := map[string]interface{}(map[string]interface{}{"name": "Tyler"})
68 | m := objx.Map{"data": []map[string]interface{}{val}, "data2": []objx.Map{val}}
69 |
70 | assert.True(t, m.Get("data").IsMSISlice())
71 | assert.True(t, m.Get("data2").IsMSISlice())
72 |
73 | o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`)
74 | assert.True(t, o.Has("d"))
75 | assert.True(t, o.Get("d").IsMSISlice())
76 |
77 | o = objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`)
78 | assert.True(t, o.Has("d"))
79 | assert.False(t, o.Get("d").IsMSISlice())
80 | }
81 |
82 | func TestEachMSI(t *testing.T) {
83 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
84 | count := 0
85 | replacedVals := make([]map[string]interface{}, 0)
86 | assert.Equal(t, m.Get("data"), m.Get("data").EachMSI(func(i int, val map[string]interface{}) bool {
87 | count++
88 | replacedVals = append(replacedVals, val)
89 |
90 | // abort early
91 | return i != 2
92 | }))
93 |
94 | m2 := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}}
95 | assert.Equal(t, m2.Get("data"), m2.Get("data").EachMSI(func(i int, val map[string]interface{}) bool {
96 | count++
97 | replacedVals = append(replacedVals, val)
98 |
99 | // abort early
100 | return i != 2
101 | }))
102 |
103 | assert.Equal(t, count, 6)
104 | assert.Equal(t, replacedVals[0], m.Get("data").MustMSISlice()[0])
105 | assert.Equal(t, replacedVals[1], m.Get("data").MustMSISlice()[1])
106 | assert.Equal(t, replacedVals[2], m.Get("data").MustMSISlice()[2])
107 | assert.Equal(t, replacedVals[3], m2.Get("data").MustMSISlice()[0])
108 | assert.Equal(t, replacedVals[4], m2.Get("data").MustMSISlice()[1])
109 | assert.Equal(t, replacedVals[5], m2.Get("data").MustMSISlice()[2])
110 | }
111 |
112 | func TestWhereMSI(t *testing.T) {
113 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
114 |
115 | selected := m.Get("data").WhereMSI(func(i int, val map[string]interface{}) bool {
116 | return i%2 == 0
117 | }).MustMSISlice()
118 |
119 | assert.Equal(t, 3, len(selected))
120 | }
121 |
122 | func TestWhereMSI2(t *testing.T) {
123 | m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}}
124 |
125 | selected := m.Get("data").WhereMSI(func(i int, val map[string]interface{}) bool {
126 | return i%2 == 0
127 | }).MustMSISlice()
128 |
129 | assert.Equal(t, 2, len(selected))
130 | }
131 |
132 | func TestGroupMSI(t *testing.T) {
133 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
134 |
135 | grouped := m.Get("data").GroupMSI(func(i int, val map[string]interface{}) string {
136 | return fmt.Sprintf("%v", i%2 == 0)
137 | }).Data().(map[string][]map[string]interface{})
138 |
139 | assert.Equal(t, 2, len(grouped))
140 | assert.Equal(t, 3, len(grouped["true"]))
141 | assert.Equal(t, 3, len(grouped["false"]))
142 | }
143 |
144 | func TestGroupMSI2(t *testing.T) {
145 | m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}}
146 |
147 | grouped := m.Get("data").GroupMSI(func(i int, val map[string]interface{}) string {
148 | return fmt.Sprintf("%v", i%2 == 0)
149 | }).Data().(map[string][]map[string]interface{})
150 |
151 | assert.Equal(t, 2, len(grouped))
152 | assert.Equal(t, 3, len(grouped["true"]))
153 | assert.Equal(t, 2, len(grouped["false"]))
154 | }
155 |
156 | func TestReplaceMSI(t *testing.T) {
157 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
158 | rawArr := m.Get("data").MustMSISlice()
159 |
160 | replaced := m.Get("data").ReplaceMSI(func(index int, val map[string]interface{}) map[string]interface{} {
161 | if index < len(rawArr)-1 {
162 | return rawArr[index+1]
163 | }
164 | return rawArr[0]
165 | })
166 | replacedArr := replaced.MustMSISlice()
167 |
168 | if assert.Equal(t, 6, len(replacedArr)) {
169 | assert.Equal(t, replacedArr[0], rawArr[1])
170 | assert.Equal(t, replacedArr[1], rawArr[2])
171 | assert.Equal(t, replacedArr[2], rawArr[3])
172 | assert.Equal(t, replacedArr[3], rawArr[4])
173 | assert.Equal(t, replacedArr[4], rawArr[5])
174 | assert.Equal(t, replacedArr[5], rawArr[0])
175 | }
176 | }
177 |
178 | func TestReplaceMSI2(t *testing.T) {
179 | m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}}
180 | rawArr := m.Get("data").MustMSISlice()
181 |
182 | replaced := m.Get("data").ReplaceMSI(func(index int, val map[string]interface{}) map[string]interface{} {
183 | if index < len(rawArr)-1 {
184 | return rawArr[index+1]
185 | }
186 | return rawArr[0]
187 | })
188 | replacedArr := replaced.MustMSISlice()
189 |
190 | if assert.Equal(t, 5, len(replacedArr)) {
191 | assert.Equal(t, replacedArr[0], rawArr[1])
192 | assert.Equal(t, replacedArr[1], rawArr[2])
193 | assert.Equal(t, replacedArr[2], rawArr[3])
194 | assert.Equal(t, replacedArr[3], rawArr[4])
195 | assert.Equal(t, replacedArr[4], rawArr[0])
196 | }
197 | }
198 |
199 | func TestCollectMSI(t *testing.T) {
200 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
201 |
202 | collected := m.Get("data").CollectMSI(func(index int, val map[string]interface{}) interface{} {
203 | return index
204 | })
205 | collectedArr := collected.MustInterSlice()
206 |
207 | if assert.Equal(t, 6, len(collectedArr)) {
208 | assert.Equal(t, collectedArr[0], 0)
209 | assert.Equal(t, collectedArr[1], 1)
210 | assert.Equal(t, collectedArr[2], 2)
211 | assert.Equal(t, collectedArr[3], 3)
212 | assert.Equal(t, collectedArr[4], 4)
213 | assert.Equal(t, collectedArr[5], 5)
214 | }
215 | }
216 |
217 | func TestCollectMSI2(t *testing.T) {
218 | m := objx.Map{"data": []objx.Map{{"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}, {"name": "Taylor"}}}
219 |
220 | collected := m.Get("data").CollectMSI(func(index int, val map[string]interface{}) interface{} {
221 | return index
222 | })
223 | collectedArr := collected.MustInterSlice()
224 |
225 | if assert.Equal(t, 5, len(collectedArr)) {
226 | assert.Equal(t, collectedArr[0], 0)
227 | assert.Equal(t, collectedArr[1], 1)
228 | assert.Equal(t, collectedArr[2], 2)
229 | assert.Equal(t, collectedArr[3], 3)
230 | assert.Equal(t, collectedArr[4], 4)
231 | }
232 | }
233 |
234 | /*
235 | Tests for ObjxMap ((objx.Map) and [](objx.Map))
236 | */
237 | func TestObjxMap(t *testing.T) {
238 | val := (objx.Map)(objx.New(1))
239 | m := objx.Map{"value": val, "value2": map[string]interface{}{"name": "Taylor"}, "nothing": nil}
240 | valMSI := objx.Map{"name": "Taylor"}
241 |
242 | assert.Equal(t, val, m.Get("value").ObjxMap())
243 | assert.Equal(t, valMSI, m.Get("value2").ObjxMap())
244 | assert.Equal(t, val, m.Get("value").MustObjxMap())
245 | assert.Equal(t, valMSI, m.Get("value2").MustObjxMap())
246 | assert.Equal(t, (objx.Map)(objx.New(nil)), m.Get("nothing").ObjxMap())
247 | assert.Equal(t, val, m.Get("nothing").ObjxMap(objx.New(1)))
248 | assert.Panics(t, func() {
249 | m.Get("age").MustObjxMap()
250 | })
251 | }
252 |
253 | func TestObjxMapSlice(t *testing.T) {
254 | val := (objx.Map)(objx.New(1))
255 | m := objx.Map{
256 | "value": [](objx.Map){val},
257 | "value2": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Taylor"})},
258 | "value3": []interface{}{val},
259 | "value4": []interface{}{map[string]interface{}(map[string]interface{}{"name": "Taylor"})},
260 | "nothing": nil,
261 | }
262 | valMSI := objx.Map{"name": "Taylor"}
263 |
264 | assert.Equal(t, val, m.Get("value").ObjxMapSlice()[0])
265 | assert.Equal(t, valMSI, m.Get("value2").ObjxMapSlice()[0])
266 | assert.Equal(t, val, m.Get("value3").ObjxMapSlice()[0])
267 | assert.Equal(t, valMSI, m.Get("value4").ObjxMapSlice()[0])
268 | assert.Equal(t, val, m.Get("value").MustObjxMapSlice()[0])
269 | assert.Equal(t, valMSI, m.Get("value2").MustObjxMapSlice()[0])
270 | assert.Equal(t, val, m.Get("value3").MustObjxMapSlice()[0])
271 | assert.Equal(t, valMSI, m.Get("value4").MustObjxMapSlice()[0])
272 | assert.Equal(t, [](objx.Map)(nil), m.Get("nothing").ObjxMapSlice())
273 | assert.Equal(t, val, m.Get("nothing").ObjxMapSlice([](objx.Map){(objx.Map)(objx.New(1))})[0])
274 | assert.Panics(t, func() {
275 | m.Get("nothing").MustObjxMapSlice()
276 | })
277 |
278 | o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`)
279 | assert.Equal(t, 9879, o.Get("d").MustObjxMapSlice()[0].Get("id").Int())
280 | assert.Equal(t, 1, len(o.Get("d").ObjxMapSlice()))
281 |
282 | i := objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`)
283 | assert.Nil(t, i.Get("d").ObjxMapSlice())
284 | }
285 |
286 | func TestIsObjxMap(t *testing.T) {
287 | m := objx.Map{"data": (objx.Map)(objx.New(1)), "data2": map[string]interface{}{"name": "Taylor"}}
288 |
289 | assert.True(t, m.Get("data").IsObjxMap())
290 | assert.True(t, m.Get("data2").IsObjxMap())
291 | }
292 |
293 | func TestIsObjxMapSlice(t *testing.T) {
294 | m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1))}, "data2": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Taylor"})}}
295 |
296 | assert.True(t, m.Get("data").IsObjxMapSlice())
297 | assert.True(t, m.Get("data2").IsObjxMapSlice())
298 |
299 | o := objx.MustFromJSON(`{"d":[{"author":{"displayName":"DemoUser3","id":2},"classes":null,"id":9879,"v":{"code":"","created":"2013-09-19T09:38:50+02:00","published":"0001-01-01T00:00:00Z","updated":"2013-09-19T09:38:50+02:00"}}],"s":200}`)
300 | assert.True(t, o.Has("d"))
301 | assert.True(t, o.Get("d").IsObjxMapSlice())
302 |
303 | // Valid json but not MSI slice
304 | o = objx.MustFromJSON(`{"d":[{"author":"abc"},[1]]}`)
305 | assert.True(t, o.Has("d"))
306 | assert.False(t, o.Get("d").IsObjxMapSlice())
307 | }
308 |
309 | func TestEachObjxMap(t *testing.T) {
310 | m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}}
311 | count := 0
312 | replacedVals := make([](objx.Map), 0)
313 | assert.Equal(t, m.Get("data"), m.Get("data").EachObjxMap(func(i int, val objx.Map) bool {
314 | count++
315 | replacedVals = append(replacedVals, val)
316 |
317 | // abort early
318 | return i != 2
319 | }))
320 |
321 | m2 := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
322 | assert.Equal(t, m2.Get("data"), m2.Get("data").EachObjxMap(func(i int, val objx.Map) bool {
323 | count++
324 | replacedVals = append(replacedVals, val)
325 |
326 | // abort early
327 | return i != 2
328 | }))
329 |
330 | assert.Equal(t, count, 6)
331 | assert.Equal(t, replacedVals[0], m.Get("data").MustObjxMapSlice()[0])
332 | assert.Equal(t, replacedVals[1], m.Get("data").MustObjxMapSlice()[1])
333 | assert.Equal(t, replacedVals[2], m.Get("data").MustObjxMapSlice()[2])
334 | assert.Equal(t, replacedVals[3], m2.Get("data").MustObjxMapSlice()[0])
335 | assert.Equal(t, replacedVals[4], m2.Get("data").MustObjxMapSlice()[1])
336 | assert.Equal(t, replacedVals[5], m2.Get("data").MustObjxMapSlice()[2])
337 | }
338 |
339 | func TestWhereObjxMap(t *testing.T) {
340 | m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}}
341 |
342 | selected := m.Get("data").WhereObjxMap(func(i int, val objx.Map) bool {
343 | return i%2 == 0
344 | }).MustObjxMapSlice()
345 |
346 | assert.Equal(t, 3, len(selected))
347 | }
348 |
349 | func TestWhereObjxMap2(t *testing.T) {
350 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
351 |
352 | selected := m.Get("data").WhereObjxMap(func(i int, val objx.Map) bool {
353 | return i%2 == 0
354 | }).MustObjxMapSlice()
355 |
356 | assert.Equal(t, 2, len(selected))
357 | }
358 |
359 | func TestGroupObjxMap(t *testing.T) {
360 | m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}}
361 |
362 | grouped := m.Get("data").GroupObjxMap(func(i int, val objx.Map) string {
363 | return fmt.Sprintf("%v", i%2 == 0)
364 | }).Data().(map[string][](objx.Map))
365 |
366 | assert.Equal(t, 2, len(grouped))
367 | assert.Equal(t, 3, len(grouped["true"]))
368 | assert.Equal(t, 3, len(grouped["false"]))
369 | }
370 |
371 | func TestGroupObjxMap2(t *testing.T) {
372 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
373 |
374 | grouped := m.Get("data").GroupObjxMap(func(i int, val objx.Map) string {
375 | return fmt.Sprintf("%v", i%2 == 0)
376 | }).Data().(map[string][](objx.Map))
377 |
378 | assert.Equal(t, 2, len(grouped))
379 | assert.Equal(t, 3, len(grouped["true"]))
380 | assert.Equal(t, 2, len(grouped["false"]))
381 | }
382 |
383 | func TestReplaceObjxMap(t *testing.T) {
384 | m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}}
385 | rawArr := m.Get("data").MustObjxMapSlice()
386 |
387 | replaced := m.Get("data").ReplaceObjxMap(func(index int, val objx.Map) objx.Map {
388 | if index < len(rawArr)-1 {
389 | return rawArr[index+1]
390 | }
391 | return rawArr[0]
392 | })
393 | replacedArr := replaced.MustObjxMapSlice()
394 |
395 | if assert.Equal(t, 6, len(replacedArr)) {
396 | assert.Equal(t, replacedArr[0], rawArr[1])
397 | assert.Equal(t, replacedArr[1], rawArr[2])
398 | assert.Equal(t, replacedArr[2], rawArr[3])
399 | assert.Equal(t, replacedArr[3], rawArr[4])
400 | assert.Equal(t, replacedArr[4], rawArr[5])
401 | assert.Equal(t, replacedArr[5], rawArr[0])
402 | }
403 | }
404 |
405 | func TestReplaceObjxMap2(t *testing.T) {
406 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
407 | rawArr := m.Get("data").MustObjxMapSlice()
408 |
409 | replaced := m.Get("data").ReplaceObjxMap(func(index int, val objx.Map) objx.Map {
410 | if index < len(rawArr)-1 {
411 | return rawArr[index+1]
412 | }
413 | return rawArr[0]
414 | })
415 | replacedArr := replaced.MustObjxMapSlice()
416 |
417 | if assert.Equal(t, 5, len(replacedArr)) {
418 | assert.Equal(t, replacedArr[0], rawArr[1])
419 | assert.Equal(t, replacedArr[1], rawArr[2])
420 | assert.Equal(t, replacedArr[2], rawArr[3])
421 | assert.Equal(t, replacedArr[3], rawArr[4])
422 | assert.Equal(t, replacedArr[4], rawArr[0])
423 | }
424 | }
425 |
426 | func TestCollectObjxMap(t *testing.T) {
427 | m := objx.Map{"data": [](objx.Map){(objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1)), (objx.Map)(objx.New(1))}}
428 |
429 | collected := m.Get("data").CollectObjxMap(func(index int, val objx.Map) interface{} {
430 | return index
431 | })
432 | collectedArr := collected.MustInterSlice()
433 |
434 | if assert.Equal(t, 6, len(collectedArr)) {
435 | assert.Equal(t, collectedArr[0], 0)
436 | assert.Equal(t, collectedArr[1], 1)
437 | assert.Equal(t, collectedArr[2], 2)
438 | assert.Equal(t, collectedArr[3], 3)
439 | assert.Equal(t, collectedArr[4], 4)
440 | assert.Equal(t, collectedArr[5], 5)
441 | }
442 | }
443 |
444 | func TestCollectObjxMap2(t *testing.T) {
445 | m := objx.Map{"data": []map[string]interface{}{map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"}), map[string]interface{}(map[string]interface{}{"name": "Tyler"})}}
446 |
447 | collected := m.Get("data").CollectObjxMap(func(index int, val objx.Map) interface{} {
448 | return index
449 | })
450 | collectedArr := collected.MustInterSlice()
451 |
452 | if assert.Equal(t, 5, len(collectedArr)) {
453 | assert.Equal(t, collectedArr[0], 0)
454 | assert.Equal(t, collectedArr[1], 1)
455 | assert.Equal(t, collectedArr[2], 2)
456 | assert.Equal(t, collectedArr[3], 3)
457 | assert.Equal(t, collectedArr[4], 4)
458 | }
459 | }
460 |
--------------------------------------------------------------------------------
/value.go:
--------------------------------------------------------------------------------
1 | package objx
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | )
7 |
8 | // Value provides methods for extracting interface{} data in various
9 | // types.
10 | type Value struct {
11 | // data contains the raw data being managed by this Value
12 | data interface{}
13 | }
14 |
15 | // Data returns the raw data contained by this Value
16 | func (v *Value) Data() interface{} {
17 | return v.data
18 | }
19 |
20 | // String returns the value always as a string
21 | func (v *Value) String() string {
22 | switch {
23 | case v.IsNil():
24 | return ""
25 | case v.IsStr():
26 | return v.Str()
27 | case v.IsBool():
28 | return strconv.FormatBool(v.Bool())
29 | case v.IsFloat32():
30 | return strconv.FormatFloat(float64(v.Float32()), 'f', -1, 32)
31 | case v.IsFloat64():
32 | return strconv.FormatFloat(v.Float64(), 'f', -1, 64)
33 | case v.IsInt():
34 | return strconv.FormatInt(int64(v.Int()), 10)
35 | case v.IsInt8():
36 | return strconv.FormatInt(int64(v.Int8()), 10)
37 | case v.IsInt16():
38 | return strconv.FormatInt(int64(v.Int16()), 10)
39 | case v.IsInt32():
40 | return strconv.FormatInt(int64(v.Int32()), 10)
41 | case v.IsInt64():
42 | return strconv.FormatInt(v.Int64(), 10)
43 | case v.IsUint():
44 | return strconv.FormatUint(uint64(v.Uint()), 10)
45 | case v.IsUint8():
46 | return strconv.FormatUint(uint64(v.Uint8()), 10)
47 | case v.IsUint16():
48 | return strconv.FormatUint(uint64(v.Uint16()), 10)
49 | case v.IsUint32():
50 | return strconv.FormatUint(uint64(v.Uint32()), 10)
51 | case v.IsUint64():
52 | return strconv.FormatUint(v.Uint64(), 10)
53 | }
54 | return fmt.Sprintf("%#v", v.Data())
55 | }
56 |
57 | // StringSlice returns the value always as a []string
58 | func (v *Value) StringSlice(optionalDefault ...[]string) []string {
59 | switch {
60 | case v.IsStrSlice():
61 | return v.MustStrSlice()
62 | case v.IsBoolSlice():
63 | slice := v.MustBoolSlice()
64 | vals := make([]string, len(slice))
65 | for i, iv := range slice {
66 | vals[i] = strconv.FormatBool(iv)
67 | }
68 | return vals
69 | case v.IsFloat32Slice():
70 | slice := v.MustFloat32Slice()
71 | vals := make([]string, len(slice))
72 | for i, iv := range slice {
73 | vals[i] = strconv.FormatFloat(float64(iv), 'f', -1, 32)
74 | }
75 | return vals
76 | case v.IsFloat64Slice():
77 | slice := v.MustFloat64Slice()
78 | vals := make([]string, len(slice))
79 | for i, iv := range slice {
80 | vals[i] = strconv.FormatFloat(iv, 'f', -1, 64)
81 | }
82 | return vals
83 | case v.IsIntSlice():
84 | slice := v.MustIntSlice()
85 | vals := make([]string, len(slice))
86 | for i, iv := range slice {
87 | vals[i] = strconv.FormatInt(int64(iv), 10)
88 | }
89 | return vals
90 | case v.IsInt8Slice():
91 | slice := v.MustInt8Slice()
92 | vals := make([]string, len(slice))
93 | for i, iv := range slice {
94 | vals[i] = strconv.FormatInt(int64(iv), 10)
95 | }
96 | return vals
97 | case v.IsInt16Slice():
98 | slice := v.MustInt16Slice()
99 | vals := make([]string, len(slice))
100 | for i, iv := range slice {
101 | vals[i] = strconv.FormatInt(int64(iv), 10)
102 | }
103 | return vals
104 | case v.IsInt32Slice():
105 | slice := v.MustInt32Slice()
106 | vals := make([]string, len(slice))
107 | for i, iv := range slice {
108 | vals[i] = strconv.FormatInt(int64(iv), 10)
109 | }
110 | return vals
111 | case v.IsInt64Slice():
112 | slice := v.MustInt64Slice()
113 | vals := make([]string, len(slice))
114 | for i, iv := range slice {
115 | vals[i] = strconv.FormatInt(iv, 10)
116 | }
117 | return vals
118 | case v.IsUintSlice():
119 | slice := v.MustUintSlice()
120 | vals := make([]string, len(slice))
121 | for i, iv := range slice {
122 | vals[i] = strconv.FormatUint(uint64(iv), 10)
123 | }
124 | return vals
125 | case v.IsUint8Slice():
126 | slice := v.MustUint8Slice()
127 | vals := make([]string, len(slice))
128 | for i, iv := range slice {
129 | vals[i] = strconv.FormatUint(uint64(iv), 10)
130 | }
131 | return vals
132 | case v.IsUint16Slice():
133 | slice := v.MustUint16Slice()
134 | vals := make([]string, len(slice))
135 | for i, iv := range slice {
136 | vals[i] = strconv.FormatUint(uint64(iv), 10)
137 | }
138 | return vals
139 | case v.IsUint32Slice():
140 | slice := v.MustUint32Slice()
141 | vals := make([]string, len(slice))
142 | for i, iv := range slice {
143 | vals[i] = strconv.FormatUint(uint64(iv), 10)
144 | }
145 | return vals
146 | case v.IsUint64Slice():
147 | slice := v.MustUint64Slice()
148 | vals := make([]string, len(slice))
149 | for i, iv := range slice {
150 | vals[i] = strconv.FormatUint(iv, 10)
151 | }
152 | return vals
153 | }
154 | if len(optionalDefault) == 1 {
155 | return optionalDefault[0]
156 | }
157 |
158 | return []string{}
159 | }
160 |
--------------------------------------------------------------------------------
/value_test.go:
--------------------------------------------------------------------------------
1 | package objx_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/objx"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestStringTypeString(t *testing.T) {
11 | m := objx.Map{
12 | "string": "foo",
13 | }
14 |
15 | assert.Equal(t, "foo", m.Get("string").String())
16 | }
17 |
18 | func TestStringTypeBool(t *testing.T) {
19 | m := objx.Map{
20 | "bool": true,
21 | }
22 |
23 | assert.Equal(t, "true", m.Get("bool").String())
24 | }
25 |
26 | func TestStringTypeInt(t *testing.T) {
27 | m := objx.Map{
28 | "int": int(1),
29 | "int8": int8(8),
30 | "int16": int16(16),
31 | "int32": int32(32),
32 | "int64": int64(64),
33 | }
34 |
35 | assert.Equal(t, "1", m.Get("int").String())
36 | assert.Equal(t, "8", m.Get("int8").String())
37 | assert.Equal(t, "16", m.Get("int16").String())
38 | assert.Equal(t, "32", m.Get("int32").String())
39 | assert.Equal(t, "64", m.Get("int64").String())
40 | }
41 |
42 | func TestStringTypeUint(t *testing.T) {
43 | m := objx.Map{
44 | "uint": uint(1),
45 | "uint8": uint8(8),
46 | "uint16": uint16(16),
47 | "uint32": uint32(32),
48 | "uint64": uint64(64),
49 | }
50 |
51 | assert.Equal(t, "1", m.Get("uint").String())
52 | assert.Equal(t, "8", m.Get("uint8").String())
53 | assert.Equal(t, "16", m.Get("uint16").String())
54 | assert.Equal(t, "32", m.Get("uint32").String())
55 | assert.Equal(t, "64", m.Get("uint64").String())
56 | }
57 |
58 | func TestStringTypeFloat(t *testing.T) {
59 | m := objx.Map{
60 | "float32": float32(32.32),
61 | "float64": float64(64.64),
62 | }
63 |
64 | assert.Equal(t, "32.32", m.Get("float32").String())
65 | assert.Equal(t, "64.64", m.Get("float64").String())
66 | }
67 |
68 | func TestStringTypeOther(t *testing.T) {
69 | m := objx.Map{
70 | "other": []string{"foo", "bar"},
71 | "nilValue": nil,
72 | }
73 |
74 | assert.Equal(t, "[]string{\"foo\", \"bar\"}", m.Get("other").String())
75 | assert.Equal(t, "", m.Get("nilValue").String())
76 | }
77 |
78 | func TestStringSliceTypeString(t *testing.T) {
79 | m := objx.Map{
80 | "string": []string{"foo", "bar"},
81 | }
82 |
83 | assert.Equal(t, []string{"foo", "bar"}, m.Get("string").StringSlice())
84 | }
85 |
86 | func TestStringSliceTypeBool(t *testing.T) {
87 | m := objx.Map{
88 | "bool": []bool{true, false},
89 | }
90 |
91 | assert.Equal(t, []string{"true", "false"}, m.Get("bool").StringSlice())
92 | }
93 |
94 | func TestStringSliceTypeInt(t *testing.T) {
95 | m := objx.Map{
96 | "int": []int{1, 2},
97 | "int8": []int8{8, 9},
98 | "int16": []int16{16, 17},
99 | "int32": []int32{32, 33},
100 | "int64": []int64{64, 65},
101 | }
102 |
103 | assert.Equal(t, []string{"1", "2"}, m.Get("int").StringSlice())
104 | assert.Equal(t, []string{"8", "9"}, m.Get("int8").StringSlice())
105 | assert.Equal(t, []string{"16", "17"}, m.Get("int16").StringSlice())
106 | assert.Equal(t, []string{"32", "33"}, m.Get("int32").StringSlice())
107 | assert.Equal(t, []string{"64", "65"}, m.Get("int64").StringSlice())
108 | }
109 |
110 | func TestStringSliceTypeUint(t *testing.T) {
111 | m := objx.Map{
112 | "uint": []uint{1, 2},
113 | "uint8": []uint8{8, 9},
114 | "uint16": []uint16{16, 17},
115 | "uint32": []uint32{32, 33},
116 | "uint64": []uint64{64, 65},
117 | }
118 |
119 | assert.Equal(t, []string{"1", "2"}, m.Get("uint").StringSlice())
120 | assert.Equal(t, []string{"8", "9"}, m.Get("uint8").StringSlice())
121 | assert.Equal(t, []string{"16", "17"}, m.Get("uint16").StringSlice())
122 | assert.Equal(t, []string{"32", "33"}, m.Get("uint32").StringSlice())
123 | assert.Equal(t, []string{"64", "65"}, m.Get("uint64").StringSlice())
124 | }
125 |
126 | func TestStringSliceTypeFloat(t *testing.T) {
127 | m := objx.Map{
128 | "float32": []float32{32.32, 33.33},
129 | "float64": []float64{64.64, 65.65},
130 | }
131 |
132 | assert.Equal(t, []string{"32.32", "33.33"}, m.Get("float32").StringSlice())
133 | assert.Equal(t, []string{"64.64", "65.65"}, m.Get("float64").StringSlice())
134 | }
135 |
136 | func TestStringSliceTypeOther(t *testing.T) {
137 | m := objx.Map{
138 | "other": "foo",
139 | }
140 |
141 | assert.Equal(t, []string{}, m.Get("other").StringSlice())
142 | assert.Equal(t, []string{"bar"}, m.Get("other").StringSlice([]string{"bar"}))
143 | }
144 |
--------------------------------------------------------------------------------