Skip to content

Commit

Permalink
ensure serialized schemas have ordered keys
Browse files Browse the repository at this point in the history
  • Loading branch information
aacebo committed Oct 8, 2024
1 parent 4d0d1bb commit ad14083
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 18 deletions.
27 changes: 21 additions & 6 deletions any.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"errors"
"fmt"
"reflect"
"slices"

"github.com/aacebo/owl/ordered_map"
)

type AnySchema struct {
Expand All @@ -29,12 +32,24 @@ func (self AnySchema) Type() string {
}

func (self *AnySchema) Rule(key string, value any, rule RuleFn) *AnySchema {
self.rules = append(self.rules, Rule{
Key: key,
Value: value,
Resolve: rule,
i := slices.IndexFunc(self.rules, func(rule Rule) bool {
return rule.Key == key
})

if i > -1 {
self.rules[i] = Rule{
Key: key,
Value: value,
Resolve: rule,
}
} else {
self.rules = append(self.rules, Rule{
Key: key,
Value: value,
Resolve: rule,
})
}

return self
}

Expand Down Expand Up @@ -70,10 +85,10 @@ func (self *AnySchema) Enum(values ...any) *AnySchema {
}

func (self AnySchema) MarshalJSON() ([]byte, error) {
data := map[string]any{}
data := ordered_map.Map[string, any]{}

for _, rule := range self.rules {
data[rule.Key] = rule.Value
data.Set(rule.Key, rule.Value)
}

return json.Marshal(data)
Expand Down
4 changes: 2 additions & 2 deletions any_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ func Test_Any(t *testing.T) {
t.Error(err)
}

if string(b) != `{"enum":[1,true,"hi"],"required":true,"type":"any"}` {
if string(b) != `{"type":"any","enum":[1,true,"hi"],"required":true}` {
t.Errorf(
"expected `%s`, received `%s`",
`{"enum":[1,true,"hi"],"required":true,"type":"any"}`,
`{"type":"any","enum":[1,true,"hi"],"required":true}`,
string(b),
)
}
Expand Down
4 changes: 2 additions & 2 deletions array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ func Test_Array(t *testing.T) {
t.Error(err)
}

if string(b) != `{"items":{"type":"string"},"required":true,"type":"array[string]"}` {
if string(b) != `{"type":"array[string]","items":{"type":"string"},"required":true}` {
t.Errorf(
"expected `%s`, received `%s`",
`{"items":{"type":"string"},"required":true,"type":"array[string]"}`,
`{"type":"array[string]","items":{"type":"string"},"required":true}`,
string(b),
)
}
Expand Down
4 changes: 2 additions & 2 deletions float_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ func Test_Float(t *testing.T) {
t.Error(err)
}

if string(b) != `{"max":5,"min":1,"type":"float"}` {
if string(b) != `{"type":"float","min":1,"max":5}` {
t.Errorf(
"expected `%s`, received `%s`",
`{"max":5,"min":1,"type":"float"}`,
`{"type":"float","min":1,"max":5}`,
string(b),
)
}
Expand Down
4 changes: 2 additions & 2 deletions int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ func Test_Int(t *testing.T) {
t.Error(err)
}

if string(b) != `{"max":5,"min":1,"type":"int"}` {
if string(b) != `{"type":"int","min":1,"max":5}` {
t.Errorf(
"expected `%s`, received `%s`",
`{"max":5,"min":1,"type":"int"}`,
`{"type":"int","min":1,"max":5}`,
string(b),
)
}
Expand Down
4 changes: 2 additions & 2 deletions object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,10 @@ func Test_Object(t *testing.T) {
t.Error(err)
}

if string(b) != `{"fields":{"password":{"max":20,"min":5,"required":true,"type":"string"},"staySignedIn":{"type":"bool"},"username":{"regex":"^[0-9a-zA-Z_-]+$","required":true,"type":"string"}},"type":"object"}` {
if string(b) != `{"type":"object","fields":{"password":{"type":"string","min":5,"max":20,"required":true},"staySignedIn":{"type":"bool"},"username":{"type":"string","regex":"^[0-9a-zA-Z_-]+$","required":true}}}` {
t.Errorf(
"expected `%s`, received `%s`",
`{"fields":{"password":{"max":20,"min":5,"required":true,"type":"string"},"staySignedIn":{"type":"bool"},"username":{"regex":"^[0-9a-zA-Z_-]+$","required":true,"type":"string"}},"type":"object"}`,
`{"type":"object","fields":{"password":{"type":"string","min":5,"max":20,"required":true},"staySignedIn":{"type":"bool"},"username":{"type":"string","regex":"^[0-9a-zA-Z_-]+$","required":true}}}`,
string(b),
)
}
Expand Down
44 changes: 44 additions & 0 deletions ordered_map/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ordered_map

import (
"bytes"
"encoding/json"
"fmt"
)

type Item[K comparable, V any] struct {
Key K
Value V
}

type Map[K comparable, V any] []Item[K, V]

func (self *Map[K, V]) Set(key K, value V) {
*self = append(*self, Item[K, V]{
Key: key,
Value: value,
})
}

func (self Map[K, V]) MarshalJSON() ([]byte, error) {
buf := &bytes.Buffer{}
buf.Write([]byte{'{'})

for i, item := range self {
b, err := json.Marshal(item.Value)

if err != nil {
return nil, err
}

buf.WriteString(fmt.Sprintf("%q:", fmt.Sprintf("%v", item.Key)))
buf.Write(b)

if i < len(self)-1 {
buf.Write([]byte{','})
}
}

buf.Write([]byte{'}'})
return buf.Bytes(), nil
}
4 changes: 2 additions & 2 deletions string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,10 @@ func Test_String(t *testing.T) {
t.Error(err)
}

if string(b) != `{"email":true,"max":5,"min":1,"type":"string"}` {
if string(b) != `{"type":"string","min":1,"max":5,"email":true}` {
t.Errorf(
"expected `%s`, received `%s`",
`{"email":true,"max":5,"min":1,"type":"string"}`,
`{"type":"string","min":1,"max":5,"email":true}`,
string(b),
)
}
Expand Down

0 comments on commit ad14083

Please sign in to comment.