Skip to content

Commit

Permalink
Add examples and update docs and README
Browse files Browse the repository at this point in the history
  • Loading branch information
bombsimon committed Oct 1, 2023
1 parent 37fa70a commit eacc85f
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 3 deletions.
52 changes: 49 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,53 @@
# JSON typedef infer

This is a port of [`json-typedef-infer`][jtd-infer] from Rust to Go. The reason
for porting this is that I was in need of JTD inference from code and not as a
CLI tool so I ported this straight from Rust.
This is a port of [`json-typedef-infer`][jtd-infer] Go. The reason for porting
this is that I was in need of JTD inference from code and not as a CLI tool.

For more information about JSON Typedef and its RFC and how to use different
kind of hints see [`json-typedef-infer`][jtd-infer]

## Usage

See [examples] directory for runnable examples and how to infer JTD.

```go
schema := NewInferrer(WithoutHints()).
Infer("my-string").
IntoSchema(WithoutHints())
// {
// "type": "string"
// }
```

If you have multiple rows of objects or lists as strings you can pass them to
the shorthand function `InferStrings`.

```go
rows := []string{
`{"name":"Joe", "age": 52, "something_optional": true, "something_nullable": 1.1}`,
`{"name":"Jane", "age": 48, "something_nullable": null}`,
}
schema := InferStrings(rows, WithoutHints()).IntoSchema(WithoutHints())
// {
// "properties": {
// "age": {
// "type": "uint8"
// },
// "name": {
// "type": "string"
// },
// "something_nullable": {
// "nullable": true,
// "type": "float64"
// }
// },
// "optionalProperties": {
// "something_optional": {
// "type": "boolean"
// }
// }
// }
```

[jtd-infer]: https://github.com/jsontypedef/json-typedef-infer/
[examples]: examples
20 changes: 20 additions & 0 deletions examples/infer_multiple_string_rows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import (
"encoding/json"

"github.com/bombsimon/jtdinfer"
)

func main() {
rows := []string{
`{"name":"Joe", "age": 52, "something_optional": true, "something_nullable": 1.1}`,
`{"name":"Jane", "age": 48, "something_nullable": null}`,
}
schema := jtdinfer.
InferStrings(rows, jtdinfer.WithoutHints()).
IntoSchema(jtdinfer.WithoutHints())

j, _ := json.MarshalIndent(schema, "", " ")
print(string(j))
}
17 changes: 17 additions & 0 deletions examples/infer_simple_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"encoding/json"

"github.com/bombsimon/jtdinfer"
)

func main() {
schema := jtdinfer.
NewInferrer(jtdinfer.WithoutHints()).
Infer("my-string").
IntoSchema(jtdinfer.WithoutHints())

j, _ := json.MarshalIndent(schema, "", " ")
print(string(j))
}
36 changes: 36 additions & 0 deletions examples/infer_with_hints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import (
"encoding/json"

"github.com/bombsimon/jtdinfer"
)

func main() {
rows := []string{
`{
"name":"Joe",
"age":52,
"work":{"department": "sales"},
"values":{"x": [1, 2, 3], "y": [4, 5, 6], "z": [7, 8, 9]},
"discriminator":[{"type":"s", "value":"foo"},{"type":"n", "value":3.14}]
}`,
`{
"name":"Jane",
"age":48,
"work":{"department": "engineering"},
"values":{"x": [1, 2, 3], "y": [4, 5, 6], "z": [7, 8, -2000]},
"discriminator":[{"type":"s", "value":"foo"},{"type":"n", "value":3.14}]
}`,
}
hints := jtdinfer.Hints{
DefaultNumType: jtdinfer.NumTypeUint32,
Enums: jtdinfer.NewHintSet().Add([]string{"work", "department"}),
Values: jtdinfer.NewHintSet().Add([]string{"values"}),
Discriminator: jtdinfer.NewHintSet().Add([]string{"discriminator", "-", "type"}),
}

schema := jtdinfer.InferStrings(rows, hints).IntoSchema(hints)
j, _ := json.MarshalIndent(schema, "", " ")
print(string(j))
}
20 changes: 20 additions & 0 deletions hints.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package jtdinfer

// Wildcard represents the character that matches any value for hints.
const Wildcard = "-"

// Hints contains the default number type to use and all the hints for enums,
// values and discriminators.
type Hints struct {
DefaultNumType NumType
Enums HintSet
Values HintSet
Discriminator HintSet
}

func WithoutHints() Hints {
return Hints{}
}

// SubHint will return the sub hints for all hint sets for the passed key.
func (h Hints) SubHints(key string) Hints {
return Hints{
DefaultNumType: h.DefaultNumType,
Expand All @@ -18,33 +26,42 @@ func (h Hints) SubHints(key string) Hints {
}
}

// IsEnumActive checks if the enum hint set is active.
func (h Hints) IsEnumActive() bool {
return h.Enums.IsActive()
}

// IsValuesActive checks if the values hint set is active.
func (h Hints) IsValuesActive() bool {
return h.Values.IsActive()
}

// PeekActiveDiscriminator will peek the currently active discriminator, if any.
// The returned boolean tells if there is an active discriminator.
func (h Hints) PeekActiveDiscriminator() (string, bool) {
return h.Discriminator.PeekActive()
}

// HintSet represents a list of paths (lists) to match for hints.
type HintSet struct {
Values [][]string
}

// NewHintSet creates a new empty `HintSet`.
func NewHintSet() HintSet {
return HintSet{
Values: [][]string{},
}
}

// Add will add a path (slice) to the `HintSet`.
func (h HintSet) Add(v []string) HintSet {
h.Values = append(h.Values, v)
return h
}

// SubHint will filter all the current sets and keep those who's first element
// matches the passed key or wildcard.
func (h HintSet) SubHints(key string) HintSet {
filteredValues := [][]string{}

Expand All @@ -64,6 +81,7 @@ func (h HintSet) SubHints(key string) HintSet {
}
}

// IsActive returns true if any set in the hint set his active.
func (h HintSet) IsActive() bool {
for _, valueList := range h.Values {
if len(valueList) == 0 {
Expand All @@ -74,6 +92,8 @@ func (h HintSet) IsActive() bool {
return false
}

// PeekActive returns the currently active value if any. The returned boolean
// tells if a value was found.
func (h HintSet) PeekActive() (string, bool) {
for _, values := range h.Values {
if len(values) != 1 {
Expand Down

0 comments on commit eacc85f

Please sign in to comment.