From aae177ae1a39c6a8a23d5e9d556951dda14aadb2 Mon Sep 17 00:00:00 2001 From: Rafael Date: Thu, 16 Apr 2020 23:19:47 +1200 Subject: [PATCH] feat (payload) Get() accept paths.like.this[15] --- context/contextFactory.go | 2 +- moleculer.go | 1 + payload/payload.go | 69 +++++++++++++++++++++++++++++++++++- payload/payload_test.go | 28 +++++++++++++++ serializer/jsonSerializer.go | 11 ++++++ 5 files changed, 109 insertions(+), 2 deletions(-) diff --git a/context/contextFactory.go b/context/contextFactory.go index 7e517bfa..6ee06243 100644 --- a/context/contextFactory.go +++ b/context/contextFactory.go @@ -75,7 +75,7 @@ func (context *Context) BrokerDelegates() *moleculer.BrokerDelegates { return context.broker } -// ChildActionContext : create a chiold context for a specific action call. +// ChildActionContext : create a child context for a specific action call. func (context *Context) ChildActionContext(actionName string, params moleculer.Payload, opts ...moleculer.Options) moleculer.BrokerContext { parentContext := context meta := parentContext.meta diff --git a/moleculer.go b/moleculer.go index 27372586..d9b98e8e 100644 --- a/moleculer.go +++ b/moleculer.go @@ -52,6 +52,7 @@ type Payload interface { Time() time.Time TimeArray() []time.Time Array() []Payload + At(index int) Payload Len() int Get(path string, defaultValue ...interface{}) Payload //Only return a payload containing only the field specified diff --git a/payload/payload.go b/payload/payload.go index f97be936..e32a2be1 100644 --- a/payload/payload.go +++ b/payload/payload.go @@ -3,6 +3,7 @@ package payload import ( "errors" "fmt" + "regexp" "sort" "strconv" "strings" @@ -216,6 +217,17 @@ func (p *RawPayload) First() moleculer.Payload { return New(nil) } +//At returns the item at the given index +func (p *RawPayload) At(index int) moleculer.Payload { + if transformer := ArrayTransformer(&p.source); transformer != nil { + l := transformer.InterfaceArray(&p.source) + if index >= 0 && index < len(l) { + return New(l[index]) + } + } + return nil +} + func (p *RawPayload) Array() []moleculer.Payload { if transformer := ArrayTransformer(&p.source); transformer != nil { source := transformer.InterfaceArray(&p.source) @@ -439,7 +451,62 @@ func (p *RawPayload) mapGet(path string) (interface{}, bool) { return nil, false } -func (p *RawPayload) Get(path string, defaultValue ...interface{}) moleculer.Payload { +func isPath(s string) bool { + return strings.Contains(s, ".") +} + +var indexedKey = regexp.MustCompile(`^(\w+)\[(\d+)\]$`) + +//isIndexed checks if key is indexed e.g. stage[0] +func isIndexed(s string) bool { + return indexedKey.MatchString(s) +} + +func splitIndex(s string) (key string, index int) { + parts := indexedKey.FindStringSubmatch(s) + key = parts[1] + index, _ = strconv.Atoi(parts[2]) + return key, index +} + +func (p *RawPayload) Get(s string, defaultValue ...interface{}) moleculer.Payload { + //check if is a path of key + if isPath(s) { + if defaultValue != nil { + return p.getPath(s, defaultValue) + } + return p.getPath(s) + } + if isIndexed(s) { + k, index := splitIndex(s) + var v moleculer.Payload + if defaultValue != nil { + v = p.getKey(k, defaultValue) + } else { + v = p.getKey(k) + } + return v.At(index) + } + if defaultValue != nil { + return p.getKey(s, defaultValue) + } + return p.getKey(s) +} + +//getPath get a value using a path expression e.g. address.country.code +// it also accepts indexed lists like address.options[0].label +func (p *RawPayload) getPath(path string, defaultValue ...interface{}) moleculer.Payload { + parts := strings.Split(path, ".") + k := parts[0] + v := p.Get(k, defaultValue) + for i := 1; i < len(parts); i++ { + k = parts[i] + v = v.Get(k, defaultValue) + } + return v +} + +func (p *RawPayload) getKey(path string, defaultValue ...interface{}) moleculer.Payload { if value, ok := p.mapGet(path); ok { return New(value) } diff --git a/payload/payload_test.go b/payload/payload_test.go index 288f0bf5..c5d765be 100644 --- a/payload/payload_test.go +++ b/payload/payload_test.go @@ -347,4 +347,32 @@ var _ = Describe("Payload", func() { Expect(snap.SnapshotMulti("PayloadError() .Error()", p.Error())).ShouldNot(HaveOccurred()) Expect(snap.SnapshotMulti("PayloadError() .ErrorPayload()", p.ErrorPayload())).ShouldNot(HaveOccurred()) }) + + type M map[string]interface{} + It("should deal field paths name.subname...", func() { + p := New(M{ + "name": "John", + "lastname": "Snow", + "address": M{ + "street": "jonny ave", + "country": M{ + "code": "NZ", + "name": "New Zealand", + }, + "options": []M{ + M{ + "label": "item 1", + }, + M{ + "label": "item 2", + }, + }, + }, + }) + Expect(p.Get("name").String()).Should(Equal("John")) + Expect(p.Get("address.street").String()).Should(Equal("jonny ave")) + Expect(p.Get("address.country.code").String()).Should(Equal("NZ")) + Expect(p.Get("address.options[0].label").String()).Should(Equal("item 1")) + Expect(p.Get("address.options[1].label").String()).Should(Equal("item 2")) + }) }) diff --git a/serializer/jsonSerializer.go b/serializer/jsonSerializer.go index fd8ed838..c0d3cd61 100644 --- a/serializer/jsonSerializer.go +++ b/serializer/jsonSerializer.go @@ -498,6 +498,17 @@ func (payload JSONPayload) TimeArray() []time.Time { return nil } +func (payload JSONPayload) At(index int) moleculer.Payload { + if payload.IsArray() { + source := payload.result.Array() + if index >= 0 && index < len(source) { + item := source[index] + return JSONPayload{item, payload.logger} + } + } + return nil +} + func (payload JSONPayload) Array() []moleculer.Payload { if payload.IsArray() { source := payload.result.Array()