Skip to content
This repository was archived by the owner on Jun 12, 2026. It is now read-only.

Commit 9a28925

Browse files
author
lianghuan
committed
fix(flatten): improve storage key handling
1 parent 0abdb96 commit 9a28925

2 files changed

Lines changed: 85 additions & 9 deletions

File tree

flatten/store.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,14 +167,20 @@ func (s *PropertiesStorage) Value(key string) (string, bool) {
167167
func (s *PropertiesStorage) MapKeys(key string, result map[string]struct{}) bool {
168168
var found bool
169169
for k := range s.data {
170-
str, ok := strings.CutPrefix(k, key)
171-
if !ok || str == "" || str[0] != '.' {
172-
continue
173-
}
174-
if str = str[1:]; str == "" {
175-
continue
170+
var str string
171+
if key == "" {
172+
str = k
173+
} else {
174+
var ok bool
175+
str, ok = strings.CutPrefix(k, key)
176+
if !ok || str == "" || str[0] != '.' {
177+
continue
178+
}
179+
if str = str[1:]; str == "" {
180+
continue
181+
}
176182
}
177-
if i := strings.Index(str, "."); i > 0 {
183+
if i := strings.IndexAny(str, ".["); i > 0 {
178184
result[str[:i]] = struct{}{}
179185
found = true
180186
} else if i < 0 {
@@ -234,7 +240,16 @@ func (s *PrefixedStorage) MapKeys(key string, result map[string]struct{}) bool {
234240

235241
// SliceEntries retrieves slice entries with the configured prefix.
236242
func (s *PrefixedStorage) SliceEntries(key string, result map[string]string) bool {
237-
return s.Storage.SliceEntries(s.Prefix+key, result)
243+
m := make(map[string]string)
244+
if !s.Storage.SliceEntries(s.Prefix+key, m) {
245+
return false
246+
}
247+
for k, v := range m {
248+
if str, ok := strings.CutPrefix(k, s.Prefix); ok {
249+
result[str] = v
250+
}
251+
}
252+
return true
238253
}
239254

240255
const (
@@ -418,6 +433,9 @@ func (s *LayeredStorage) MapKeys(key string, result map[string]struct{}) bool {
418433
func (s *LayeredStorage) SliceEntries(key string, result map[string]string) bool {
419434
for _, arr := range s.layers {
420435
for _, source := range arr {
436+
if _, ok := source.Value(key); ok {
437+
return false
438+
}
421439
if source.SliceEntries(key, result) {
422440
return true
423441
}

flatten/store_test.go

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,37 @@ func TestPropertiesStorage(t *testing.T) {
183183
assert.Map(t, result).ContainsKeys([]string{"http", "grpc"})
184184
})
185185

186+
t.Run("MapKeys with nested slice", func(t *testing.T) {
187+
p := NewProperties(map[string]string{
188+
"server.users[0].name": "Alice",
189+
"server.users[1].name": "Bob",
190+
})
191+
s := NewPropertiesStorage(p)
192+
193+
result := make(map[string]struct{})
194+
found := s.MapKeys("server", result)
195+
196+
assert.That(t, found).True()
197+
assert.Map(t, result).ContainsKeys([]string{"users"})
198+
assert.That(t, len(result)).Equal(1)
199+
})
200+
201+
t.Run("MapKeys with empty key collects root keys", func(t *testing.T) {
202+
p := NewProperties(map[string]string{
203+
"server.host": "localhost",
204+
"users[0].name": "Alice",
205+
"debug": "true",
206+
})
207+
s := NewPropertiesStorage(p)
208+
209+
result := make(map[string]struct{})
210+
found := s.MapKeys("", result)
211+
212+
assert.That(t, found).True()
213+
assert.Map(t, result).ContainsKeys([]string{"server", "users", "debug"})
214+
assert.That(t, len(result)).Equal(3)
215+
})
216+
186217
t.Run("MapKeys with non-existing prefix", func(t *testing.T) {
187218
p := NewProperties(map[string]string{
188219
"server.host": "localhost",
@@ -313,7 +344,10 @@ func TestPrefixedStorage(t *testing.T) {
313344
found := s.SliceEntries("users", result)
314345

315346
assert.That(t, found).True()
316-
assert.Map(t, result).ContainsKeys([]string{"prod.users[0].name", "prod.users[0].age"})
347+
assert.Map(t, result).ContainsKeys([]string{"users[0].name", "users[0].age"})
348+
assert.Map(t, result).NotContainsKeys([]string{"prod.users[0].name", "prod.users[0].age"})
349+
assert.That(t, result["users[0].name"]).Equal("Alice")
350+
assert.That(t, result["users[0].age"]).Equal("30")
317351
})
318352

319353
t.Run("Empty prefix", func(t *testing.T) {
@@ -503,6 +537,30 @@ func TestLayeredStorage(t *testing.T) {
503537
assert.That(t, result["users[0].name"]).Equal("Override")
504538
})
505539

540+
t.Run("SliceEntries stops at higher priority scalar value", func(t *testing.T) {
541+
s := &LayeredStorage{}
542+
543+
defaultLayer := NewProperties(map[string]string{
544+
"users[0]": "Default",
545+
"users[1]": "User1",
546+
})
547+
s.AddStorage(StorageDefault, NewPropertiesStorage(defaultLayer), "default")
548+
549+
cmdlineLayer := NewProperties(map[string]string{
550+
"users": "Override1,Override2",
551+
})
552+
s.AddStorage(StorageCommandLine, NewPropertiesStorage(cmdlineLayer), "cmdline")
553+
554+
result := make(map[string]string)
555+
found := s.SliceEntries("users", result)
556+
557+
assert.That(t, found).False()
558+
assert.That(t, len(result)).Equal(0)
559+
val, ok := s.Value("users")
560+
assert.That(t, ok).True()
561+
assert.That(t, val).Equal("Override1,Override2")
562+
})
563+
506564
t.Run("multiple sources in same layer", func(t *testing.T) {
507565
s := &LayeredStorage{}
508566

0 commit comments

Comments
 (0)