summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vmihailenco/msgpack/v5/decode_query.go')
-rw-r--r--vendor/github.com/vmihailenco/msgpack/v5/decode_query.go158
1 files changed, 158 insertions, 0 deletions
diff --git a/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go b/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go
new file mode 100644
index 00000000..c302ed1f
--- /dev/null
+++ b/vendor/github.com/vmihailenco/msgpack/v5/decode_query.go
@@ -0,0 +1,158 @@
+package msgpack
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/vmihailenco/msgpack/v5/msgpcode"
+)
+
+type queryResult struct {
+ query string
+ key string
+ hasAsterisk bool
+
+ values []interface{}
+}
+
+func (q *queryResult) nextKey() {
+ ind := strings.IndexByte(q.query, '.')
+ if ind == -1 {
+ q.key = q.query
+ q.query = ""
+ return
+ }
+ q.key = q.query[:ind]
+ q.query = q.query[ind+1:]
+}
+
+// Query extracts data specified by the query from the msgpack stream skipping
+// any other data. Query consists of map keys and array indexes separated with dot,
+// e.g. key1.0.key2.
+func (d *Decoder) Query(query string) ([]interface{}, error) {
+ res := queryResult{
+ query: query,
+ }
+ if err := d.query(&res); err != nil {
+ return nil, err
+ }
+ return res.values, nil
+}
+
+func (d *Decoder) query(q *queryResult) error {
+ q.nextKey()
+ if q.key == "" {
+ v, err := d.decodeInterfaceCond()
+ if err != nil {
+ return err
+ }
+ q.values = append(q.values, v)
+ return nil
+ }
+
+ code, err := d.PeekCode()
+ if err != nil {
+ return err
+ }
+
+ switch {
+ case code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code):
+ err = d.queryMapKey(q)
+ case code == msgpcode.Array16 || code == msgpcode.Array32 || msgpcode.IsFixedArray(code):
+ err = d.queryArrayIndex(q)
+ default:
+ err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key)
+ }
+ return err
+}
+
+func (d *Decoder) queryMapKey(q *queryResult) error {
+ n, err := d.DecodeMapLen()
+ if err != nil {
+ return err
+ }
+ if n == -1 {
+ return nil
+ }
+
+ for i := 0; i < n; i++ {
+ key, err := d.decodeStringTemp()
+ if err != nil {
+ return err
+ }
+
+ if key == q.key {
+ if err := d.query(q); err != nil {
+ return err
+ }
+ if q.hasAsterisk {
+ return d.skipNext((n - i - 1) * 2)
+ }
+ return nil
+ }
+
+ if err := d.Skip(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (d *Decoder) queryArrayIndex(q *queryResult) error {
+ n, err := d.DecodeArrayLen()
+ if err != nil {
+ return err
+ }
+ if n == -1 {
+ return nil
+ }
+
+ if q.key == "*" {
+ q.hasAsterisk = true
+
+ query := q.query
+ for i := 0; i < n; i++ {
+ q.query = query
+ if err := d.query(q); err != nil {
+ return err
+ }
+ }
+
+ q.hasAsterisk = false
+ return nil
+ }
+
+ ind, err := strconv.Atoi(q.key)
+ if err != nil {
+ return err
+ }
+
+ for i := 0; i < n; i++ {
+ if i == ind {
+ if err := d.query(q); err != nil {
+ return err
+ }
+ if q.hasAsterisk {
+ return d.skipNext(n - i - 1)
+ }
+ return nil
+ }
+
+ if err := d.Skip(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (d *Decoder) skipNext(n int) error {
+ for i := 0; i < n; i++ {
+ if err := d.Skip(); err != nil {
+ return err
+ }
+ }
+ return nil
+}