Skip to content

Commit 4d764f5

Browse files
committed
Fix Infer, rename tests, add benchmark
- `Infer` can now handle numeric values that are not `float64` - Add tests for `Infer` in addition to `InferStrings` - Remove test with only one case and move to table - Rename tests (drop `JTD`) - Add benchmarking to see effects on new type switch Fixes #8
1 parent b717747 commit 4d764f5

File tree

3 files changed

+100
-24
lines changed

3 files changed

+100
-24
lines changed

inferred_number.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,34 @@ func (i *InferredNumber) ContainedBy(nt NumType) bool {
134134

135135
return minValue <= i.Min && maxValue >= i.Max
136136
}
137+
138+
func anyAsNumber(value any) (float64, bool) {
139+
switch v := value.(type) {
140+
case float64:
141+
return v, true
142+
case float32:
143+
return float64(v), true
144+
case uint:
145+
return float64(v), true
146+
case uint8:
147+
return float64(v), true
148+
case uint16:
149+
return float64(v), true
150+
case uint32:
151+
return float64(v), true
152+
case uint64:
153+
return float64(v), true
154+
case int:
155+
return float64(v), true
156+
case int8:
157+
return float64(v), true
158+
case int16:
159+
return float64(v), true
160+
case int32:
161+
return float64(v), true
162+
case int64:
163+
return float64(v), true
164+
default:
165+
return 0.0, false
166+
}
167+
}

inferred_schema.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,7 @@ func (i *InferredSchema) Infer(value any, hints Hints) *InferredSchema {
8383
return &InferredSchema{SchemaType: SchemaTypeBoolean}
8484
}
8585

86-
// In Go all numbers from unmarshalling JSON will be represented as float64
87-
// so this is the only type we need.
88-
if v, ok := value.(float64); ok && i.SchemaType == SchemaTypeUnknown {
86+
if v, ok := anyAsNumber(value); ok && i.SchemaType == SchemaTypeUnknown {
8987
return &InferredSchema{
9088
SchemaType: SchemaTypeNumber,
9189
Number: NewNumber().Infer(v),
@@ -175,7 +173,7 @@ func (i *InferredSchema) Infer(value any, hints Hints) *InferredSchema {
175173
return &InferredSchema{SchemaType: SchemaTypeAny}
176174
}
177175

178-
if v, ok := value.(float64); ok && i.SchemaType == SchemaTypeNumber {
176+
if v, ok := anyAsNumber(value); ok && i.SchemaType == SchemaTypeNumber {
179177
return &InferredSchema{
180178
SchemaType: SchemaTypeNumber,
181179
Number: i.Number.Infer(v),

inferrer_test.go

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,49 @@ import (
1212
"github.com/stretchr/testify/require"
1313
)
1414

15+
func TestInfer(t *testing.T) {
16+
for _, tc := range []struct {
17+
value any
18+
expectedSchema Schema
19+
}{
20+
{
21+
value: "52",
22+
expectedSchema: Schema{Type: jtd.TypeString},
23+
},
24+
{
25+
value: 52,
26+
expectedSchema: Schema{Type: jtd.TypeUint8},
27+
},
28+
{
29+
value: nil,
30+
expectedSchema: Schema{Nullable: true},
31+
},
32+
{
33+
value: map[string]any{
34+
"name": "Joe",
35+
"age": 52,
36+
},
37+
expectedSchema: Schema{
38+
Properties: map[string]Schema{
39+
"name": {Type: jtd.TypeString},
40+
"age": {Type: jtd.TypeUint8},
41+
},
42+
},
43+
},
44+
{
45+
value: []int{1, 3, 5},
46+
expectedSchema: Schema{
47+
Elements: &Schema{Type: jtd.TypeUint8},
48+
},
49+
},
50+
} {
51+
t.Run(fmt.Sprintf("infer_%T", tc.value), func(t *testing.T) {
52+
gotSchema := NewInferrer(WithoutHints()).Infer(tc.value).IntoSchema()
53+
assert.EqualValues(t, tc.expectedSchema, gotSchema)
54+
})
55+
}
56+
}
57+
1558
func TestInferString(t *testing.T) {
1659
cases := []struct {
1760
description string
@@ -55,6 +98,19 @@ func TestInferString(t *testing.T) {
5598
},
5699
},
57100
},
101+
{
102+
description: "object with array",
103+
values: []string{
104+
`{"name": "Joe", "age": 42, "hobbies": ["code", "animals"]}`,
105+
},
106+
expectedSchema: Schema{
107+
Properties: map[string]Schema{
108+
"name": {Type: jtd.TypeString},
109+
"age": {Type: jtd.TypeUint8},
110+
"hobbies": {Elements: &Schema{Type: jtd.TypeString}},
111+
},
112+
},
113+
},
58114
{
59115
description: "array",
60116
values: []string{`[1, 2, 3]`},
@@ -144,24 +200,7 @@ func TestInferString(t *testing.T) {
144200
}
145201
}
146202

147-
func TestJTDInfer(t *testing.T) {
148-
rows := []string{
149-
`{"name": "Joe", "age": 42, "hobbies": ["code", "animals"]}`,
150-
}
151-
152-
expectedSchema := Schema{
153-
Properties: map[string]Schema{
154-
"name": {Type: jtd.TypeString},
155-
"age": {Type: jtd.TypeUint8},
156-
"hobbies": {Elements: &Schema{Type: jtd.TypeString}},
157-
},
158-
}
159-
gotSchema := InferStrings(rows, WithoutHints()).IntoSchema()
160-
161-
assert.EqualValues(t, expectedSchema, gotSchema)
162-
}
163-
164-
func TestJTDInferrerWithEnumHints(t *testing.T) {
203+
func TestInferrerWithEnumHints(t *testing.T) {
165204
hints := Hints{
166205
Enums: NewHintSet().
167206
Add([]string{"name"}).
@@ -209,7 +248,7 @@ func TestJTDInferrerWithEnumHints(t *testing.T) {
209248
assert.EqualValues(t, expectedSchema, gotSchema)
210249
}
211250

212-
func TestJTDInferWithValuesHints(t *testing.T) {
251+
func TestInferWithValuesHints(t *testing.T) {
213252
hints := Hints{
214253
Values: NewHintSet().Add([]string{}),
215254
}
@@ -231,7 +270,7 @@ func TestJTDInferWithValuesHints(t *testing.T) {
231270
assert.EqualValues(t, expectedSchema, gotSchema)
232271
}
233272

234-
func TestJTDInferWithDiscriminatorHints(t *testing.T) {
273+
func TestInferWithDiscriminatorHints(t *testing.T) {
235274
hints := Hints{
236275
Discriminator: NewHintSet().Add([]string{"-", "type"}),
237276
}
@@ -280,6 +319,14 @@ func BenchmarkInferThousandRowsNoMissingHints(b *testing.B) {
280319
}
281320
}
282321

322+
func BenchmarkInferSimpleString(b *testing.B) {
323+
inferrer := NewInferrer(WithoutHints())
324+
325+
for n := 0; n < b.N; n++ {
326+
inferrer.Infer("string")
327+
}
328+
}
329+
283330
func generateRows(n int) []string {
284331
row := `{"name":"bench", "speed":100.2}`
285332
rows := []string{}

0 commit comments

Comments
 (0)