Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation about state machines and few refinements along the way #112

Merged
merged 72 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
9fa9466
readme: fix wrong code block
widmogrod Mar 4, 2024
b3b8706
x/machine: better testing suite usability
widmogrod Mar 30, 2024
149944d
x/workflow: refactor to new testing suite
widmogrod Mar 30, 2024
173f519
example/state: refactor to order service and use new testing suite
widmogrod Mar 30, 2024
57f610f
dev: introduce moq
widmogrod Mar 30, 2024
884a866
dev: expose different port for documentation
widmogrod Mar 30, 2024
a23dac3
docs: description of state machine
widmogrod Mar 30, 2024
f4d73b5
docs: small fixes
widmogrod Mar 30, 2024
1f3fb67
example: tic tac toe machine use new testing suite
widmogrod Mar 30, 2024
4a7b9b1
go.mod update
widmogrod Mar 30, 2024
c825ebf
my-app: few adjustments to code
widmogrod Mar 31, 2024
dcb4437
example/state: moq generation needs to be in the same file as mkunion
widmogrod Mar 31, 2024
1c5e6ed
update ci.yml with go moq and deps bump
widmogrod Mar 31, 2024
03cc034
update ci.yml with go moq and deps bump
widmogrod Mar 31, 2024
fe52a7d
update ci.yml GOPATH
widmogrod Mar 31, 2024
826d26c
update ci.yml GOPATH
widmogrod Mar 31, 2024
72f3f89
update ci.yml GOPATH
widmogrod Mar 31, 2024
1560c21
update ci.yml GOPATH
widmogrod Mar 31, 2024
a7c9c86
update ci.yml GOPATH
widmogrod Mar 31, 2024
8e6a8c8
update dev loop
widmogrod Mar 31, 2024
2e1c273
docs: clean and expand on generic unions
widmogrod May 3, 2024
2b6d15d
docs: clean and fix typos in getting started
widmogrod May 3, 2024
7dd3884
docs: introduce roadmap idea
widmogrod May 3, 2024
7f6c3c3
docs: expand state machine documentation
widmogrod May 3, 2024
f9635dd
example: reorder model.go file
widmogrod May 3, 2024
9893242
docs: refine state machine description
widmogrod May 4, 2024
80e8e24
docs: Marshaling union as JSON
widmogrod May 11, 2024
182d567
docs: Improve title and wording
widmogrod May 11, 2024
753969b
docs: Add feature to the roadmap
widmogrod May 11, 2024
80954d2
example: Add TreeJson serialisation
widmogrod May 11, 2024
7d3fe4d
cmd: type-registry now registers json marshaler
widmogrod May 11, 2024
bdbab97
shared/json: add method description
widmogrod May 11, 2024
87b6196
cmd/mkunion: add registering JSONMarshaler during generation
widmogrod May 11, 2024
ba21876
x/machine: add context to machine.Handle(ctx, ...)
widmogrod May 11, 2024
c34ff6c
x/workflow: update Transition function to support context
widmogrod May 11, 2024
9f99887
x/taskqueue: change signature machine.Handle(ctx,...)
widmogrod May 11, 2024
a146d53
x/taskqueue: change signature machine.Handle(ctx,...) to have context…
widmogrod May 11, 2024
bceca05
x/state: Introduce storage example and tests
widmogrod May 11, 2024
d48af06
example/tic_tac_toe: change signature machine.Handle(ctx,...) to have…
widmogrod May 11, 2024
e4bde3d
f: generic union example with JSON serialisation
widmogrod May 11, 2024
ab496ad
my-app: change signature machine.Handle(ctx,...)
widmogrod May 11, 2024
abe5d83
x/schema: test fallback conversions
widmogrod May 11, 2024
45fb01d
update comments
widmogrod May 11, 2024
b6af66f
docs: introduce incomplete documentations
widmogrod May 11, 2024
b818e43
feature: make type-registry ON by default
widmogrod May 11, 2024
32b5f10
fix: fix moq problem with order of running of go:generate
widmogrod May 11, 2024
a58c460
maintenance: go mod tidy
widmogrod May 12, 2024
cf0ecb4
debug: ci.yaml find empty imports
widmogrod May 12, 2024
00150c0
debug: supress find errors
widmogrod May 12, 2024
8c77002
debug: supress find errors
widmogrod May 12, 2024
5d5752d
debug: make find return 0
widmogrod May 12, 2024
c02fa01
debug: make find return 0
widmogrod May 12, 2024
9f0f49f
debug: where is empty import
widmogrod May 12, 2024
d13b7b9
fix: attempt to filter out empty imports
widmogrod May 12, 2024
8aa7ec2
debug: print lines
widmogrod May 12, 2024
05c9b9e
debug: print lines
widmogrod May 12, 2024
e85c80b
debug: more debugging
widmogrod May 12, 2024
4aff6f2
fix: attempt to filter out empty imports
widmogrod May 12, 2024
55fa8f7
debug: more debugging
widmogrod May 12, 2024
979c3e8
ci.yml: go mod download
widmogrod May 12, 2024
2176e11
debug: more debugging
widmogrod May 12, 2024
3395c6d
debug: more debugging
widmogrod May 12, 2024
b488ee0
debug: more debugging
widmogrod May 12, 2024
b2959dc
debug: more debugging
widmogrod May 12, 2024
a19f97c
fix: moq problem and type-registry
widmogrod May 12, 2024
25322b4
x/shape: improve package lookup
widmogrod May 12, 2024
b88c951
x/shape: more debugging
widmogrod May 12, 2024
65f57e0
x/shape: more debugging
widmogrod May 12, 2024
8ebe078
x/shape: more debugging
widmogrod May 12, 2024
55b2496
x/shape: more debugging
widmogrod May 12, 2024
a1747f0
x/shape: more debugging
widmogrod May 12, 2024
73b719d
x/shape: reduce debugging
widmogrod May 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,36 @@ jobs:
name: Test implementation in Golang
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ^1.21
id: go

- run: cd cmd/mkunion; go get -v -t -d ./...
- run: cd cmd/mkunion; go build -o mkunion

- run: go install github.com/matryer/moq@latest

- run: go get -v -t -d ./...
- run: go generate ./...

# initiate docker-compose services
- run: |
pip install awscli-local
- run: pip install awscli-local
- run: dev/bootstrap.sh -nologs

- run: |
find . -type f -name '*.go' -exec grep -C 2 -H 'github.com/opensearch-project/opensearch-go/v2' {} + &2>/dev/null || true

- run: |
ls -la /home/runner/go/pkg/mod/github.com/opensearch-project/opensearch-go
ls -la /home/runner/go/pkg/mod/cache/download/github.com/opensearch-project/opensearch-go

tree /home/runner/go/pkg/mod/github.com/opensearch-project/opensearch-go
tree /home/runner/go/pkg/mod/cache/download/github.com/opensearch-project/opensearch-go

- run: |
cat x/storage/schemaless/types_reg_gen.go

# run tests
- run: |
export RUN_EXPERIMENTAL_TEST="false"
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@


## About
Strongly typed **union type** in golang.
Strongly typed **union type** in golang with generics*.

* with full _pattern matching_ support
* with full _json marshalling_ support
* with exhaustive _pattern matching_ support
* with _json marshalling_ including generics
* and as a bonus, can generate compatible typescript types for end-to-end type safety in your application

## Why
Expand All @@ -19,7 +19,7 @@ Visitor pattern requires a lot of boiler plate code and hand crafting of the `Ac

On top of that, any data marshalling like to/from JSON requires additional, hand crafted code, to make it work.

MkUnion solves all of those problems, by generating opinionated and strongly typed mindful code for you.
MkUnion solves all of those problems, by generating opinionated and strongly typed meaningful code for you.

## Example

Expand Down
15 changes: 14 additions & 1 deletion cmd/mkunion/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func main() {
},
&cli.BoolFlag{
Name: "type-registry",
Value: false,
Value: true,
},
},
Action: func(c *cli.Context) error {
Expand Down Expand Up @@ -563,7 +563,20 @@ func GenerateTypeRegistry(inferred *shape.IndexedTypeWalker) (bytes.Buffer, erro
shape.WithPkgImportName(),
)

// Register go type
contents.WriteString(fmt.Sprintf("\tshared.TypeRegistryStore[%s](%q)\n", instantiatedTypeName, fullTypeName))

// Try to register type JSON marshaller
if ref, ok := inst.(*shape.RefName); ok {
some, found := shape.LookupShapeOnDisk(ref)
if !found {
continue
}
some = shape.IndexWith(some, ref)
if shape.IsUnion(some) {
contents.WriteString(fmt.Sprintf("\t%s\n", generators.StrRegisterUnionFuncName(shape.ToGoPkgName(some), some)))
}
}
}

contents.WriteString("}\n")
Expand Down
10 changes: 10 additions & 0 deletions dev/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,24 @@ project_root=$(dirname "$cwd")
envrc_file=$project_root/.envrc

echo "Check if necessary tools are installed"
command -v go >/dev/null 2>&1 || { echo >&2 "golang is not installed. Aborting."; exit 1; }
command -v docker >/dev/null 2>&1 || { echo >&2 "docker is not installed. Aborting."; exit 1; }
command -v docker-compose >/dev/null 2>&1 || { echo >&2 "docker-compose is not installed. Aborting."; exit 1; }
command -v awslocal >/dev/null 2>&1 || { echo >&2 "awslocal is not installed. Aborting. Please run
pip install awscli-local "; exit 1; }

# check for moq
command -v moq >/dev/null 2>&1 || { echo >&2 "moq is not installed. Aborting please run
go install github.com/matryer/moq@latest"; exit 1; }

echo "Creating volume directory"
mkdir -p $cwd/_volume

if [ "$1" == "-install-only" ]; then
trap - EXIT
exit 0
fi

echo "Starting localstack"
docker compose -f $cwd/compose.yml up -d
# trap exit and stop docker compose
Expand Down
3 changes: 2 additions & 1 deletion dev/docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ cwd=$(dirname "$0")
project_root=$(dirname "$cwd")

if [ "$1" == "run" ]; then
docker run --rm -it -p 8000:8000 -v ${project_root}:/docs squidfunk/mkdocs-material
echo "Serving documentation at http://localhost:8088"
docker run --rm -it -p 8088:8000 -v ${project_root}:/docs squidfunk/mkdocs-material
elif [ "$1" == "build" ]; then
docker run --rm -it -v ${project_root}:/docs squidfunk/mkdocs-material build
else
Expand Down
11 changes: 6 additions & 5 deletions docs/development/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ title: Contributing and development
---

# Contributing and development
## Contributing

If you want to contribute to `mkunion` project, please open issue first to discuss your idea.

I have opinions about how `mkunion` should work, how I want to evolve it, and I want to make sure that your idea fits into the project.

## Development

Checkout repo and run:
Expand All @@ -28,8 +34,3 @@ To preview documentation run:
```
./dev/docs.sh run
```

## Contributing

If you want to contribute to `mkunion` project, please open issue first to discuss your idea.
I have opinions about how `mkunion` should work, how I want to evolve it, and I want to make sure that your idea fits into the project.
23 changes: 12 additions & 11 deletions docs/examples/generic_union.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Generic unions
title: Union and generic types
---
# Generic unions
# Union and generic types
MkUnion will generate generic unions for you.

You only need to declare each variant type of the union with a type parameter,
Expand All @@ -27,18 +27,16 @@ type (
)
```

After you run generation (as described in [getting started](/getting_started.md)),
After you run generation (as described in [getting started](../getting_started.md)),
you have access to the same features as with non-generic unions.

## Matching function

Let's define higher order function `ReduceTree` that will travers leaves in tree and produce a single value.
Let's define higher order function `ReduceTree` that will travers leaves in `Tree` and produce a single value.

This function uses `MatchTreeR1` function that is generated automatically for you.

```go title="example/tree.go"

```go
func ReduceTree[A, B any](x Tree[A], f func(A, B) B, init B) B {
return MatchTreeR1(
x,
Expand Down Expand Up @@ -78,11 +76,7 @@ func ExampleTreeSumValues() {

You can also reduce tree to complex structure, for example to keep track of order of values in the tree, along with sum of all values in the tree.

```go title="example/tree.go"

```go title="example/tree_test.go"

```go
func ExampleTreeCustomReduction() {
tree := &Branch[int]{
L: &Leaf[int]{Value: 1},
Expand Down Expand Up @@ -154,4 +148,11 @@ func MapOption[A, B any](x Option[A], f func(A) B) Option[B] {
},
)
}
```
```

In above example, we define `MapEither` and `MapOption` functions that will apply function `f` to value inside `Either` or `Option` type.

It would be much better to have only one `Map` definition, but due to limitations of Go type system, we need to define separate functions for each type.

I'm considering adding code generation for such behaviours in the future. Not yet due to focus on validating core concepts.

81 changes: 81 additions & 0 deletions docs/examples/json.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Marshaling union as JSON
---

# Marshaling union as JSON

MkUnion provides you with utility function that allows you to marshal and unmarshal union types to JSON,
reducing burden of writing custom marshaling and unmarshaling functions for union types.

- `shared.JSONMarshal[A any](in A) ([]byte, error)`
- `shared.JSONUnmarshal[A any](data []byte) (A, error)`

Below is an example of how to use those functions and how the output JSON looks like.


```go title="example/tree_json_test.go"
import (
"github.com/widmogrod/mkunion/x/shared"
)

--8<-- "example/tree_json_test.go:8:30"
```

Formated JSON output of the example above:
```json
{
"$type": "example.Branch",
"example.Branch": {
"L": {
"$type": "example.Leaf",
"example.Leaf": {
"Value": 1
}
},
"R": {
"$type": "example.Branch",
"example.Branch": {
"L": {
"$type": "example.Branch",
"example.Branch": {
"L": {
"$type": "example.Leaf",
"example.Leaf": {
"Value": 2
}
},
"R": {
"$type": "example.Leaf",
"example.Leaf": {
"Value": 3
}
}
}
},
"R": {
"$type": "example.Leaf",
"example.Leaf": {
"Value": 4
}
}
}
}
}
}
```


There are few things that you can notice in this example:

- Each union type discriminator field `$type` field that holds the type name, and corresponding key with the name of the type, that holds value of union variant.
- This is opinionated way, and library don't allow to change it.
I was experimenting with making this behaviour customizable, but it make code and API mode complex, and I prefer to keep it simple, and increase interoperability between different libraries and applications, that way.

- Recursive union types are supported, and they are marshaled as nested JSON objects.]

- `$type` don't have to have full package import name, nor type parameter,
mostly because in `shared.JSONUnmarshal[Tree[int]](json)` you hint that your code accepts `Tree[int]`.
- I'm considering adding explicit type discriminators like `example.Branch[int]` or `example.Leaf[int]`.
It could increase type strictness on client side, BUT it makes generating TypeScript types more complex, and I'm not sure if it's worth it.

- It's not shown on this example, but you can also reference types and union types from other packages, and serialization will work as expected.
Loading