diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dba3f99e..5017d2c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,11 @@ jobs: # initiate docker-compose services - run: | pip install awscli-local - - run: dev/bootstrap.sh& sleep 10 + - run: dev/bootstrap.sh -nologs # run tests - run: | + export RUN_EXPERIMENTAL_TEST="false" set -e retries=3 until [ $retries -le 0 ]; do diff --git a/cmd/mkunion/main.go b/cmd/mkunion/main.go index 16fb2076..ec2f60ac 100644 --- a/cmd/mkunion/main.go +++ b/cmd/mkunion/main.go @@ -16,16 +16,6 @@ import ( "syscall" ) -type extractImports interface { - ExtractImports(x shape.Shape) generators.PkgMap - SkipImportsAndPackage(x bool) -} - -type extractInitFuncs interface { - ExtractImportFuncs(s shape.Shape) []string - SkipInitFunc(flag bool) -} - func main() { ctx, _ := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) @@ -99,77 +89,36 @@ func main() { return err } - unions := inferred.RetrieveUnions() - if len(unions) == 0 { - log.Infof("no union found in %s", sourcePath) - continue + contents, err := GenerateUnions(inferred) + if err != nil { + return fmt.Errorf("failed generating union in %s: %w", sourcePath, err) } - packageName := "main" - pkgMap := make(generators.PkgMap) - initFunc := make(generators.InitFuncs, 0, 0) - shapesContents := bytes.Buffer{} - - for _, union := range unions { - packageName = shape.ToGoPkgName(union) - - genVisitor := generators.NewVisitorGenerator(union) - genVisitor.SkipImportsAndPackage(true) - - contents := []byte("//union:genVisitor\n") - contents, err = genVisitor.Generate() - if err != nil { - return fmt.Errorf("failed to generate genVisitor for %s in %s: %w", shape.ToGoTypeName(union), sourcePath, err) - } - shapesContents.Write(contents) - - genShape := generators.NewShapeUnion(union) - genShape.SkipImportsAndPackage(true) - genShape.SkipInitFunc(true) - - contents = []byte("//union:shape\n") - contents, err = genShape.Generate() - if err != nil { - return fmt.Errorf("failed to generate shape for %s in %s: %w", shape.ToGoTypeName(union), sourcePath, err) - } - shapesContents.Write(contents) - - genSerde := generators.NewSerdeJSONUnion(union) - genSerde.SkipImportsAndPackage(true) + err = SaveFile(contents, sourcePath, "union_gen") + if err != nil { + return fmt.Errorf("failed saving union in %s: %w", sourcePath, err) + } - contents = []byte("//union:serde:json\n") - contents, err = genSerde.Generate() - if err != nil { - return fmt.Errorf("failed to generate json serde for %s in %s: %w", shape.ToGoTypeName(union), sourcePath, err) - } - shapesContents.Write(contents) + contents, err = GenerateSerde(inferred) + if err != nil { + return fmt.Errorf("failed generating serde in %s: %w", sourcePath, err) + } - pkgMap = generators.MergePkgMaps(pkgMap, - genShape.ExtractImports(union), - genSerde.ExtractImports(union), - ) + err = SaveFile(contents, sourcePath, "serde_gen") + if err != nil { + return fmt.Errorf("failed saving serde in %s: %w", sourcePath, err) + } - initFunc = append(initFunc, genShape.ExtractImportFuncs(union)...) + contents, err = GenerateShape(inferred) + if err != nil { + return fmt.Errorf("failed generating shape in %s: %w", sourcePath, err) } - contents := "// Code generated by mkunion. DO NOT EDIT.\n" - contents += fmt.Sprintf("package %s\n\n", packageName) - contents += generators.GenerateImports(pkgMap) - contents += generators.GenerateInitFunc(initFunc) - contents += shapesContents.String() - - sourceName := path.Base(sourcePath) - baseName := strings.TrimSuffix(sourceName, path.Ext(sourceName)) - fileName := path.Join( - path.Dir(sourcePath), - fmt.Sprintf("%s_union_gen.go", baseName), - ) - - log.Infof("writing %s", fileName) - err = os.WriteFile(fileName, []byte(contents), 0644) + err = SaveFile(contents, sourcePath, "shape_gen") if err != nil { - return fmt.Errorf("failed to write union in %s: %w", sourcePath, err) + return fmt.Errorf("failed saving shape in %s: %w", sourcePath, err) } + } return nil @@ -222,118 +171,6 @@ func main() { return nil }, }, - { - Name: "serde", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "type", - DefaultText: "json", - }, - &cli.StringSliceFlag{ - Name: "input-go-file", - Aliases: []string{"i", "input"}, - Usage: `When not provided, it will try to use GOFILE environment variable, used when combined with //go:generate mkunion -name=MyUnionType`, - TakesFile: true, - }, - &cli.BoolFlag{ - Name: "verbose", - Aliases: []string{"v"}, - Required: false, - Value: false, - }, - }, - Action: func(c *cli.Context) error { - if c.Bool("verbose") { - log.SetLevel(log.DebugLevel) - } - - sourcePaths := c.StringSlice("input-go-file") - if len(sourcePaths) == 0 && os.Getenv("GOFILE") != "" { - cwd, _ := syscall.Getwd() - sourceName := path.Base(os.Getenv("GOFILE")) - sourcePaths = []string{ - path.Join(cwd, sourceName), - } - } - - if len(sourcePaths) == 0 { - // show usage - cli.ShowAppHelpAndExit(c, 1) - } - - for _, sourcePath := range sourcePaths { - inferred, err := shape.InferFromFile(sourcePath) - if err != nil { - return fmt.Errorf("failed inferring shape in %s; %w", sourcePath, err) - } - - shapes := inferred.RetrieveShapesTaggedAs("serde") - if len(shapes) == 0 { - log.Infof("no shape found in %s", sourcePath) - continue - } - - packageName := "main" - pkgMap := make(generators.PkgMap) - initFunc := make(generators.InitFuncs, 0, 0) - shapesContents := bytes.Buffer{} - - for _, x := range shapes { - packageName = shape.ToGoPkgName(x) - genSerde := generators.NewSerdeJSONTagged(x) - genSerde.SkipImportsAndPackage(true) - - genShape := generators.NewShapeTagged(x) - genShape.SkipImportsAndPackage(true) - genShape.SkipInitFunc(true) - - contents := "//shape:serde:json\n" - contents, err = genSerde.Generate() - if err != nil { - return fmt.Errorf("failed to generate json serde for %s in %s: %w", shape.ToGoTypeName(x), sourcePath, err) - } - shapesContents.WriteString(contents) - - contents = "//shape:shape\n" - contents, err = genShape.Generate() - if err != nil { - return fmt.Errorf("failed to generate shape for %s in %s: %w", shape.ToGoTypeName(x), sourcePath, err) - } - shapesContents.WriteString(contents) - - pkgMap = generators.MergePkgMaps(pkgMap, - genSerde.ExtractImports(x), - genShape.ExtractImports(x), - ) - - initFunc = append(initFunc, genShape.ExtractImportFuncs(x)...) - } - - contents := "// Code generated by mkunion. DO NOT EDIT.\n" - contents += fmt.Sprintf("package %s\n\n", packageName) - contents += generators.GenerateImports(pkgMap) - contents += generators.GenerateInitFunc(initFunc) - contents += shapesContents.String() - - sourceName := path.Base(sourcePath) - baseName := strings.TrimSuffix(sourceName, path.Ext(sourceName)) - fileName := path.Join( - path.Dir(sourcePath), - fmt.Sprintf("%s_serde_gen.go", baseName), - ) - - log.Infof("writing %s", fileName) - err = os.WriteFile(fileName, []byte(contents), 0644) - if err != nil { - return fmt.Errorf("failed to write serde in %s: %w", sourcePath, err) - } - - return nil - } - - return nil - }, - }, { Name: "shape-export", Flags: []cli.Flag{ @@ -407,3 +244,244 @@ func main() { log.Fatal(err) } } + +func GenerateUnions(inferred *shape.InferredInfo) (bytes.Buffer, error) { + shapesContents := bytes.Buffer{} + unions := inferred.RetrieveUnions() + if len(unions) == 0 { + return shapesContents, nil + } + + var err error + packageName := "main" + pkgMap := make(generators.PkgMap) + initFunc := make(generators.InitFuncs, 0) + + for _, union := range unions { + packageName = shape.ToGoPkgName(union) + + genVisitor := generators.NewVisitorGenerator(union) + genVisitor.SkipImportsAndPackage(true) + + contents := []byte("//union:genVisitor\n") + contents, err = genVisitor.Generate() + if err != nil { + return shapesContents, fmt.Errorf("failed to generate genVisitor for %s: %w", shape.ToGoTypeName(union), err) + } + shapesContents.Write(contents) + + genSerde := generators.NewSerdeJSONUnion(union) + genSerde.SkipImportsAndPackage(true) + + contents = []byte("//union:serde:json\n") + contents, err = genSerde.Generate() + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateUnions: failed to generate json serde for %s: %w", shape.ToGoTypeName(union), err) + } + shapesContents.Write(contents) + + pkgMap = generators.MergePkgMaps(pkgMap, + genSerde.ExtractImports(union), + ) + } + + contents := bytes.Buffer{} + contents.WriteString("// Code generated by mkunion. DO NOT EDIT.\n") + contents.WriteString(fmt.Sprintf("package %s\n\n", packageName)) + contents.WriteString(generators.GenerateImports(pkgMap)) + contents.WriteString(generators.GenerateInitFunc(initFunc)) + _, err = shapesContents.WriteTo(&contents) + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateUnions: failed to write shapes contents: %w", err) + } + + return contents, nil +} + +func GenerateSerde(inferred *shape.InferredInfo) (bytes.Buffer, error) { + shapesContents := bytes.Buffer{} + shapes := inferred.RetrieveShapesTaggedAs("serde") + if len(shapes) == 0 { + return shapesContents, nil + } + + var err error + packageName := "main" + pkgMap := make(generators.PkgMap) + initFunc := make(generators.InitFuncs, 0, 0) + + for _, x := range shapes { + packageName = shape.ToGoPkgName(x) + genSerde := generators.NewSerdeJSONTagged(x) + genSerde.SkipImportsAndPackage(true) + + contents := "//shape:serde:json\n" + contents, err = genSerde.Generate() + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateSerde: failed to generate json serde for %s: %w", shape.ToGoTypeName(x), err) + } + shapesContents.WriteString(contents) + + pkgMap = generators.MergePkgMaps(pkgMap, + genSerde.ExtractImports(x), + ) + } + + contents := bytes.Buffer{} + contents.WriteString("// Code generated by mkunion. DO NOT EDIT.\n") + contents.WriteString(fmt.Sprintf("package %s\n\n", packageName)) + contents.WriteString(generators.GenerateImports(pkgMap)) + contents.WriteString(generators.GenerateInitFunc(initFunc)) + + _, err = shapesContents.WriteTo(&contents) + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateSerde: failed to write shapes contents: %w", err) + } + + return contents, nil +} + +func GenerateShape(inferred *shape.InferredInfo) (bytes.Buffer, error) { + shapesContents := bytes.Buffer{} + shapes := inferred.RetrieveShapes() + if len(shapes) == 0 { + return shapesContents, nil + } + + packageName := "main" + pkgMap := make(generators.PkgMap) + initFunc := make(generators.InitFuncs, 0) + + for _, x := range shapes { + packageName = shape.ToGoPkgName(x) + contents, err := GenerateShapeFollow(x, &pkgMap, &initFunc, inferred) + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateShape: failed to generate shape for %s: %w", shape.ToGoTypeName(x), err) + } + if contents != nil { + _, err = contents.WriteTo(&shapesContents) + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateShape: failed to write shape for %s: %w", shape.ToGoTypeName(x), err) + } + } + } + + contents := bytes.Buffer{} + contents.WriteString("// Code generated by mkunion. DO NOT EDIT.\n") + contents.WriteString(fmt.Sprintf("package %s\n\n", packageName)) + contents.WriteString(generators.GenerateImports(pkgMap)) + contents.WriteString(generators.GenerateInitFunc(initFunc)) + _, err := shapesContents.WriteTo(&contents) + if err != nil { + return shapesContents, fmt.Errorf("mkunion.GenerateUnions: failed to write shapes contents: %w", err) + } + + return contents, nil +} + +func GenerateShapeFollow(x shape.Shape, pkgMap *generators.PkgMap, initFunc *[]string, inferred *shape.InferredInfo) (*bytes.Buffer, error) { + var result *bytes.Buffer + for _, y := range shape.ExtractRefs(x) { + // filter types that are not from the same package + if y.PkgImportName != shape.ToGoPkgImportName(x) { + log.Debugf("mkunion.GenerateShapeFollow: skipping %s, not from the same package", shape.ToGoTypeName(y)) + continue + } + + contents, err := GenerateShapeOnce(y, pkgMap, initFunc, inferred) + if err != nil { + return nil, fmt.Errorf("mkunion.GenerateShapeFollow: failed to generate shape for %s: %w", shape.ToGoTypeName(y), err) + } + + if contents == nil { + continue + } + + if result == nil { + result = contents + } else { + _, err = contents.WriteTo(result) + if err != nil { + return nil, fmt.Errorf("mkunion.GenerateShapeFollow: failed to write shape for %s: %w", shape.ToGoTypeName(y), err) + } + } + } + + return result, nil +} + +var _generatedShape = map[string]bool{} + +func GenerateShapeOnce(x shape.Shape, pkgMap *generators.PkgMap, initFunc *[]string, inferred *shape.InferredInfo) (*bytes.Buffer, error) { + key := shape.ToGoTypeName(x, shape.WithPkgImportName()) + if _generatedShape[key] { + log.Debugf("mkunion.GenerateShapeOnce: shape %s already generated", key) + return nil, nil + } + + result := bytes.Buffer{} + + switch x := x.(type) { + case *shape.RefName: + y := inferred.RetrieveShapeFromRef(x) + if y == nil { + log.Warnf("mkunion.GenerateShapeOnce: failed to lookup shape %s", shape.ToGoTypeName(x, shape.WithPkgImportName())) + return nil, nil + } + + switch y := y.(type) { + case *shape.RefName: + log.Warnf("mkunion.GenerateShapeOnce: lookup RefName %s", shape.ToGoTypeName(y, shape.WithPkgImportName())) + return nil, nil + } + + return GenerateShapeOnce(y, pkgMap, initFunc, inferred) + + case *shape.UnionLike: + for _, v := range x.Variant { + key := shape.ToGoTypeName(v, shape.WithPkgImportName()) + _generatedShape[key] = true + } + } + + _generatedShape[key] = true + + gen := generators.NewShapeTagged(x) + gen.SkipImportsAndPackage(true) + gen.SkipInitFunc(true) + + result.WriteString("//shape:shape\n") + contents, err := gen.Generate() + if err != nil { + return nil, fmt.Errorf("mkunion.GenerateShapeOnce: failed to generate tagged shape for %s: %w", shape.ToGoTypeName(x, shape.WithPkgImportName()), err) + } + result.WriteString(contents) + + *pkgMap = generators.MergePkgMaps(*pkgMap, + gen.ExtractImports(x), + ) + + *initFunc = append(*initFunc, gen.ExtractImportFuncs(x)...) + + return &result, nil +} + +func SaveFile(contents bytes.Buffer, sourcePath string, infix string) error { + if len(contents.Bytes()) == 0 { + return nil + } + + sourceName := path.Base(sourcePath) + baseName := strings.TrimSuffix(sourceName, path.Ext(sourceName)) + fileName := path.Join( + path.Dir(sourcePath), + fmt.Sprintf("%s_%s.go", baseName, infix), + ) + + log.Infof("writing %s", fileName) + err := os.WriteFile(fileName, contents.Bytes(), 0644) + if err != nil { + return fmt.Errorf("mkunion.SaveFile: failed to write serde in %s: %w", sourcePath, err) + } + return nil +} diff --git a/dev/bootstrap.sh b/dev/bootstrap.sh index 25dc1ea4..a910865a 100755 --- a/dev/bootstrap.sh +++ b/dev/bootstrap.sh @@ -40,5 +40,12 @@ echo "export AWS_SQS_QUEUE_URL=$queue_url" >> $envrc_file echo "Localstack is UI is at port" echo "http://localhost:8080" +## check if it should stream logs, or just end +## don't trigger trap on exit +if [ "$1" == "-nologs" ]; then + trap - EXIT + exit 0 +fi + echo "Streaming logs" docker compose -f $cwd/compose.yml logs -f diff --git a/example/my-app/server.go b/example/my-app/server.go index b6c2680f..dc8af21d 100644 --- a/example/my-app/server.go +++ b/example/my-app/server.go @@ -197,8 +197,6 @@ func main() { })) e.POST("/message", TypedJSONRequest( - ChatCMDFromJSON, - ChatResultToJSON, func(x ChatCMD) (ChatResult, error) { ctx := context.Background() @@ -354,8 +352,6 @@ func main() { }) e.POST("/flow", TypedJSONRequest( - workflow.WorkflowFromJSON, - workflow.WorkflowToJSON, func(x workflow.Workflow) (workflow.Workflow, error) { flow, ok := x.(*workflow.Flow) if !ok { @@ -500,8 +496,6 @@ func main() { }) e.POST("/", TypedJSONRequest( - workflow.CommandFromJSON, - workflow.StateToJSON, func(cmd workflow.Command) (workflow.State, error) { return srv.CreateOrUpdate(cmd) })) @@ -523,8 +517,6 @@ func main() { }) e.POST("/callback", TypedJSONRequest( - workflow.CommandFromJSON, - workflow.StateToJSON, func(cmd workflow.Command) (workflow.State, error) { callbackCMD, ok := cmd.(*workflow.Callback) if !ok { @@ -699,7 +691,7 @@ AND Data["workflow.Scheduled"].ExpectedRunTimestamp > 0 log.Infof("exiting") } -func TypedJSONRequest[A, B any](des func([]byte) (A, error), ser func(B) ([]byte, error), handle func(x A) (B, error)) func(c echo.Context) error { +func TypedJSONRequest[A, B any](handle func(x A) (B, error)) func(c echo.Context) error { return func(c echo.Context) error { data, err := io.ReadAll(c.Request().Body) if err != nil { @@ -707,7 +699,7 @@ func TypedJSONRequest[A, B any](des func([]byte) (A, error), ser func(B) ([]byte return err } - in, err := des(data) + in, err := shared.JSONUnmarshal[A](data) if err != nil { log.Errorf("TypedJSONRequest: failed to parse request body: %v", err) return err @@ -723,7 +715,7 @@ func TypedJSONRequest[A, B any](des func([]byte) (A, error), ser func(B) ([]byte return fmt.Errorf("TypedJSONRequest: TypedRequest: expected %T, got %T", b, out) } - result, err := ser(out) + result, err := shared.JSONMarshal[B](out) if err != nil { log.Errorf("TypedJSONRequest: failed to convert to json: %v", err) return err diff --git a/example/my-app/src/workflow/github_com_widmogrod_mkunion_exammple_my-app.ts b/example/my-app/src/workflow/github_com_widmogrod_mkunion_exammple_my-app.ts index 369a9fa8..e26c0307 100644 --- a/example/my-app/src/workflow/github_com_widmogrod_mkunion_exammple_my-app.ts +++ b/example/my-app/src/workflow/github_com_widmogrod_mkunion_exammple_my-app.ts @@ -32,53 +32,53 @@ export type ChatResponses = { Responses?: ChatResult[], } -export type FindRecords = schemaless.FindingRecords> +export type Command = workflow.Command -export type FunctionOutput = workflow.FunctionOutput +export type Expr = workflow.Expr -export type UpdateRecords = schemaless.UpdateRecords> +export type FindRecords = schemaless.FindingRecords> export type FunctionInput = workflow.FunctionInput -export type RefreshFlows = {} +export type FunctionOutput = workflow.FunctionOutput export type GenerateImage = { Width?: number, Height?: number, } -export type Schema = schema.Schema - -export type RefreshStates = {} - -export type Service = {} - export type ListWorkflowsFn = { Count?: number, Words?: string[], EnumTest?: string, } -export type Command = workflow.Command +export type PageResult = schemaless.PageResult> + +export type Predicate = workflow.Predicate + +export type RefreshFlows = {} + +export type RefreshStates = {} export type Reshaper = workflow.Reshaper -export type Workflow = workflow.Workflow +export type Schema = schema.Schema -export type State = workflow.State +export type Service = {} -export type Expr = workflow.Expr +export type State = workflow.State -export type Predicate = workflow.Predicate +export type UpdateRecords = schemaless.UpdateRecords> -export type PageResult = schemaless.PageResult> +export type Workflow = workflow.Workflow -//eslint-disable-next-line -import * as schema from './github_com_widmogrod_mkunion_x_schema' //eslint-disable-next-line import * as openai from './github_com_sashabaranov_go-openai' //eslint-disable-next-line +import * as schema from './github_com_widmogrod_mkunion_x_schema' +//eslint-disable-next-line import * as schemaless from './github_com_widmogrod_mkunion_x_storage_schemaless' //eslint-disable-next-line import * as workflow from './github_com_widmogrod_mkunion_x_workflow' diff --git a/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_storage_schemaless.ts b/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_storage_schemaless.ts index b8d742e9..f14750a9 100644 --- a/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_storage_schemaless.ts +++ b/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_storage_schemaless.ts @@ -22,6 +22,12 @@ export type Record = { Version?: number, } +export type PageResult = { + Items?: A[], + Next?: FindingRecords, + Prev?: FindingRecords, +} + export type UpdateRecords = { UpdatingPolicy?: UpdatingPolicy, Saving?: {[key: string]: T}, @@ -30,12 +36,6 @@ export type UpdateRecords = { export type UpdatingPolicy = number -export type PageResult = { - Items?: A[], - Next?: FindingRecords, - Prev?: FindingRecords, -} - //eslint-disable-next-line import * as predicate from './github_com_widmogrod_mkunion_x_storage_predicate' diff --git a/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_workflow.ts b/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_workflow.ts index 075aa28f..7d002d25 100644 --- a/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_workflow.ts +++ b/example/my-app/src/workflow/github_com_widmogrod_mkunion_x_workflow.ts @@ -1,14 +1,4 @@ //generated by mkunion -export type FunctionOutput = { - Result?: schema.Schema, -} - -export type FunctionInput = { - Name?: string, - CallbackID?: string, - Args?: schema.Schema[], -} - export type Command = { "$type"?: "workflow.Run", "workflow.Run": Run @@ -176,6 +166,16 @@ export type ResumeSchedule = { ParentRunID?: string, } +export type FunctionInput = { + Name?: string, + CallbackID?: string, + Args?: schema.Schema[], +} + +export type FunctionOutput = { + Result?: schema.Schema, +} + export type State = { "$type"?: "workflow.NextOperation", "workflow.NextOperation": NextOperation diff --git a/x/generators/model.go b/x/generators/model.go index eb6ba25f..003efc4d 100644 --- a/x/generators/model.go +++ b/x/generators/model.go @@ -46,6 +46,8 @@ func GenerateInitFunc(inits InitFuncs) string { return "" } + sort.Strings(inits) + result := &strings.Builder{} result.WriteString("func init() {\n") diff --git a/x/generators/serde_json_tagged.go b/x/generators/serde_json_tagged.go index 2934e9fa..8750178a 100644 --- a/x/generators/serde_json_tagged.go +++ b/x/generators/serde_json_tagged.go @@ -47,18 +47,20 @@ func (g *SerdeJSONTagged) Generate() (string, error) { } body.WriteString(varPart) - marshalPart, err := g.GenerateMarshalJSON(g.shape) - if err != nil { - return "", fmt.Errorf("generators.SerdeJSONTagged.Generate: when generating marshal %w", err) + if !shape.IsWeekAlias(g.shape) { + marshalPart, err := g.GenerateMarshalJSON(g.shape) + if err != nil { + return "", fmt.Errorf("generators.SerdeJSONTagged.Generate: when generating marshal %w", err) - } - body.WriteString(marshalPart) + } + body.WriteString(marshalPart) - unmarshalPart, err := g.GenerateUnmarshalJSON(g.shape) - if err != nil { - return "", fmt.Errorf("generators.SerdeJSONTagged.Generate: when generating unmarshal %w", err) + unmarshalPart, err := g.GenerateUnmarshalJSON(g.shape) + if err != nil { + return "", fmt.Errorf("generators.SerdeJSONTagged.Generate: when generating unmarshal %w", err) + } + body.WriteString(unmarshalPart) } - body.WriteString(unmarshalPart) head := &strings.Builder{} if !g.skipImportsAndPackage { @@ -236,6 +238,10 @@ func (g *SerdeJSONTagged) GenerateMarshalJSONMethods(x shape.Shape) (string, err g.didGenerateMarshalJSONMethod[methodName] = true } + if shape.IsWeekAlias(x) { + return "", nil + } + rootTypeName := g.rootTypeName() typeName := shape.ToGoTypeName(x, shape.WithRootPackage(shape.ToGoPkgName(g.shape))) errorContext := g.errorContext(methodName) @@ -506,6 +512,10 @@ func (g *SerdeJSONTagged) GenerateUnmarshalJSONMethods(x shape.Shape) (string, e g.didGenerateUnmarshalJSONMethod[methodName] = true } + if shape.IsWeekAlias(x) { + return "", nil + } + rootTypeName := g.rootTypeName() typeName := shape.ToGoTypeName(x, shape.WithRootPackage(shape.ToGoPkgName(g.shape))) errorContext := g.errorContext(methodName) diff --git a/x/generators/serde_json_tagged_test.go b/x/generators/serde_json_tagged_test.go index 881fe952..16adf540 100644 --- a/x/generators/serde_json_tagged_test.go +++ b/x/generators/serde_json_tagged_test.go @@ -6,8 +6,7 @@ import ( "testing" ) -func TestNewSerdeJSONTagged_Struct(t *testing.T) { - //t.Skip("not implemented") +func TestNewSerdeJSONTagged_ListOf2(t *testing.T) { inferred, err := shape.InferFromFile("testutils/tree.go") if err != nil { t.Fatal(err) @@ -370,14 +369,14 @@ func (r *ListOf2[T1,T2]) _unmarshalJSONschema_Schema(data []byte) (schema.Schema `, result) } -func TestNewSerdeJSONTagged_Alias(t *testing.T) { +func TestNewSerdeJSONTagged_ListOfAliasAny(t *testing.T) { inferred, err := shape.InferFromFile("testutils/tree.go") if err != nil { t.Fatal(err) } generator := NewSerdeJSONTagged( - inferred.RetrieveShapeNamedAs("K"), + inferred.RetrieveShapeNamedAs("ListOfAliasAny"), ) result, err := generator.Generate() @@ -390,51 +389,10 @@ import ( ) var ( - _ json.Unmarshaler = (*K)(nil) - _ json.Marshaler = (*K)(nil) + _ json.Unmarshaler = (*ListOfAliasAny)(nil) + _ json.Marshaler = (*ListOfAliasAny)(nil) ) -func (r *K) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil - } - return r._marshalJSONK(*r) -} -func (r *K) _marshalJSONK(x K) ([]byte, error) { - return r._marshalJSONstring(string(x)) -} -func (r *K) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("testutils: K._marshalJSONstring:; %w", err) - } - return result, nil -} -func (r *K) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONK(data) - if err != nil { - return fmt.Errorf("testutils: K.UnmarshalJSON: %w", err) - } - *r = result - return nil -} -func (r *K) _unmarshalJSONK(data []byte) (K, error) { - var result K - intermidiary, err := r._unmarshalJSONstring(data) - if err != nil { - return result, fmt.Errorf("testutils: K._unmarshalJSONK: alias; %w", err) - } - result = K(intermidiary) - return result, nil -} -func (r *K) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("testutils: K._unmarshalJSONstring: native primitive unwrap; %w", err) - } - return result, nil -} `, result) } diff --git a/x/generators/serde_json_union_alias_test.go.asset b/x/generators/serde_json_union_alias_test.go.asset new file mode 100644 index 00000000..351e5a52 --- /dev/null +++ b/x/generators/serde_json_union_alias_test.go.asset @@ -0,0 +1,122 @@ +package testutils + +import ( + "encoding/json" + "fmt" + "github.com/widmogrod/mkunion/x/shared" +) + +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/generators/testutils.Forest", ForestFromJSON, ForestToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/generators/testutils.Tree2", Tree2FromJSON, Tree2ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/generators/testutils.Leaf2", Leaf2FromJSON, Leaf2ToJSON) +} + +type ForestUnionJSON struct { + Type string `json:"$type,omitempty"` + Tree2 json.RawMessage `json:"testutils.Tree2,omitempty"` + Leaf2 json.RawMessage `json:"testutils.Leaf2,omitempty"` +} + +func ForestFromJSON(x []byte) (Forest, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data ForestUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "testutils.Tree2": + return Tree2FromJSON(data.Tree2) + case "testutils.Leaf2": + return Leaf2FromJSON(data.Leaf2) + } + + if data.Tree2 != nil { + return Tree2FromJSON(data.Tree2) + } else if data.Leaf2 != nil { + return Leaf2FromJSON(data.Leaf2) + } + + return nil, fmt.Errorf("testutils.Forest: unknown type %s", data.Type) +} + +func ForestToJSON(x Forest) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchForestR2( + x, + func(x *Tree2) ([]byte, error) { + body, err := Tree2ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ForestUnionJSON{ + Type: "testutils.Tree2", + Tree2: body, + }) + }, + func(x *Leaf2) ([]byte, error) { + body, err := Leaf2ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ForestUnionJSON{ + Type: "testutils.Leaf2", + Leaf2: body, + }) + }, + ) +} + +func Tree2FromJSON(x []byte) (*Tree2, error) { + result := new(Tree2) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func Tree2ToJSON(x *Tree2) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Tree2)(nil) + _ json.Marshaler = (*Tree2)(nil) +) + + + +func Leaf2FromJSON(x []byte) (*Leaf2, error) { + result := new(Leaf2) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func Leaf2ToJSON(x *Leaf2) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Leaf2)(nil) + _ json.Marshaler = (*Leaf2)(nil) +) + + diff --git a/x/generators/serde_json_union_test.go b/x/generators/serde_json_union_test.go index 10ccf6a9..d37d5f5b 100644 --- a/x/generators/serde_json_union_test.go +++ b/x/generators/serde_json_union_test.go @@ -10,7 +10,7 @@ import ( _ "github.com/widmogrod/mkunion/x/generators/testutils" ) -func TestSerdeJSONUnion(t *testing.T) { +func TestSerdeJSONUnion_Generate_Tree(t *testing.T) { log.SetLevel(log.DebugLevel) inferred, err := shape.InferFromFile("testutils/tree.go") assert.NoError(t, err) @@ -24,3 +24,18 @@ func TestSerdeJSONUnion(t *testing.T) { assert.NoError(t, err) assert.Equal(t, string(reference), string(result)) } + +func TestSerdeJSONUnion_Generate_Forest(t *testing.T) { + log.SetLevel(log.DebugLevel) + inferred, err := shape.InferFromFile("testutils/tree.go") + assert.NoError(t, err) + + g := NewSerdeJSONUnion(inferred.RetrieveUnion("Forest")) + + result, err := g.Generate() + assert.NoError(t, err) + + reference, err := os.ReadFile("serde_json_union_alias_test.go.asset") + assert.NoError(t, err) + assert.Equal(t, string(reference), string(result)) +} diff --git a/x/generators/shape_tagged.go b/x/generators/shape_tagged.go index 361a72df..b6545eda 100644 --- a/x/generators/shape_tagged.go +++ b/x/generators/shape_tagged.go @@ -430,7 +430,7 @@ func GuardToString(x shape.Guard) string { fmt.Fprintf(result, "&shape.Enum{\n") if len(x.Val) > 0 { - fmt.Fprintf(result, "\tVal: []string{,\n") + fmt.Fprintf(result, "\tVal: []string{\n") for _, val := range x.Val { fmt.Fprintf(result, "\t\t%q,\n", val) } diff --git a/x/generators/shape_tagged_test.go b/x/generators/shape_tagged_test.go index a039127f..76e832c3 100644 --- a/x/generators/shape_tagged_test.go +++ b/x/generators/shape_tagged_test.go @@ -6,7 +6,7 @@ import ( "testing" ) -func TestShapeTagged_Struct(t *testing.T) { +func TestShapeTagged_ListOf2(t *testing.T) { inferred, err := shape.InferFromFile("testutils/tree.go") if err != nil { t.Fatal(err) @@ -144,3 +144,43 @@ func ListOf2Shape() shape.Shape { } `, result) } +func TestShapeTagged_ListOfAliasAny(t *testing.T) { + inferred, err := shape.InferFromFile("testutils/tree.go") + if err != nil { + t.Fatal(err) + } + + generator := NewShapeTagged( + inferred.RetrieveShapeNamedAs("ListOfAliasAny"), + ) + + result, err := generator.Generate() + assert.NoError(t, err) + assert.Equal(t, `package testutils + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(ListOfAliasAnyShape()) +} + +func ListOfAliasAnyShape() shape.Shape { + return &shape.AliasLike{ + Name: "ListOfAliasAny", + PkgName: "testutils", + PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", + IsAlias: true, + Type: &shape.RefName{ + Name: "ListOf", + PkgName: "testutils", + PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", + Indexed: []shape.Shape{ + &shape.Any{}, + }, + }, + } +} +`, result) +} diff --git a/x/generators/shape_union.go b/x/generators/shape_union.go deleted file mode 100644 index ca07fba4..00000000 --- a/x/generators/shape_union.go +++ /dev/null @@ -1,50 +0,0 @@ -package generators - -import ( - _ "embed" - "github.com/widmogrod/mkunion/x/shape" -) - -func NewShapeUnion(union *shape.UnionLike) *ShapeUnion { - core := NewShapeTagged(union) - return &ShapeUnion{ - gen: core, - } -} - -type ShapeUnion struct { - gen *ShapeTagged -} - -func (g *ShapeUnion) SkipImportsAndPackage(flag bool) { - g.gen.SkipImportsAndPackage(flag) -} - -func (g *ShapeUnion) SkipInitFunc(flag bool) { - g.gen.SkipInitFunc(flag) -} - -func (g *ShapeUnion) GenerateImports(pkgMap PkgMap) (string, error) { - return g.gen.GenerateImports(pkgMap) -} - -func (g *ShapeUnion) ExtractImports(x shape.Shape) PkgMap { - return g.gen.ExtractImports(x) -} - -func (g *ShapeUnion) ExtractImportFuncs(s shape.Shape) []string { - return g.gen.ExtractImportFuncs(s) -} - -func (g *ShapeUnion) GenerateInitFunc(init []string) (string, error) { - return g.gen.GenerateInitFunc(init) -} - -func (g *ShapeUnion) Generate() ([]byte, error) { - result, err := g.gen.Generate() - if err != nil { - return nil, err - } - - return []byte(result), nil -} diff --git a/x/generators/shape_union_test.go b/x/generators/shape_union_test.go deleted file mode 100644 index 54e33750..00000000 --- a/x/generators/shape_union_test.go +++ /dev/null @@ -1,268 +0,0 @@ -package generators - -import ( - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - "github.com/widmogrod/mkunion/x/shape" - "testing" -) - -func TestShapeGenerator(t *testing.T) { - log.SetLevel(log.DebugLevel) - inferred, err := shape.InferFromFile("testutils/tree.go") - assert.NoError(t, err) - - g := NewShapeUnion(inferred.RetrieveUnion("Tree")) - - result, err := g.Generate() - assert.NoError(t, err) - assert.Equal(t, `package testutils - -import ( - "github.com/widmogrod/mkunion/x/shape" -) - -func init() { - shape.Register(TreeShape()) - shape.Register(BranchShape()) - shape.Register(LeafShape()) - shape.Register(KShape()) - shape.Register(PShape()) - shape.Register(MaShape()) - shape.Register(LaShape()) - shape.Register(KaShape()) -} - - -func TreeShape() shape.Shape { - return &shape.UnionLike{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Variant: []shape.Shape{ - BranchShape(), - LeafShape(), - KShape(), - PShape(), - MaShape(), - LaShape(), - KaShape(), - }, - } -} - -func BranchShape() shape.Shape { - return &shape.StructLike{ - Name: "Branch", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Fields: []*shape.FieldLike{ - { - Name: "Lit", - Type: &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - { - Name: "List", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - }, - { - Name: "Map", - Type: &shape.MapLike{ - Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - Val: &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - }, - { - Name: "Of", - Type: &shape.PointerLike{ - Type: &shape.RefName{ - Name: "ListOf", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Indexed: []shape.Shape{ - &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "json": { - Value: "just_of", - }, - }, - }, - { - Name: "L", - Type: &shape.PointerLike{ - Type: &shape.RefName{ - Name: "Leaf", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - }, - { - Name: "Kattr", - Type: &shape.ListLike{ - Element: &shape.PointerLike{ - Type: &shape.RefName{ - Name: "Leaf", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - ArrayLen: shape.Ptr(2), - }, - }, - { - Name: "IntPtr", - Type: &shape.PointerLike{ - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int64{}, - }, - }, - }, - }, - }, - } -} - -func LeafShape() shape.Shape { - return &shape.StructLike{ - Name: "Leaf", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Fields: []*shape.FieldLike{ - { - Name: "Value", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int64{}, - }, - }, - }, - }, - } -} - -func KShape() shape.Shape { - return &shape.AliasLike{ - Name: "K", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - } -} - -func PShape() shape.Shape { - return &shape.AliasLike{ - Name: "P", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Type: &shape.RefName{ - Name: "ListOf2", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Indexed: []shape.Shape{ - &shape.RefName{ - Name: "ListOf", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Indexed: []shape.Shape{ - &shape.Any{}, - }, - }, - &shape.PointerLike{ - Type: &shape.RefName{ - Name: "ListOf2", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Indexed: []shape.Shape{ - &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int64{}, - }, - }, - &shape.PointerLike{ - Type: &shape.RefName{ - Name: "Duration", - PkgName: "time", - PkgImportName: "time", - }, - }, - }, - }, - }, - }, - }, - } -} - -func MaShape() shape.Shape { - return &shape.AliasLike{ - Name: "Ma", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Type: &shape.MapLike{ - Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - Val: &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - } -} - -func LaShape() shape.Shape { - return &shape.AliasLike{ - Name: "La", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - } -} - -func KaShape() shape.Shape { - return &shape.AliasLike{ - Name: "Ka", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - Type: &shape.ListLike{ - Element: &shape.MapLike{ - Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - Val: &shape.RefName{ - Name: "Tree", - PkgName: "testutils", - PkgImportName: "github.com/widmogrod/mkunion/x/generators/testutils", - }, - }, - }, - } -} -`, string(result)) -} diff --git a/x/generators/testutils/tree.go b/x/generators/testutils/tree.go index f7bb986e..28de178d 100644 --- a/x/generators/testutils/tree.go +++ b/x/generators/testutils/tree.go @@ -6,7 +6,6 @@ import ( ) //go:generate go run ../../../cmd/mkunion/main.go -//go:generate go run ../../../cmd/mkunion/main.go serde //go:tag mkunion:"Tree" type ( @@ -27,6 +26,14 @@ type ( Ka []map[string]Tree ) +//go:tag mkunion:"Forest" +type ( + Tree2 = Branch + Leaf2 = Leaf +) + +type ListOfAliasAny = ListOf[any] + //go:tag serde:"json" type ListOf[T any] struct { Data T diff --git a/x/schema/go.go b/x/schema/go.go index ebf62f87..dd015488 100644 --- a/x/schema/go.go +++ b/x/schema/go.go @@ -25,34 +25,34 @@ func FromPrimitiveGo(x any) Schema { return MkBool(y) case int: - return MkInt(uint64(y)) + return MkInt(int64(y)) case int8: - return MkInt(uint64(y)) + return MkInt(int64(y)) case int16: - return MkInt(uint64(y)) + return MkInt(int64(y)) case int32: - return MkInt(uint64(y)) + return MkInt(int64(y)) case int64: - return MkInt(uint64(y)) + return MkInt(int64(y)) case uint: - return MkInt(uint64(y)) + return MkUint(uint64(y)) case uint8: - return MkInt(uint64(y)) + return MkUint(uint64(y)) case uint16: - return MkInt(uint64(y)) + return MkUint(uint64(y)) case uint32: - return MkInt(uint64(y)) + return MkUint(uint64(y)) case uint64: - return MkInt(uint64(y)) + return MkUint(uint64(y)) case float32: return MkFloat(float64(y)) @@ -147,15 +147,15 @@ func ToGoPrimitive(x Schema) (any, error) { } func ToGoG[A any](x Schema) (res A, err error) { - defer func() { - if r := recover(); r != nil { - if e, ok := r.(error); ok { - err = fmt.Errorf("schema.ToGoG: panic recover; %w", e) - } else { - err = fmt.Errorf("schema.ToGoG: panic recover; %#v", e) - } - } - }() + //defer func() { + // if r := recover(); r != nil { + // if e, ok := r.(error); ok { + // err = fmt.Errorf("schema.ToGoG: panic recover; %w", e) + // } else { + // err = fmt.Errorf("schema.ToGoG: panic recover; %#v", e) + // } + // } + //}() res = ToGo[A](x) return @@ -168,7 +168,36 @@ func ToGo[A any](x Schema) A { panic(fmt.Errorf("schema.ToGo: primitive; %w", err)) } - return value.(A) + var result A + switch y := value.(type) { + case float64: + switch any(result).(type) { + case int: + return any(int(y)).(A) + //case int8: + // return any(int8(y)).(A) + //case int16: + // return any(int16(y)).(A) + //case int32: + // return any(int32(y)).(A) + //case int64: + // return any(int64(y)).(A) + //case uint: + // return any(uint(y)).(A) + //case uint8: + // return any(uint8(y)).(A) + //case uint16: + // return any(uint16(y)).(A) + //case uint32: + // return any(uint32(y)).(A) + //case uint64: + // return any(uint64(y)).(A) + //case float32: + // return any(float32(y)).(A) + case float64: + return any(float64(y)).(A) + } + } } v := reflect.TypeOf(new(A)).Elem() @@ -265,34 +294,34 @@ func FromGoReflect(xschema shape.Shape, yreflect reflect.Value) Schema { return shape.MatchNumberKindR1( x.Kind, func(x *shape.UInt) Schema { - return MkInt(uint64(yreflect.Uint())) + return MkUint(yreflect.Uint()) }, func(x *shape.UInt8) Schema { - return MkInt(uint64(yreflect.Uint())) + return MkUint(yreflect.Uint()) }, func(x *shape.UInt16) Schema { - return MkInt(uint64(yreflect.Uint())) + return MkUint(yreflect.Uint()) }, func(x *shape.UInt32) Schema { - return MkInt(uint64(yreflect.Uint())) + return MkUint(yreflect.Uint()) }, func(x *shape.UInt64) Schema { - return MkInt(uint64(yreflect.Uint())) + return MkUint(yreflect.Uint()) }, func(x *shape.Int) Schema { - return MkInt(uint64(yreflect.Int())) + return MkInt(yreflect.Int()) }, func(x *shape.Int8) Schema { - return MkInt(uint64(yreflect.Int())) + return MkInt(yreflect.Int()) }, func(x *shape.Int16) Schema { - return MkInt(uint64(yreflect.Int())) + return MkInt(yreflect.Int()) }, func(x *shape.Int32) Schema { - return MkInt(uint64(yreflect.Int())) + return MkInt(yreflect.Int()) }, func(x *shape.Int64) Schema { - return MkInt(uint64(yreflect.Int())) + return MkInt(yreflect.Int()) }, func(x *shape.Float32) Schema { return MkFloat(yreflect.Float()) diff --git a/x/schema/location.go b/x/schema/location.go index 21c44b26..93005709 100644 --- a/x/schema/location.go +++ b/x/schema/location.go @@ -5,7 +5,9 @@ import ( "strings" ) -//go:generate go run ../../cmd/mkunion/main.go -name=Location -skip-extension=schema,shape +//go:generate go run ../../cmd/mkunion/main.go + +//go:tag mkunion:"Location" type ( LocationField struct { Name string diff --git a/x/schema/location_shape_gen.go b/x/schema/location_shape_gen.go new file mode 100644 index 00000000..9fb378c7 --- /dev/null +++ b/x/schema/location_shape_gen.go @@ -0,0 +1,68 @@ +// Code generated by mkunion. DO NOT EDIT. +package schema + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(LocationAnythingShape()) + shape.Register(LocationFieldShape()) + shape.Register(LocationIndexShape()) + shape.Register(LocationShape()) +} + +//shape:shape + +func LocationShape() shape.Shape { + return &shape.UnionLike{ + Name: "Location", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Variant: []shape.Shape{ + LocationFieldShape(), + LocationIndexShape(), + LocationAnythingShape(), + }, + } +} + +func LocationFieldShape() shape.Shape { + return &shape.StructLike{ + Name: "LocationField", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Fields: []*shape.FieldLike{ + { + Name: "Name", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +func LocationIndexShape() shape.Shape { + return &shape.StructLike{ + Name: "LocationIndex", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Fields: []*shape.FieldLike{ + { + Name: "Index", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + }, + } +} + +func LocationAnythingShape() shape.Shape { + return &shape.StructLike{ + Name: "LocationAnything", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + } +} diff --git a/x/schema/location_union_gen.go b/x/schema/location_union_gen.go index b711db36..ed729d64 100644 --- a/x/schema/location_union_gen.go +++ b/x/schema/location_union_gen.go @@ -4,17 +4,9 @@ package schema import ( "encoding/json" "fmt" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(LocationShape()) - shape.Register(LocationFieldShape()) - shape.Register(LocationIndexShape()) - shape.Register(LocationAnythingShape()) -} - type LocationVisitor interface { VisitLocationField(v *LocationField) any VisitLocationIndex(v *LocationIndex) any @@ -107,59 +99,6 @@ func MatchLocationR0( f3(v) } } - -func LocationShape() shape.Shape { - return &shape.UnionLike{ - Name: "Location", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Variant: []shape.Shape{ - LocationFieldShape(), - LocationIndexShape(), - LocationAnythingShape(), - }, - } -} - -func LocationFieldShape() shape.Shape { - return &shape.StructLike{ - Name: "LocationField", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Fields: []*shape.FieldLike{ - { - Name: "Name", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - }, - } -} - -func LocationIndexShape() shape.Shape { - return &shape.StructLike{ - Name: "LocationIndex", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Fields: []*shape.FieldLike{ - { - Name: "Index", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int{}, - }, - }, - }, - }, - } -} - -func LocationAnythingShape() shape.Shape { - return &shape.StructLike{ - Name: "LocationAnything", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - } -} func init() { shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/schema.Location", LocationFromJSON, LocationToJSON) shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/schema.LocationField", LocationFieldFromJSON, LocationFieldToJSON) diff --git a/x/schema/model.go b/x/schema/model.go index 1fba3ff2..4a9d7c07 100644 --- a/x/schema/model.go +++ b/x/schema/model.go @@ -1,8 +1,8 @@ package schema -//go:generate go run ../../cmd/mkunion/main.go serde +//go:generate go run ../../cmd/mkunion/main.go -//go:generate go run ../../cmd/mkunion/main.go -name=Schema +//go:tag mkunion:"Schema" type ( None struct{} Bool bool @@ -34,7 +34,12 @@ func MkBool(b bool) *Bool { return (*Bool)(&b) } -func MkInt(x uint64) *Number { +func MkInt(x int64) *Number { + v := float64(x) + return (*Number)(&v) +} + +func MkUint(x uint64) *Number { v := float64(x) return (*Number)(&v) } @@ -71,3 +76,8 @@ func MkField(name string, value Schema) Field { Value: value, } } + +func AppendList(list *List, items ...Schema) *List { + result := append(*list, items...) + return &result +} diff --git a/x/schema/model_serde_gen.go b/x/schema/model_serde_gen.go index 786c9f2b..d6e319ab 100644 --- a/x/schema/model_serde_gen.go +++ b/x/schema/model_serde_gen.go @@ -4,14 +4,9 @@ package schema import ( "encoding/json" "fmt" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(FieldShape()) -} - var ( _ json.Unmarshaler = (*Field)(nil) _ json.Marshaler = (*Field)(nil) @@ -102,29 +97,3 @@ func (r *Field) _unmarshalJSONSchema(data []byte) (Schema, error) { } return result, nil } -func FieldShape() shape.Shape { - return &shape.StructLike{ - Name: "Field", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Fields: []*shape.FieldLike{ - { - Name: "Name", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Value", - Type: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} diff --git a/x/schema/model_shape_gen.go b/x/schema/model_shape_gen.go new file mode 100644 index 00000000..9e426193 --- /dev/null +++ b/x/schema/model_shape_gen.go @@ -0,0 +1,150 @@ +// Code generated by mkunion. DO NOT EDIT. +package schema + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(BinaryShape()) + shape.Register(BoolShape()) + shape.Register(FieldShape()) + shape.Register(ListShape()) + shape.Register(MapShape()) + shape.Register(NoneShape()) + shape.Register(NumberShape()) + shape.Register(SchemaShape()) + shape.Register(StringShape()) +} + +//shape:shape + +func SchemaShape() shape.Shape { + return &shape.UnionLike{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Variant: []shape.Shape{ + NoneShape(), + BoolShape(), + NumberShape(), + StringShape(), + BinaryShape(), + ListShape(), + MapShape(), + }, + } +} + +func NoneShape() shape.Shape { + return &shape.StructLike{ + Name: "None", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + } +} + +func BoolShape() shape.Shape { + return &shape.AliasLike{ + Name: "Bool", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Type: &shape.PrimitiveLike{Kind: &shape.BooleanLike{}}, + } +} + +func NumberShape() shape.Shape { + return &shape.AliasLike{ + Name: "Number", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Float64{}, + }, + }, + } +} + +func StringShape() shape.Shape { + return &shape.AliasLike{ + Name: "String", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + } +} + +func BinaryShape() shape.Shape { + return &shape.AliasLike{ + Name: "Binary", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Type: &shape.ListLike{ + Element: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.UInt8{}, + }, + }, + }, + } +} + +func ListShape() shape.Shape { + return &shape.AliasLike{ + Name: "List", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + } +} + +func MapShape() shape.Shape { + return &shape.AliasLike{ + Name: "Map", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + } +} + +//shape:shape +func FieldShape() shape.Shape { + return &shape.StructLike{ + Name: "Field", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + Fields: []*shape.FieldLike{ + { + Name: "Name", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Value", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} diff --git a/x/schema/model_union_gen.go b/x/schema/model_union_gen.go index b3bbc246..e39cd516 100644 --- a/x/schema/model_union_gen.go +++ b/x/schema/model_union_gen.go @@ -4,21 +4,9 @@ package schema import ( "encoding/json" "fmt" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(SchemaShape()) - shape.Register(NoneShape()) - shape.Register(BoolShape()) - shape.Register(NumberShape()) - shape.Register(StringShape()) - shape.Register(BinaryShape()) - shape.Register(ListShape()) - shape.Register(MapShape()) -} - type SchemaVisitor interface { VisitNone(v *None) any VisitBool(v *Bool) any @@ -171,108 +159,6 @@ func MatchSchemaR0( f7(v) } } - -func SchemaShape() shape.Shape { - return &shape.UnionLike{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Variant: []shape.Shape{ - NoneShape(), - BoolShape(), - NumberShape(), - StringShape(), - BinaryShape(), - ListShape(), - MapShape(), - }, - } -} - -func NoneShape() shape.Shape { - return &shape.StructLike{ - Name: "None", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - } -} - -func BoolShape() shape.Shape { - return &shape.AliasLike{ - Name: "Bool", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Type: &shape.PrimitiveLike{Kind: &shape.BooleanLike{}}, - } -} - -func NumberShape() shape.Shape { - return &shape.AliasLike{ - Name: "Number", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Float64{}, - }, - }, - } -} - -func StringShape() shape.Shape { - return &shape.AliasLike{ - Name: "String", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - } -} - -func BinaryShape() shape.Shape { - return &shape.AliasLike{ - Name: "Binary", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Type: &shape.ListLike{ - Element: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.UInt8{}, - }, - }, - }, - } -} - -func ListShape() shape.Shape { - return &shape.AliasLike{ - Name: "List", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - } -} - -func MapShape() shape.Shape { - return &shape.AliasLike{ - Name: "Map", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - Type: &shape.MapLike{ - Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - Val: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - } -} func init() { shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/schema.Schema", SchemaFromJSON, SchemaToJSON) shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/schema.None", NoneFromJSON, NoneToJSON) diff --git a/x/schema/testutil/max.go b/x/schema/testutil/max.go index 940368dc..bcc1cbfa 100644 --- a/x/schema/testutil/max.go +++ b/x/schema/testutil/max.go @@ -1,6 +1,6 @@ package testutil -//go:generate go run ../../../cmd/mkunion/main.go serde +//go:generate go run ../../../cmd/mkunion/main.go //go:tag serde:"json" type Max struct { diff --git a/x/schema/testutil/max_test.go b/x/schema/testutil/max_test.go index 035fecff..a2e295cb 100644 --- a/x/schema/testutil/max_test.go +++ b/x/schema/testutil/max_test.go @@ -39,11 +39,11 @@ func TestMaxScalars(t *testing.T) { "Int64": schema.MkInt(math.MaxInt64), "Float32": schema.MkFloat(math.MaxFloat32), "Float64": schema.MkFloat(math.MaxFloat64), - "Uint": schema.MkInt(math.MaxUint), - "Uint8": schema.MkInt(math.MaxInt8), - "Uint16": schema.MkInt(math.MaxUint16), - "Uint32": schema.MkInt(math.MaxUint32), - "Uint64": schema.MkInt(math.MaxUint64), + "Uint": schema.MkUint(math.MaxUint), + "Uint8": schema.MkUint(math.MaxInt8), + "Uint16": schema.MkUint(math.MaxUint16), + "Uint32": schema.MkUint(math.MaxUint32), + "Uint64": schema.MkUint(math.MaxUint64), }, s) }) } diff --git a/x/shape/fromfile.go b/x/shape/fromfile.go index 78adb416..6056c489 100644 --- a/x/shape/fromfile.go +++ b/x/shape/fromfile.go @@ -12,6 +12,7 @@ import ( "path" "path/filepath" "regexp" + "sort" "strconv" "strings" ) @@ -225,32 +226,48 @@ func (f *InferredInfo) RetrieveUnion(name string) *UnionLike { func (f *InferredInfo) RetrieveShapes() []Shape { shapes := make(map[string]Shape) + + ordered := make([]string, 0) for name, shape := range f.shapes { shapes[name] = shape + ordered = append(ordered, name) } + sort.Strings(ordered) - var result = make([]Shape, 0) - for unionName, variantsNames := range f.possibleVariantTypes { + var result []Shape + unionNames := f.sortedPossibleUnionNames() + for _, unionName := range unionNames { union := f.RetrieveUnion(unionName) if union == nil { continue } result = append(result, union) - delete(shapes, unionName) - for _, variantName := range variantsNames { + for _, variantName := range f.possibleVariantTypes[unionName] { delete(shapes, variantName) } } - for _, shape := range shapes { - result = append(result, shape) + for _, name := range ordered { + if _, ok := shapes[name]; !ok { + continue + } + result = append(result, shapes[name]) } return result } +func (f *InferredInfo) sortedPossibleUnionNames() []string { + unionNames := make([]string, len(f.possibleVariantTypes)) + for unionName := range f.possibleVariantTypes { + unionNames = append(unionNames, unionName) + } + sort.Strings(unionNames) + return unionNames +} + func (f *InferredInfo) RetrieveStructs() []*StructLike { var result []*StructLike for _, shape := range f.RetrieveShapes() { @@ -266,6 +283,18 @@ func (f *InferredInfo) RetrieveShapeNamedAs(name string) Shape { return f.shapes[name] } +func (f *InferredInfo) RetrieveShapeFromRef(x *RefName) Shape { + shapes := f.RetrieveShapes() + for _, shape := range shapes { + // weak check + if Name(shape) == Name(x) { + return shape + } + } + + return nil +} + func (f *InferredInfo) RetrieveShapesTaggedAs(tagName string) []Shape { var result []Shape for _, shape := range f.RetrieveShapes() { @@ -392,7 +421,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: &PrimitiveLike{Kind: &StringLike{}}, Tags: f.possibleTaggedTypes[f.currentType], } @@ -404,7 +433,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: &PrimitiveLike{ Kind: &NumberLike{ Kind: TypeStringToNumberKindMap[next.Name], @@ -418,7 +447,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: &PrimitiveLike{Kind: &BooleanLike{}}, Tags: f.possibleTaggedTypes[f.currentType], } @@ -431,7 +460,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: &RefName{ Name: next.Name, PkgName: f.pkgName, @@ -449,7 +478,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: f.selectExrToShape(next), Tags: f.possibleTaggedTypes[f.currentType], } @@ -463,7 +492,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: FromAST(next, opt...), Tags: f.possibleTaggedTypes[f.currentType], } @@ -477,7 +506,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: FromAST(next, opt...), Tags: f.possibleTaggedTypes[f.currentType], } @@ -490,7 +519,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: &MapLike{ Key: FromAST(next.Key, opt...), Val: FromAST(next.Value, opt...), @@ -505,7 +534,7 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { Name: f.currentType, PkgName: f.pkgName, PkgImportName: f.pkgImportName, - IsAlias: IsAlias(t), + IsAlias: IsASTAlias(t), Type: &ListLike{ Element: FromAST(next.Elt, opt...), //ElementIsPointer: IsStarExpr(next.Elt), @@ -522,6 +551,20 @@ func (f *InferredInfo) Visit(n ast.Node) ast.Visitor { TypeParams: f.extractTypeParams(t.TypeParams), Tags: f.possibleTaggedTypes[f.currentType], } + + case *ast.StarExpr: + // example: + // type A *string + // type B = *int + f.shapes[f.currentType] = &AliasLike{ + Name: f.currentType, + PkgName: f.pkgName, + PkgImportName: f.pkgImportName, + IsAlias: IsASTAlias(t), + Type: &PointerLike{ + Type: FromAST(next.X, opt...), + }, + } } case *ast.StructType: @@ -818,7 +861,7 @@ func (f *InferredInfo) optionAST() []FromASTOption { } } -func IsAlias(t *ast.TypeSpec) bool { +func IsASTAlias(t *ast.TypeSpec) bool { return t.Assign != 0 } diff --git a/x/shape/fromfile_test.go b/x/shape/fromfile_test.go index 9da2ff63..6f475487 100644 --- a/x/shape/fromfile_test.go +++ b/x/shape/fromfile_test.go @@ -341,4 +341,44 @@ func TestInferFromFile(t *testing.T) { if diff := cmp.Diff(expected2, strut); diff != "" { t.Errorf("mismatch (-want +got):\n%s", diff) } + + alias := inferred.RetrieveUnion("AliasExample") + expected3 := &UnionLike{ + Name: "AliasExample", + PkgName: "testasset", + PkgImportName: "github.com/widmogrod/mkunion/x/shape/testasset", + Variant: []Shape{ + &AliasLike{ + Name: "A2", + PkgName: "testasset", + PkgImportName: "github.com/widmogrod/mkunion/x/shape/testasset", + IsAlias: true, + Type: &RefName{ + Name: "A", + PkgName: "testasset", + PkgImportName: "github.com/widmogrod/mkunion/x/shape/testasset", + }, + }, + &AliasLike{ + Name: "B2", + PkgName: "testasset", + PkgImportName: "github.com/widmogrod/mkunion/x/shape/testasset", + IsAlias: true, + Type: &RefName{ + Name: "B", + PkgName: "testasset", + PkgImportName: "github.com/widmogrod/mkunion/x/shape/testasset", + }, + }, + }, + Tags: map[string]Tag{ + "mkunion": { + Value: "AliasExample", + }, + }, + } + + if diff := cmp.Diff(expected3, alias); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } } diff --git a/x/shape/fromgo_test.go b/x/shape/fromgo_test.go index cede2bc3..25b7ac64 100644 --- a/x/shape/fromgo_test.go +++ b/x/shape/fromgo_test.go @@ -141,7 +141,7 @@ func TestFromGoo(t *testing.T) { }, { Name: "ArrayLen", - Type: &PointerLike{Type: &PrimitiveLike{&NumberLike{}}}, + Type: &PointerLike{Type: &PrimitiveLike{&NumberLike{Kind: &Int{}}}}, }, }, }, diff --git a/x/shape/lookup_refs.go b/x/shape/lookup_refs.go index f01d7275..a5fa4642 100644 --- a/x/shape/lookup_refs.go +++ b/x/shape/lookup_refs.go @@ -118,7 +118,7 @@ var onDiskCache = sync.Map{} // it's suited for generators, that parse AST func LookupShapeOnDisk(x *RefName) (Shape, bool) { key := shapeFullName(x) - log.Infof("shape.LookupShapeOnDisk: %s", key) + log.Debugf("shape.LookupShapeOnDisk: %s", key) if v, ok := onDiskCache.Load(key); ok { return v.(Shape), true } diff --git a/x/shape/shape.go b/x/shape/shape.go index 1dd76706..eab733af 100644 --- a/x/shape/shape.go +++ b/x/shape/shape.go @@ -1,7 +1,6 @@ package shape // go:generate ../../cmd/mkunion/mkunion -// go:generate ../../cmd/mkunion/mkunion serde //go:tag mkunion:"Shape" type ( @@ -316,6 +315,19 @@ func UnwrapPointer(x string) string { return x } +// IsWeekAlias returns true if given shape is an alias and it's week alias. +// example: +// +// type A = string +func IsWeekAlias(x Shape) bool { + alias, isAlias := x.(*AliasLike) + if !isAlias { + return false + } + + return alias.IsAlias +} + func IsString(x Shape) bool { prim, isPrimitive := x.(*PrimitiveLike) if !isPrimitive { diff --git a/x/shape/shape_serde_gen.go b/x/shape/shape_serde_gen.go index df862cef..1197232d 100644 --- a/x/shape/shape_serde_gen.go +++ b/x/shape/shape_serde_gen.go @@ -7,10 +7,6 @@ import ( "github.com/widmogrod/mkunion/x/shared" ) -func init() { - Register(TypeParamShape()) -} - var ( _ json.Unmarshaler = (*TypeParam)(nil) _ json.Marshaler = (*TypeParam)(nil) @@ -101,29 +97,3 @@ func (r *TypeParam) _unmarshalJSONShape(data []byte) (Shape, error) { } return result, nil } -func TypeParamShape() Shape { - return &StructLike{ - Name: "TypeParam", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Name", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "Type", - Type: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - Tags: map[string]Tag{ - "serde": { - Value: "json", - }, - }, - } -} diff --git a/x/shape/shape_shape_gen.go b/x/shape/shape_shape_gen.go new file mode 100644 index 00000000..38152896 --- /dev/null +++ b/x/shape/shape_shape_gen.go @@ -0,0 +1,658 @@ +// Code generated by mkunion. DO NOT EDIT. +package shape + +func init() { + Register(PrimitiveKindShape()) + Register(BooleanLikeShape()) + Register(StringLikeShape()) + Register(NumberLikeShape()) + Register(NumberKindShape()) + Register(UIntShape()) + Register(UInt8Shape()) + Register(UInt16Shape()) + Register(UInt32Shape()) + Register(UInt64Shape()) + Register(IntShape()) + Register(Int8Shape()) + Register(Int16Shape()) + Register(Int32Shape()) + Register(Int64Shape()) + Register(Float32Shape()) + Register(Float64Shape()) + Register(GuardShape()) + Register(EnumShape()) + Register(RequiredShape()) + Register(AndGuardShape()) + Register(ShapeShape()) + Register(AnyShape()) + Register(RefNameShape()) + Register(PointerLikeShape()) + Register(AliasLikeShape()) + Register(PrimitiveLikeShape()) + Register(ListLikeShape()) + Register(MapLikeShape()) + Register(StructLikeShape()) + Register(UnionLikeShape()) + Register(TagShape()) + Register(TypeParamShape()) + Register(FieldLikeShape()) +} + +//shape:shape + +func PrimitiveKindShape() Shape { + return &UnionLike{ + Name: "PrimitiveKind", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Variant: []Shape{ + BooleanLikeShape(), + StringLikeShape(), + NumberLikeShape(), + }, + } +} + +func BooleanLikeShape() Shape { + return &StructLike{ + Name: "BooleanLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func StringLikeShape() Shape { + return &StructLike{ + Name: "StringLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func NumberLikeShape() Shape { + return &StructLike{ + Name: "NumberLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Kind", + Type: &RefName{ + Name: "NumberKind", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + } +} + +//shape:shape + +func NumberKindShape() Shape { + return &UnionLike{ + Name: "NumberKind", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Variant: []Shape{ + UIntShape(), + UInt8Shape(), + UInt16Shape(), + UInt32Shape(), + UInt64Shape(), + IntShape(), + Int8Shape(), + Int16Shape(), + Int32Shape(), + Int64Shape(), + Float32Shape(), + Float64Shape(), + }, + } +} + +func UIntShape() Shape { + return &StructLike{ + Name: "UInt", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func UInt8Shape() Shape { + return &StructLike{ + Name: "UInt8", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func UInt16Shape() Shape { + return &StructLike{ + Name: "UInt16", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func UInt32Shape() Shape { + return &StructLike{ + Name: "UInt32", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func UInt64Shape() Shape { + return &StructLike{ + Name: "UInt64", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func IntShape() Shape { + return &StructLike{ + Name: "Int", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func Int8Shape() Shape { + return &StructLike{ + Name: "Int8", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func Int16Shape() Shape { + return &StructLike{ + Name: "Int16", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func Int32Shape() Shape { + return &StructLike{ + Name: "Int32", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func Int64Shape() Shape { + return &StructLike{ + Name: "Int64", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func Float32Shape() Shape { + return &StructLike{ + Name: "Float32", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func Float64Shape() Shape { + return &StructLike{ + Name: "Float64", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +//shape:shape + +func GuardShape() Shape { + return &UnionLike{ + Name: "Guard", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Variant: []Shape{ + EnumShape(), + RequiredShape(), + AndGuardShape(), + }, + } +} + +func EnumShape() Shape { + return &StructLike{ + Name: "Enum", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Val", + Type: &ListLike{ + Element: &PrimitiveLike{Kind: &StringLike{}}, + }, + }, + }, + } +} + +func RequiredShape() Shape { + return &StructLike{ + Name: "Required", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func AndGuardShape() Shape { + return &StructLike{ + Name: "AndGuard", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "L", + Type: &ListLike{ + Element: &RefName{ + Name: "Guard", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + } +} + +//shape:shape + +func ShapeShape() Shape { + return &UnionLike{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Variant: []Shape{ + AnyShape(), + RefNameShape(), + PointerLikeShape(), + AliasLikeShape(), + PrimitiveLikeShape(), + ListLikeShape(), + MapLikeShape(), + StructLikeShape(), + UnionLikeShape(), + }, + } +} + +func AnyShape() Shape { + return &StructLike{ + Name: "Any", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + } +} + +func RefNameShape() Shape { + return &StructLike{ + Name: "RefName", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Name", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgImportName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "Indexed", + Type: &ListLike{ + Element: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + } +} + +func PointerLikeShape() Shape { + return &StructLike{ + Name: "PointerLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Type", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + } +} + +func AliasLikeShape() Shape { + return &StructLike{ + Name: "AliasLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Name", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgImportName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "IsAlias", + Type: &PrimitiveLike{Kind: &BooleanLike{}}, + }, + { + Name: "Type", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + { + Name: "Tags", + Type: &MapLike{ + Key: &PrimitiveLike{Kind: &StringLike{}}, + Val: &RefName{ + Name: "Tag", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + } +} + +func PrimitiveLikeShape() Shape { + return &StructLike{ + Name: "PrimitiveLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Kind", + Type: &RefName{ + Name: "PrimitiveKind", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + } +} + +func ListLikeShape() Shape { + return &StructLike{ + Name: "ListLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Element", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + { + Name: "ArrayLen", + Type: &PointerLike{ + Type: &PrimitiveLike{ + Kind: &NumberLike{ + Kind: &Int{}, + }, + }, + }, + }, + }, + } +} + +func MapLikeShape() Shape { + return &StructLike{ + Name: "MapLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Key", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + { + Name: "Val", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + } +} + +func StructLikeShape() Shape { + return &StructLike{ + Name: "StructLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Name", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgImportName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "TypeParams", + Type: &ListLike{ + Element: &RefName{ + Name: "TypeParam", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + { + Name: "Fields", + Type: &ListLike{ + Element: &PointerLike{ + Type: &RefName{ + Name: "FieldLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + { + Name: "Tags", + Type: &MapLike{ + Key: &PrimitiveLike{Kind: &StringLike{}}, + Val: &RefName{ + Name: "Tag", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + } +} + +func UnionLikeShape() Shape { + return &StructLike{ + Name: "UnionLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Name", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "PkgImportName", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "Variant", + Type: &ListLike{ + Element: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + { + Name: "Tags", + Type: &MapLike{ + Key: &PrimitiveLike{Kind: &StringLike{}}, + Val: &RefName{ + Name: "Tag", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + } +} + +//shape:shape +func TagShape() Shape { + return &StructLike{ + Name: "Tag", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Value", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "Options", + Type: &ListLike{ + Element: &PrimitiveLike{Kind: &StringLike{}}, + }, + }, + }, + } +} + +//shape:shape +func TypeParamShape() Shape { + return &StructLike{ + Name: "TypeParam", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Name", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "Type", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + Tags: map[string]Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func FieldLikeShape() Shape { + return &StructLike{ + Name: "FieldLike", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + Fields: []*FieldLike{ + { + Name: "Name", + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + { + Name: "Type", + Type: &RefName{ + Name: "Shape", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + { + Name: "Desc", + Type: &PointerLike{ + Type: &PrimitiveLike{Kind: &StringLike{}}, + }, + }, + { + Name: "Guard", + Type: &RefName{ + Name: "Guard", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + { + Name: "Tags", + Type: &MapLike{ + Key: &PrimitiveLike{Kind: &StringLike{}}, + Val: &RefName{ + Name: "Tag", + PkgName: "shape", + PkgImportName: "github.com/widmogrod/mkunion/x/shape", + }, + }, + }, + }, + } +} diff --git a/x/shape/shape_union_gen.go b/x/shape/shape_union_gen.go index 0d898f2d..7bb4edd9 100644 --- a/x/shape/shape_union_gen.go +++ b/x/shape/shape_union_gen.go @@ -7,109 +7,93 @@ import ( "github.com/widmogrod/mkunion/x/shared" ) -func init() { - Register(ShapeShape()) - Register(AnyShape()) - Register(RefNameShape()) - Register(PointerLikeShape()) - Register(AliasLikeShape()) - Register(PrimitiveLikeShape()) - Register(ListLikeShape()) - Register(MapLikeShape()) - Register(StructLikeShape()) - Register(UnionLikeShape()) - Register(PrimitiveKindShape()) - Register(BooleanLikeShape()) - Register(StringLikeShape()) - Register(NumberLikeShape()) - Register(NumberKindShape()) - Register(UIntShape()) - Register(UInt8Shape()) - Register(UInt16Shape()) - Register(UInt32Shape()) - Register(UInt64Shape()) - Register(IntShape()) - Register(Int8Shape()) - Register(Int16Shape()) - Register(Int32Shape()) - Register(Int64Shape()) - Register(Float32Shape()) - Register(Float64Shape()) - Register(GuardShape()) - Register(EnumShape()) - Register(RequiredShape()) - Register(AndGuardShape()) -} - -type ShapeVisitor interface { - VisitAny(v *Any) any - VisitRefName(v *RefName) any - VisitPointerLike(v *PointerLike) any - VisitAliasLike(v *AliasLike) any - VisitPrimitiveLike(v *PrimitiveLike) any - VisitListLike(v *ListLike) any - VisitMapLike(v *MapLike) any - VisitStructLike(v *StructLike) any - VisitUnionLike(v *UnionLike) any +type NumberKindVisitor interface { + VisitUInt(v *UInt) any + VisitUInt8(v *UInt8) any + VisitUInt16(v *UInt16) any + VisitUInt32(v *UInt32) any + VisitUInt64(v *UInt64) any + VisitInt(v *Int) any + VisitInt8(v *Int8) any + VisitInt16(v *Int16) any + VisitInt32(v *Int32) any + VisitInt64(v *Int64) any + VisitFloat32(v *Float32) any + VisitFloat64(v *Float64) any } -type Shape interface { - AcceptShape(g ShapeVisitor) any +type NumberKind interface { + AcceptNumberKind(g NumberKindVisitor) any } var ( - _ Shape = (*Any)(nil) - _ Shape = (*RefName)(nil) - _ Shape = (*PointerLike)(nil) - _ Shape = (*AliasLike)(nil) - _ Shape = (*PrimitiveLike)(nil) - _ Shape = (*ListLike)(nil) - _ Shape = (*MapLike)(nil) - _ Shape = (*StructLike)(nil) - _ Shape = (*UnionLike)(nil) + _ NumberKind = (*UInt)(nil) + _ NumberKind = (*UInt8)(nil) + _ NumberKind = (*UInt16)(nil) + _ NumberKind = (*UInt32)(nil) + _ NumberKind = (*UInt64)(nil) + _ NumberKind = (*Int)(nil) + _ NumberKind = (*Int8)(nil) + _ NumberKind = (*Int16)(nil) + _ NumberKind = (*Int32)(nil) + _ NumberKind = (*Int64)(nil) + _ NumberKind = (*Float32)(nil) + _ NumberKind = (*Float64)(nil) ) -func (r *Any) AcceptShape(v ShapeVisitor) any { return v.VisitAny(r) } -func (r *RefName) AcceptShape(v ShapeVisitor) any { return v.VisitRefName(r) } -func (r *PointerLike) AcceptShape(v ShapeVisitor) any { return v.VisitPointerLike(r) } -func (r *AliasLike) AcceptShape(v ShapeVisitor) any { return v.VisitAliasLike(r) } -func (r *PrimitiveLike) AcceptShape(v ShapeVisitor) any { return v.VisitPrimitiveLike(r) } -func (r *ListLike) AcceptShape(v ShapeVisitor) any { return v.VisitListLike(r) } -func (r *MapLike) AcceptShape(v ShapeVisitor) any { return v.VisitMapLike(r) } -func (r *StructLike) AcceptShape(v ShapeVisitor) any { return v.VisitStructLike(r) } -func (r *UnionLike) AcceptShape(v ShapeVisitor) any { return v.VisitUnionLike(r) } +func (r *UInt) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt(r) } +func (r *UInt8) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt8(r) } +func (r *UInt16) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt16(r) } +func (r *UInt32) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt32(r) } +func (r *UInt64) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt64(r) } +func (r *Int) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt(r) } +func (r *Int8) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt8(r) } +func (r *Int16) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt16(r) } +func (r *Int32) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt32(r) } +func (r *Int64) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt64(r) } +func (r *Float32) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitFloat32(r) } +func (r *Float64) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitFloat64(r) } -func MatchShapeR3[T0, T1, T2 any]( - x Shape, - f1 func(x *Any) (T0, T1, T2), - f2 func(x *RefName) (T0, T1, T2), - f3 func(x *PointerLike) (T0, T1, T2), - f4 func(x *AliasLike) (T0, T1, T2), - f5 func(x *PrimitiveLike) (T0, T1, T2), - f6 func(x *ListLike) (T0, T1, T2), - f7 func(x *MapLike) (T0, T1, T2), - f8 func(x *StructLike) (T0, T1, T2), - f9 func(x *UnionLike) (T0, T1, T2), +func MatchNumberKindR3[T0, T1, T2 any]( + x NumberKind, + f1 func(x *UInt) (T0, T1, T2), + f2 func(x *UInt8) (T0, T1, T2), + f3 func(x *UInt16) (T0, T1, T2), + f4 func(x *UInt32) (T0, T1, T2), + f5 func(x *UInt64) (T0, T1, T2), + f6 func(x *Int) (T0, T1, T2), + f7 func(x *Int8) (T0, T1, T2), + f8 func(x *Int16) (T0, T1, T2), + f9 func(x *Int32) (T0, T1, T2), + f10 func(x *Int64) (T0, T1, T2), + f11 func(x *Float32) (T0, T1, T2), + f12 func(x *Float64) (T0, T1, T2), ) (T0, T1, T2) { switch v := x.(type) { - case *Any: + case *UInt: return f1(v) - case *RefName: + case *UInt8: return f2(v) - case *PointerLike: + case *UInt16: return f3(v) - case *AliasLike: + case *UInt32: return f4(v) - case *PrimitiveLike: + case *UInt64: return f5(v) - case *ListLike: + case *Int: return f6(v) - case *MapLike: + case *Int8: return f7(v) - case *StructLike: + case *Int16: return f8(v) - case *UnionLike: + case *Int32: return f9(v) + case *Int64: + return f10(v) + case *Float32: + return f11(v) + case *Float64: + return f12(v) } var result1 T0 var result2 T1 @@ -117,429 +101,172 @@ func MatchShapeR3[T0, T1, T2 any]( return result1, result2, result3 } -func MatchShapeR2[T0, T1 any]( - x Shape, - f1 func(x *Any) (T0, T1), - f2 func(x *RefName) (T0, T1), - f3 func(x *PointerLike) (T0, T1), - f4 func(x *AliasLike) (T0, T1), - f5 func(x *PrimitiveLike) (T0, T1), - f6 func(x *ListLike) (T0, T1), - f7 func(x *MapLike) (T0, T1), - f8 func(x *StructLike) (T0, T1), - f9 func(x *UnionLike) (T0, T1), +func MatchNumberKindR2[T0, T1 any]( + x NumberKind, + f1 func(x *UInt) (T0, T1), + f2 func(x *UInt8) (T0, T1), + f3 func(x *UInt16) (T0, T1), + f4 func(x *UInt32) (T0, T1), + f5 func(x *UInt64) (T0, T1), + f6 func(x *Int) (T0, T1), + f7 func(x *Int8) (T0, T1), + f8 func(x *Int16) (T0, T1), + f9 func(x *Int32) (T0, T1), + f10 func(x *Int64) (T0, T1), + f11 func(x *Float32) (T0, T1), + f12 func(x *Float64) (T0, T1), ) (T0, T1) { switch v := x.(type) { - case *Any: + case *UInt: return f1(v) - case *RefName: + case *UInt8: return f2(v) - case *PointerLike: + case *UInt16: return f3(v) - case *AliasLike: + case *UInt32: return f4(v) - case *PrimitiveLike: + case *UInt64: return f5(v) - case *ListLike: + case *Int: return f6(v) - case *MapLike: + case *Int8: return f7(v) - case *StructLike: + case *Int16: return f8(v) - case *UnionLike: + case *Int32: return f9(v) + case *Int64: + return f10(v) + case *Float32: + return f11(v) + case *Float64: + return f12(v) } var result1 T0 var result2 T1 return result1, result2 } -func MatchShapeR1[T0 any]( - x Shape, - f1 func(x *Any) T0, - f2 func(x *RefName) T0, - f3 func(x *PointerLike) T0, - f4 func(x *AliasLike) T0, - f5 func(x *PrimitiveLike) T0, - f6 func(x *ListLike) T0, - f7 func(x *MapLike) T0, - f8 func(x *StructLike) T0, - f9 func(x *UnionLike) T0, +func MatchNumberKindR1[T0 any]( + x NumberKind, + f1 func(x *UInt) T0, + f2 func(x *UInt8) T0, + f3 func(x *UInt16) T0, + f4 func(x *UInt32) T0, + f5 func(x *UInt64) T0, + f6 func(x *Int) T0, + f7 func(x *Int8) T0, + f8 func(x *Int16) T0, + f9 func(x *Int32) T0, + f10 func(x *Int64) T0, + f11 func(x *Float32) T0, + f12 func(x *Float64) T0, ) T0 { switch v := x.(type) { - case *Any: + case *UInt: return f1(v) - case *RefName: + case *UInt8: return f2(v) - case *PointerLike: + case *UInt16: return f3(v) - case *AliasLike: + case *UInt32: return f4(v) - case *PrimitiveLike: + case *UInt64: return f5(v) - case *ListLike: + case *Int: return f6(v) - case *MapLike: + case *Int8: return f7(v) - case *StructLike: + case *Int16: return f8(v) - case *UnionLike: + case *Int32: return f9(v) + case *Int64: + return f10(v) + case *Float32: + return f11(v) + case *Float64: + return f12(v) } var result1 T0 return result1 } -func MatchShapeR0( - x Shape, - f1 func(x *Any), - f2 func(x *RefName), - f3 func(x *PointerLike), - f4 func(x *AliasLike), - f5 func(x *PrimitiveLike), - f6 func(x *ListLike), - f7 func(x *MapLike), - f8 func(x *StructLike), - f9 func(x *UnionLike), +func MatchNumberKindR0( + x NumberKind, + f1 func(x *UInt), + f2 func(x *UInt8), + f3 func(x *UInt16), + f4 func(x *UInt32), + f5 func(x *UInt64), + f6 func(x *Int), + f7 func(x *Int8), + f8 func(x *Int16), + f9 func(x *Int32), + f10 func(x *Int64), + f11 func(x *Float32), + f12 func(x *Float64), ) { switch v := x.(type) { - case *Any: + case *UInt: f1(v) - case *RefName: + case *UInt8: f2(v) - case *PointerLike: + case *UInt16: f3(v) - case *AliasLike: + case *UInt32: f4(v) - case *PrimitiveLike: + case *UInt64: f5(v) - case *ListLike: + case *Int: f6(v) - case *MapLike: + case *Int8: f7(v) - case *StructLike: + case *Int16: f8(v) - case *UnionLike: + case *Int32: f9(v) - } -} - -func ShapeShape() Shape { - return &UnionLike{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Variant: []Shape{ - AnyShape(), - RefNameShape(), - PointerLikeShape(), - AliasLikeShape(), - PrimitiveLikeShape(), - ListLikeShape(), - MapLikeShape(), - StructLikeShape(), - UnionLikeShape(), - }, - } -} - -func AnyShape() Shape { - return &StructLike{ - Name: "Any", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } -} - -func RefNameShape() Shape { - return &StructLike{ - Name: "RefName", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Name", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgImportName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "Indexed", - Type: &ListLike{ - Element: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - }, - } -} - -func PointerLikeShape() Shape { - return &StructLike{ - Name: "PointerLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Type", - Type: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - } -} - -func AliasLikeShape() Shape { - return &StructLike{ - Name: "AliasLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Name", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgImportName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "IsAlias", - Type: &PrimitiveLike{Kind: &BooleanLike{}}, - }, - { - Name: "Type", - Type: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - { - Name: "Tags", - Type: &MapLike{ - Key: &PrimitiveLike{Kind: &StringLike{}}, - Val: &RefName{ - Name: "Tag", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - }, - } -} - -func PrimitiveLikeShape() Shape { - return &StructLike{ - Name: "PrimitiveLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Kind", - Type: &RefName{ - Name: "PrimitiveKind", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - } -} - -func ListLikeShape() Shape { - return &StructLike{ - Name: "ListLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Element", - Type: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - { - Name: "ArrayLen", - Type: &PointerLike{ - Type: &PrimitiveLike{ - Kind: &NumberLike{}, - }, - }, - }, - }, - } -} - -func MapLikeShape() Shape { - return &StructLike{ - Name: "MapLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Key", - Type: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - { - Name: "Val", - Type: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - } -} - -func StructLikeShape() Shape { - return &StructLike{ - Name: "StructLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Name", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgImportName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "TypeParams", - Type: &ListLike{ - Element: &RefName{ - Name: "TypeParam", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - { - Name: "Fields", - Type: &ListLike{ - Element: &PointerLike{ - Type: &RefName{ - Name: "FieldLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - }, - { - Name: "Tags", - Type: &MapLike{ - Key: &PrimitiveLike{Kind: &StringLike{}}, - Val: &RefName{ - Name: "Tag", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - }, - } -} - -func UnionLikeShape() Shape { - return &StructLike{ - Name: "UnionLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Name", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "PkgImportName", - Type: &PrimitiveLike{Kind: &StringLike{}}, - }, - { - Name: "Variant", - Type: &ListLike{ - Element: &RefName{ - Name: "Shape", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - { - Name: "Tags", - Type: &MapLike{ - Key: &PrimitiveLike{Kind: &StringLike{}}, - Val: &RefName{ - Name: "Tag", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - }, + case *Int64: + f10(v) + case *Float32: + f11(v) + case *Float64: + f12(v) } } func init() { - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Shape", ShapeFromJSON, ShapeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Any", AnyFromJSON, AnyToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.RefName", RefNameFromJSON, RefNameToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.PointerLike", PointerLikeFromJSON, PointerLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.AliasLike", AliasLikeFromJSON, AliasLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.PrimitiveLike", PrimitiveLikeFromJSON, PrimitiveLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.ListLike", ListLikeFromJSON, ListLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.MapLike", MapLikeFromJSON, MapLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.StructLike", StructLikeFromJSON, StructLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UnionLike", UnionLikeFromJSON, UnionLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.NumberKind", NumberKindFromJSON, NumberKindToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt", UIntFromJSON, UIntToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt8", UInt8FromJSON, UInt8ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt16", UInt16FromJSON, UInt16ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt32", UInt32FromJSON, UInt32ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt64", UInt64FromJSON, UInt64ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int", IntFromJSON, IntToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int8", Int8FromJSON, Int8ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int16", Int16FromJSON, Int16ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int32", Int32FromJSON, Int32ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int64", Int64FromJSON, Int64ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Float32", Float32FromJSON, Float32ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Float64", Float64FromJSON, Float64ToJSON) } -type ShapeUnionJSON struct { - Type string `json:"$type,omitempty"` - Any json.RawMessage `json:"shape.Any,omitempty"` - RefName json.RawMessage `json:"shape.RefName,omitempty"` - PointerLike json.RawMessage `json:"shape.PointerLike,omitempty"` - AliasLike json.RawMessage `json:"shape.AliasLike,omitempty"` - PrimitiveLike json.RawMessage `json:"shape.PrimitiveLike,omitempty"` - ListLike json.RawMessage `json:"shape.ListLike,omitempty"` - MapLike json.RawMessage `json:"shape.MapLike,omitempty"` - StructLike json.RawMessage `json:"shape.StructLike,omitempty"` - UnionLike json.RawMessage `json:"shape.UnionLike,omitempty"` +type NumberKindUnionJSON struct { + Type string `json:"$type,omitempty"` + UInt json.RawMessage `json:"shape.UInt,omitempty"` + UInt8 json.RawMessage `json:"shape.UInt8,omitempty"` + UInt16 json.RawMessage `json:"shape.UInt16,omitempty"` + UInt32 json.RawMessage `json:"shape.UInt32,omitempty"` + UInt64 json.RawMessage `json:"shape.UInt64,omitempty"` + Int json.RawMessage `json:"shape.Int,omitempty"` + Int8 json.RawMessage `json:"shape.Int8,omitempty"` + Int16 json.RawMessage `json:"shape.Int16,omitempty"` + Int32 json.RawMessage `json:"shape.Int32,omitempty"` + Int64 json.RawMessage `json:"shape.Int64,omitempty"` + Float32 json.RawMessage `json:"shape.Float32,omitempty"` + Float64 json.RawMessage `json:"shape.Float64,omitempty"` } -func ShapeFromJSON(x []byte) (Shape, error) { +func NumberKindFromJSON(x []byte) (NumberKind, error) { if x == nil || len(x) == 0 { return nil, nil } @@ -547,166 +274,211 @@ func ShapeFromJSON(x []byte) (Shape, error) { return nil, nil } - var data ShapeUnionJSON + var data NumberKindUnionJSON err := json.Unmarshal(x, &data) if err != nil { return nil, err } switch data.Type { - case "shape.Any": - return AnyFromJSON(data.Any) - case "shape.RefName": - return RefNameFromJSON(data.RefName) - case "shape.PointerLike": - return PointerLikeFromJSON(data.PointerLike) - case "shape.AliasLike": - return AliasLikeFromJSON(data.AliasLike) - case "shape.PrimitiveLike": - return PrimitiveLikeFromJSON(data.PrimitiveLike) - case "shape.ListLike": - return ListLikeFromJSON(data.ListLike) - case "shape.MapLike": - return MapLikeFromJSON(data.MapLike) - case "shape.StructLike": - return StructLikeFromJSON(data.StructLike) - case "shape.UnionLike": - return UnionLikeFromJSON(data.UnionLike) + case "shape.UInt": + return UIntFromJSON(data.UInt) + case "shape.UInt8": + return UInt8FromJSON(data.UInt8) + case "shape.UInt16": + return UInt16FromJSON(data.UInt16) + case "shape.UInt32": + return UInt32FromJSON(data.UInt32) + case "shape.UInt64": + return UInt64FromJSON(data.UInt64) + case "shape.Int": + return IntFromJSON(data.Int) + case "shape.Int8": + return Int8FromJSON(data.Int8) + case "shape.Int16": + return Int16FromJSON(data.Int16) + case "shape.Int32": + return Int32FromJSON(data.Int32) + case "shape.Int64": + return Int64FromJSON(data.Int64) + case "shape.Float32": + return Float32FromJSON(data.Float32) + case "shape.Float64": + return Float64FromJSON(data.Float64) } - if data.Any != nil { - return AnyFromJSON(data.Any) - } else if data.RefName != nil { - return RefNameFromJSON(data.RefName) - } else if data.PointerLike != nil { - return PointerLikeFromJSON(data.PointerLike) - } else if data.AliasLike != nil { - return AliasLikeFromJSON(data.AliasLike) - } else if data.PrimitiveLike != nil { - return PrimitiveLikeFromJSON(data.PrimitiveLike) - } else if data.ListLike != nil { - return ListLikeFromJSON(data.ListLike) - } else if data.MapLike != nil { - return MapLikeFromJSON(data.MapLike) - } else if data.StructLike != nil { - return StructLikeFromJSON(data.StructLike) - } else if data.UnionLike != nil { - return UnionLikeFromJSON(data.UnionLike) + if data.UInt != nil { + return UIntFromJSON(data.UInt) + } else if data.UInt8 != nil { + return UInt8FromJSON(data.UInt8) + } else if data.UInt16 != nil { + return UInt16FromJSON(data.UInt16) + } else if data.UInt32 != nil { + return UInt32FromJSON(data.UInt32) + } else if data.UInt64 != nil { + return UInt64FromJSON(data.UInt64) + } else if data.Int != nil { + return IntFromJSON(data.Int) + } else if data.Int8 != nil { + return Int8FromJSON(data.Int8) + } else if data.Int16 != nil { + return Int16FromJSON(data.Int16) + } else if data.Int32 != nil { + return Int32FromJSON(data.Int32) + } else if data.Int64 != nil { + return Int64FromJSON(data.Int64) + } else if data.Float32 != nil { + return Float32FromJSON(data.Float32) + } else if data.Float64 != nil { + return Float64FromJSON(data.Float64) } - return nil, fmt.Errorf("shape.Shape: unknown type %s", data.Type) + return nil, fmt.Errorf("shape.NumberKind: unknown type %s", data.Type) } -func ShapeToJSON(x Shape) ([]byte, error) { +func NumberKindToJSON(x NumberKind) ([]byte, error) { if x == nil { return nil, nil } - return MatchShapeR2( + return MatchNumberKindR2( x, - func(x *Any) ([]byte, error) { - body, err := AnyToJSON(x) + func(x *UInt) ([]byte, error) { + body, err := UIntToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.Any", - Any: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.UInt", + UInt: body, }) }, - func(x *RefName) ([]byte, error) { - body, err := RefNameToJSON(x) + func(x *UInt8) ([]byte, error) { + body, err := UInt8ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.RefName", - RefName: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.UInt8", + UInt8: body, }) }, - func(x *PointerLike) ([]byte, error) { - body, err := PointerLikeToJSON(x) + func(x *UInt16) ([]byte, error) { + body, err := UInt16ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.PointerLike", - PointerLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.UInt16", + UInt16: body, }) }, - func(x *AliasLike) ([]byte, error) { - body, err := AliasLikeToJSON(x) + func(x *UInt32) ([]byte, error) { + body, err := UInt32ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.AliasLike", - AliasLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.UInt32", + UInt32: body, }) }, - func(x *PrimitiveLike) ([]byte, error) { - body, err := PrimitiveLikeToJSON(x) + func(x *UInt64) ([]byte, error) { + body, err := UInt64ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.PrimitiveLike", - PrimitiveLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.UInt64", + UInt64: body, }) }, - func(x *ListLike) ([]byte, error) { - body, err := ListLikeToJSON(x) + func(x *Int) ([]byte, error) { + body, err := IntToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.ListLike", - ListLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Int", + Int: body, }) }, - func(x *MapLike) ([]byte, error) { - body, err := MapLikeToJSON(x) + func(x *Int8) ([]byte, error) { + body, err := Int8ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.MapLike", - MapLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Int8", + Int8: body, }) }, - func(x *StructLike) ([]byte, error) { - body, err := StructLikeToJSON(x) + func(x *Int16) ([]byte, error) { + body, err := Int16ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.StructLike", - StructLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Int16", + Int16: body, }) }, - func(x *UnionLike) ([]byte, error) { - body, err := UnionLikeToJSON(x) + func(x *Int32) ([]byte, error) { + body, err := Int32ToJSON(x) if err != nil { return nil, err } - return json.Marshal(ShapeUnionJSON{ - Type: "shape.UnionLike", - UnionLike: body, + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Int32", + Int32: body, + }) + }, + func(x *Int64) ([]byte, error) { + body, err := Int64ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Int64", + Int64: body, + }) + }, + func(x *Float32) ([]byte, error) { + body, err := Float32ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Float32", + Float32: body, + }) + }, + func(x *Float64) ([]byte, error) { + body, err := Float64ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NumberKindUnionJSON{ + Type: "shape.Float64", + Float64: body, }) }, ) } -func AnyFromJSON(x []byte) (*Any, error) { - result := new(Any) +func UIntFromJSON(x []byte) (*UInt, error) { + result := new(UInt) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -715,50 +487,50 @@ func AnyFromJSON(x []byte) (*Any, error) { return result, nil } -func AnyToJSON(x *Any) ([]byte, error) { +func UIntToJSON(x *UInt) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Any)(nil) - _ json.Marshaler = (*Any)(nil) + _ json.Unmarshaler = (*UInt)(nil) + _ json.Marshaler = (*UInt)(nil) ) -func (r *Any) MarshalJSON() ([]byte, error) { +func (r *UInt) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONAny(*r) + return r._marshalJSONUInt(*r) } -func (r *Any) _marshalJSONAny(x Any) ([]byte, error) { +func (r *UInt) _marshalJSONUInt(x UInt) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Any._marshalJSONAny: struct; %w", err) + return nil, fmt.Errorf("shape: UInt._marshalJSONUInt: struct; %w", err) } return result, nil } -func (r *Any) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONAny(data) +func (r *UInt) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONUInt(data) if err != nil { - return fmt.Errorf("shape: Any.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: UInt.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Any) _unmarshalJSONAny(data []byte) (Any, error) { - result := Any{} +func (r *UInt) _unmarshalJSONUInt(data []byte) (UInt, error) { + result := UInt{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Any._unmarshalJSONAny: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: UInt._unmarshalJSONUInt: native struct unwrap; %w", err) } return result, nil } -func RefNameFromJSON(x []byte) (*RefName, error) { - result := new(RefName) +func UInt8FromJSON(x []byte) (*UInt8, error) { + result := new(UInt8) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -767,158 +539,50 @@ func RefNameFromJSON(x []byte) (*RefName, error) { return result, nil } -func RefNameToJSON(x *RefName) ([]byte, error) { +func UInt8ToJSON(x *UInt8) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*RefName)(nil) - _ json.Marshaler = (*RefName)(nil) + _ json.Unmarshaler = (*UInt8)(nil) + _ json.Marshaler = (*UInt8)(nil) ) -func (r *RefName) MarshalJSON() ([]byte, error) { +func (r *UInt8) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONRefName(*r) + return r._marshalJSONUInt8(*r) } -func (r *RefName) _marshalJSONRefName(x RefName) ([]byte, error) { +func (r *UInt8) _marshalJSONUInt8(x UInt8) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldName []byte - fieldName, err = r._marshalJSONstring(x.Name) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name Name; %w", err) - } - partial["Name"] = fieldName - var fieldPkgName []byte - fieldPkgName, err = r._marshalJSONstring(x.PkgName) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name PkgName; %w", err) - } - partial["PkgName"] = fieldPkgName - var fieldPkgImportName []byte - fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name PkgImportName; %w", err) - } - partial["PkgImportName"] = fieldPkgImportName - var fieldIndexed []byte - fieldIndexed, err = r._marshalJSONSliceShape(x.Indexed) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name Indexed; %w", err) - } - partial["Indexed"] = fieldIndexed - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: struct; %w", err) - } - return result, nil -} -func (r *RefName) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONstring:; %w", err) - } - return result, nil -} -func (r *RefName) _marshalJSONSliceShape(x []Shape) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONShape(v) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONSliceShape: at index %d; %w", i, err) - } - partial[i] = item - } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONSliceShape:; %w", err) - } - return result, nil -} -func (r *RefName) _marshalJSONShape(x Shape) ([]byte, error) { - result, err := shared.JSONMarshal[Shape](x) - if err != nil { - return nil, fmt.Errorf("shape: RefName._marshalJSONShape:; %w", err) + return nil, fmt.Errorf("shape: UInt8._marshalJSONUInt8: struct; %w", err) } return result, nil } -func (r *RefName) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONRefName(data) +func (r *UInt8) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONUInt8(data) if err != nil { - return fmt.Errorf("shape: RefName.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: UInt8.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *RefName) _unmarshalJSONRefName(data []byte) (RefName, error) { - result := RefName{} +func (r *UInt8) _unmarshalJSONUInt8(data []byte) (UInt8, error) { + result := UInt8{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: native struct unwrap; %w", err) - } - if fieldName, ok := partial["Name"]; ok { - result.Name, err = r._unmarshalJSONstring(fieldName) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field Name; %w", err) - } - } - if fieldPkgName, ok := partial["PkgName"]; ok { - result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field PkgName; %w", err) - } - } - if fieldPkgImportName, ok := partial["PkgImportName"]; ok { - result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field PkgImportName; %w", err) - } - } - if fieldIndexed, ok := partial["Indexed"]; ok { - result.Indexed, err = r._unmarshalJSONSliceShape(fieldIndexed) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field Indexed; %w", err) - } - } - return result, nil -} -func (r *RefName) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONstring: native primitive unwrap; %w", err) - } - return result, nil -} -func (r *RefName) _unmarshalJSONSliceShape(data []byte) ([]Shape, error) { - result := make([]Shape, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONSliceShape: native list unwrap; %w", err) - } - for i, v := range partial { - item, err := r._unmarshalJSONShape(v) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONSliceShape: at index %d; %w", i, err) - } - result = append(result, item) - } - return result, nil -} -func (r *RefName) _unmarshalJSONShape(data []byte) (Shape, error) { - result, err := shared.JSONUnmarshal[Shape](data) - if err != nil { - return result, fmt.Errorf("shape: RefName._unmarshalJSONShape: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: UInt8._unmarshalJSONUInt8: native struct unwrap; %w", err) } return result, nil } -func PointerLikeFromJSON(x []byte) (*PointerLike, error) { - result := new(PointerLike) +func UInt16FromJSON(x []byte) (*UInt16, error) { + result := new(UInt16) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -927,76 +591,50 @@ func PointerLikeFromJSON(x []byte) (*PointerLike, error) { return result, nil } -func PointerLikeToJSON(x *PointerLike) ([]byte, error) { +func UInt16ToJSON(x *UInt16) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*PointerLike)(nil) - _ json.Marshaler = (*PointerLike)(nil) + _ json.Unmarshaler = (*UInt16)(nil) + _ json.Marshaler = (*UInt16)(nil) ) -func (r *PointerLike) MarshalJSON() ([]byte, error) { +func (r *UInt16) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONPointerLike(*r) + return r._marshalJSONUInt16(*r) } -func (r *PointerLike) _marshalJSONPointerLike(x PointerLike) ([]byte, error) { +func (r *UInt16) _marshalJSONUInt16(x UInt16) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldType []byte - fieldType, err = r._marshalJSONShape(x.Type) - if err != nil { - return nil, fmt.Errorf("shape: PointerLike._marshalJSONPointerLike: field name Type; %w", err) - } - partial["Type"] = fieldType result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: PointerLike._marshalJSONPointerLike: struct; %w", err) + return nil, fmt.Errorf("shape: UInt16._marshalJSONUInt16: struct; %w", err) } return result, nil } -func (r *PointerLike) _marshalJSONShape(x Shape) ([]byte, error) { - result, err := shared.JSONMarshal[Shape](x) +func (r *UInt16) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONUInt16(data) if err != nil { - return nil, fmt.Errorf("shape: PointerLike._marshalJSONShape:; %w", err) - } - return result, nil -} -func (r *PointerLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONPointerLike(data) - if err != nil { - return fmt.Errorf("shape: PointerLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: UInt16.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *PointerLike) _unmarshalJSONPointerLike(data []byte) (PointerLike, error) { - result := PointerLike{} +func (r *UInt16) _unmarshalJSONUInt16(data []byte) (UInt16, error) { + result := UInt16{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: PointerLike._unmarshalJSONPointerLike: native struct unwrap; %w", err) - } - if fieldType, ok := partial["Type"]; ok { - result.Type, err = r._unmarshalJSONShape(fieldType) - if err != nil { - return result, fmt.Errorf("shape: PointerLike._unmarshalJSONPointerLike: field Type; %w", err) - } - } - return result, nil -} -func (r *PointerLike) _unmarshalJSONShape(data []byte) (Shape, error) { - result, err := shared.JSONUnmarshal[Shape](data) - if err != nil { - return result, fmt.Errorf("shape: PointerLike._unmarshalJSONShape: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: UInt16._unmarshalJSONUInt16: native struct unwrap; %w", err) } return result, nil } -func AliasLikeFromJSON(x []byte) (*AliasLike, error) { - result := new(AliasLike) +func UInt32FromJSON(x []byte) (*UInt32, error) { + result := new(UInt32) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1005,213 +643,102 @@ func AliasLikeFromJSON(x []byte) (*AliasLike, error) { return result, nil } -func AliasLikeToJSON(x *AliasLike) ([]byte, error) { +func UInt32ToJSON(x *UInt32) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*AliasLike)(nil) - _ json.Marshaler = (*AliasLike)(nil) + _ json.Unmarshaler = (*UInt32)(nil) + _ json.Marshaler = (*UInt32)(nil) ) -func (r *AliasLike) MarshalJSON() ([]byte, error) { +func (r *UInt32) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONAliasLike(*r) + return r._marshalJSONUInt32(*r) } -func (r *AliasLike) _marshalJSONAliasLike(x AliasLike) ([]byte, error) { +func (r *UInt32) _marshalJSONUInt32(x UInt32) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldName []byte - fieldName, err = r._marshalJSONstring(x.Name) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name Name; %w", err) - } - partial["Name"] = fieldName - var fieldPkgName []byte - fieldPkgName, err = r._marshalJSONstring(x.PkgName) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name PkgName; %w", err) - } - partial["PkgName"] = fieldPkgName - var fieldPkgImportName []byte - fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name PkgImportName; %w", err) - } - partial["PkgImportName"] = fieldPkgImportName - var fieldIsAlias []byte - fieldIsAlias, err = r._marshalJSONbool(x.IsAlias) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name IsAlias; %w", err) - } - partial["IsAlias"] = fieldIsAlias - var fieldType []byte - fieldType, err = r._marshalJSONShape(x.Type) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name Type; %w", err) - } - partial["Type"] = fieldType - var fieldTags []byte - fieldTags, err = r._marshalJSONmapLb_string_bLTag(x.Tags) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name Tags; %w", err) - } - partial["Tags"] = fieldTags - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: struct; %w", err) - } - return result, nil -} -func (r *AliasLike) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONstring:; %w", err) - } - return result, nil -} -func (r *AliasLike) _marshalJSONbool(x bool) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONbool:; %w", err) - } - return result, nil -} -func (r *AliasLike) _marshalJSONShape(x Shape) ([]byte, error) { - result, err := shared.JSONMarshal[Shape](x) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONShape:; %w", err) - } - return result, nil -} -func (r *AliasLike) _marshalJSONmapLb_string_bLTag(x map[string]Tag) ([]byte, error) { - partial := make(map[string]json.RawMessage) - for k, v := range x { - key := string(k) - value, err := r._marshalJSONTag(v) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONmapLb_string_bLTag: value; %w", err) - } - partial[string(key)] = value - } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONmapLb_string_bLTag:; %w", err) - } - return result, nil -} -func (r *AliasLike) _marshalJSONTag(x Tag) ([]byte, error) { - result, err := shared.JSONMarshal[Tag](x) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._marshalJSONTag:; %w", err) + return nil, fmt.Errorf("shape: UInt32._marshalJSONUInt32: struct; %w", err) } return result, nil } -func (r *AliasLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONAliasLike(data) +func (r *UInt32) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONUInt32(data) if err != nil { - return fmt.Errorf("shape: AliasLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: UInt32.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *AliasLike) _unmarshalJSONAliasLike(data []byte) (AliasLike, error) { - result := AliasLike{} +func (r *UInt32) _unmarshalJSONUInt32(data []byte) (UInt32, error) { + result := UInt32{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: native struct unwrap; %w", err) - } - if fieldName, ok := partial["Name"]; ok { - result.Name, err = r._unmarshalJSONstring(fieldName) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field Name; %w", err) - } - } - if fieldPkgName, ok := partial["PkgName"]; ok { - result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field PkgName; %w", err) - } - } - if fieldPkgImportName, ok := partial["PkgImportName"]; ok { - result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field PkgImportName; %w", err) - } - } - if fieldIsAlias, ok := partial["IsAlias"]; ok { - result.IsAlias, err = r._unmarshalJSONbool(fieldIsAlias) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field IsAlias; %w", err) - } - } - if fieldType, ok := partial["Type"]; ok { - result.Type, err = r._unmarshalJSONShape(fieldType) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field Type; %w", err) - } - } - if fieldTags, ok := partial["Tags"]; ok { - result.Tags, err = r._unmarshalJSONmapLb_string_bLTag(fieldTags) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field Tags; %w", err) - } + return result, fmt.Errorf("shape: UInt32._unmarshalJSONUInt32: native struct unwrap; %w", err) } return result, nil } -func (r *AliasLike) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) + +func UInt64FromJSON(x []byte) (*UInt64, error) { + result := new(UInt64) + err := result.UnmarshalJSON(x) if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONstring: native primitive unwrap; %w", err) + return nil, err } + return result, nil } -func (r *AliasLike) _unmarshalJSONbool(data []byte) (bool, error) { - var result bool - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONbool: native primitive unwrap; %w", err) + +func UInt64ToJSON(x *UInt64) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*UInt64)(nil) + _ json.Marshaler = (*UInt64)(nil) +) + +func (r *UInt64) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } - return result, nil + return r._marshalJSONUInt64(*r) } -func (r *AliasLike) _unmarshalJSONShape(data []byte) (Shape, error) { - result, err := shared.JSONUnmarshal[Shape](data) +func (r *UInt64) _marshalJSONUInt64(x UInt64) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + result, err := json.Marshal(partial) if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONShape: native ref unwrap; %w", err) + return nil, fmt.Errorf("shape: UInt64._marshalJSONUInt64: struct; %w", err) } return result, nil } -func (r *AliasLike) _unmarshalJSONmapLb_string_bLTag(data []byte) (map[string]Tag, error) { - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) +func (r *UInt64) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONUInt64(data) if err != nil { - return nil, fmt.Errorf("shape: AliasLike._unmarshalJSONmapLb_string_bLTag: native map unwrap; %w", err) - } - result := make(map[string]Tag) - for k, v := range partial { - key := string(k) - value, err := r._unmarshalJSONTag(v) - if err != nil { - return nil, fmt.Errorf("shape: AliasLike._unmarshalJSONmapLb_string_bLTag: value; %w", err) - } - result[key] = value + return fmt.Errorf("shape: UInt64.UnmarshalJSON: %w", err) } - return result, nil + *r = result + return nil } -func (r *AliasLike) _unmarshalJSONTag(data []byte) (Tag, error) { - result, err := shared.JSONUnmarshal[Tag](data) +func (r *UInt64) _unmarshalJSONUInt64(data []byte) (UInt64, error) { + result := UInt64{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: AliasLike._unmarshalJSONTag: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: UInt64._unmarshalJSONUInt64: native struct unwrap; %w", err) } return result, nil } -func PrimitiveLikeFromJSON(x []byte) (*PrimitiveLike, error) { - result := new(PrimitiveLike) +func IntFromJSON(x []byte) (*Int, error) { + result := new(Int) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1220,76 +747,50 @@ func PrimitiveLikeFromJSON(x []byte) (*PrimitiveLike, error) { return result, nil } -func PrimitiveLikeToJSON(x *PrimitiveLike) ([]byte, error) { +func IntToJSON(x *Int) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*PrimitiveLike)(nil) - _ json.Marshaler = (*PrimitiveLike)(nil) + _ json.Unmarshaler = (*Int)(nil) + _ json.Marshaler = (*Int)(nil) ) -func (r *PrimitiveLike) MarshalJSON() ([]byte, error) { +func (r *Int) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONPrimitiveLike(*r) + return r._marshalJSONInt(*r) } -func (r *PrimitiveLike) _marshalJSONPrimitiveLike(x PrimitiveLike) ([]byte, error) { +func (r *Int) _marshalJSONInt(x Int) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldKind []byte - fieldKind, err = r._marshalJSONPrimitiveKind(x.Kind) + result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: PrimitiveLike._marshalJSONPrimitiveLike: field name Kind; %w", err) - } - partial["Kind"] = fieldKind - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("shape: PrimitiveLike._marshalJSONPrimitiveLike: struct; %w", err) - } - return result, nil -} -func (r *PrimitiveLike) _marshalJSONPrimitiveKind(x PrimitiveKind) ([]byte, error) { - result, err := shared.JSONMarshal[PrimitiveKind](x) - if err != nil { - return nil, fmt.Errorf("shape: PrimitiveLike._marshalJSONPrimitiveKind:; %w", err) + return nil, fmt.Errorf("shape: Int._marshalJSONInt: struct; %w", err) } return result, nil } -func (r *PrimitiveLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONPrimitiveLike(data) +func (r *Int) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONInt(data) if err != nil { - return fmt.Errorf("shape: PrimitiveLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: Int.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *PrimitiveLike) _unmarshalJSONPrimitiveLike(data []byte) (PrimitiveLike, error) { - result := PrimitiveLike{} +func (r *Int) _unmarshalJSONInt(data []byte) (Int, error) { + result := Int{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: PrimitiveLike._unmarshalJSONPrimitiveLike: native struct unwrap; %w", err) - } - if fieldKind, ok := partial["Kind"]; ok { - result.Kind, err = r._unmarshalJSONPrimitiveKind(fieldKind) - if err != nil { - return result, fmt.Errorf("shape: PrimitiveLike._unmarshalJSONPrimitiveLike: field Kind; %w", err) - } - } - return result, nil -} -func (r *PrimitiveLike) _unmarshalJSONPrimitiveKind(data []byte) (PrimitiveKind, error) { - result, err := shared.JSONUnmarshal[PrimitiveKind](data) - if err != nil { - return result, fmt.Errorf("shape: PrimitiveLike._unmarshalJSONPrimitiveKind: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: Int._unmarshalJSONInt: native struct unwrap; %w", err) } return result, nil } -func ListLikeFromJSON(x []byte) (*ListLike, error) { - result := new(ListLike) +func Int8FromJSON(x []byte) (*Int8, error) { + result := new(Int8) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1298,124 +799,102 @@ func ListLikeFromJSON(x []byte) (*ListLike, error) { return result, nil } -func ListLikeToJSON(x *ListLike) ([]byte, error) { +func Int8ToJSON(x *Int8) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*ListLike)(nil) - _ json.Marshaler = (*ListLike)(nil) + _ json.Unmarshaler = (*Int8)(nil) + _ json.Marshaler = (*Int8)(nil) ) -func (r *ListLike) MarshalJSON() ([]byte, error) { +func (r *Int8) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONListLike(*r) + return r._marshalJSONInt8(*r) } -func (r *ListLike) _marshalJSONListLike(x ListLike) ([]byte, error) { +func (r *Int8) _marshalJSONInt8(x Int8) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldElement []byte - fieldElement, err = r._marshalJSONShape(x.Element) - if err != nil { - return nil, fmt.Errorf("shape: ListLike._marshalJSONListLike: field name Element; %w", err) - } - partial["Element"] = fieldElement - var fieldArrayLen []byte - fieldArrayLen, err = r._marshalJSONPtrint(x.ArrayLen) - if err != nil { - return nil, fmt.Errorf("shape: ListLike._marshalJSONListLike: field name ArrayLen; %w", err) - } - if fieldArrayLen != nil { - partial["ArrayLen"] = fieldArrayLen - } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: ListLike._marshalJSONListLike: struct; %w", err) - } - return result, nil -} -func (r *ListLike) _marshalJSONShape(x Shape) ([]byte, error) { - result, err := shared.JSONMarshal[Shape](x) - if err != nil { - return nil, fmt.Errorf("shape: ListLike._marshalJSONShape:; %w", err) - } - return result, nil -} -func (r *ListLike) _marshalJSONPtrint(x *int) ([]byte, error) { - if x == nil { - return nil, nil - } - return r._marshalJSONint(*x) -} -func (r *ListLike) _marshalJSONint(x int) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("shape: ListLike._marshalJSONint:; %w", err) + return nil, fmt.Errorf("shape: Int8._marshalJSONInt8: struct; %w", err) } return result, nil } -func (r *ListLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONListLike(data) +func (r *Int8) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONInt8(data) if err != nil { - return fmt.Errorf("shape: ListLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: Int8.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *ListLike) _unmarshalJSONListLike(data []byte) (ListLike, error) { - result := ListLike{} +func (r *Int8) _unmarshalJSONInt8(data []byte) (Int8, error) { + result := Int8{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: ListLike._unmarshalJSONListLike: native struct unwrap; %w", err) - } - if fieldElement, ok := partial["Element"]; ok { - result.Element, err = r._unmarshalJSONShape(fieldElement) - if err != nil { - return result, fmt.Errorf("shape: ListLike._unmarshalJSONListLike: field Element; %w", err) - } - } - if fieldArrayLen, ok := partial["ArrayLen"]; ok { - result.ArrayLen, err = r._unmarshalJSONPtrint(fieldArrayLen) - if err != nil { - return result, fmt.Errorf("shape: ListLike._unmarshalJSONListLike: field ArrayLen; %w", err) - } + return result, fmt.Errorf("shape: Int8._unmarshalJSONInt8: native struct unwrap; %w", err) } return result, nil } -func (r *ListLike) _unmarshalJSONShape(data []byte) (Shape, error) { - result, err := shared.JSONUnmarshal[Shape](data) + +func Int16FromJSON(x []byte) (*Int16, error) { + result := new(Int16) + err := result.UnmarshalJSON(x) if err != nil { - return result, fmt.Errorf("shape: ListLike._unmarshalJSONShape: native ref unwrap; %w", err) + return nil, err } + return result, nil } -func (r *ListLike) _unmarshalJSONPtrint(data []byte) (*int, error) { - if len(data) == 0 { + +func Int16ToJSON(x *Int16) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Int16)(nil) + _ json.Marshaler = (*Int16)(nil) +) + +func (r *Int16) MarshalJSON() ([]byte, error) { + if r == nil { return nil, nil } - if string(data[:4]) == "null" { - return nil, nil + return r._marshalJSONInt16(*r) +} +func (r *Int16) _marshalJSONInt16(x Int16) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: Int16._marshalJSONInt16: struct; %w", err) } - result, err := r._unmarshalJSONint(data) + return result, nil +} +func (r *Int16) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONInt16(data) if err != nil { - return nil, fmt.Errorf("shape: ListLike._unmarshalJSONPtrint: pointer; %w", err) + return fmt.Errorf("shape: Int16.UnmarshalJSON: %w", err) } - return &result, nil + *r = result + return nil } -func (r *ListLike) _unmarshalJSONint(data []byte) (int, error) { - var result int - err := json.Unmarshal(data, &result) +func (r *Int16) _unmarshalJSONInt16(data []byte) (Int16, error) { + result := Int16{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: ListLike._unmarshalJSONint: native primitive unwrap; %w", err) + return result, fmt.Errorf("shape: Int16._unmarshalJSONInt16: native struct unwrap; %w", err) } return result, nil } -func MapLikeFromJSON(x []byte) (*MapLike, error) { - result := new(MapLike) +func Int32FromJSON(x []byte) (*Int32, error) { + result := new(Int32) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1424,88 +903,50 @@ func MapLikeFromJSON(x []byte) (*MapLike, error) { return result, nil } -func MapLikeToJSON(x *MapLike) ([]byte, error) { +func Int32ToJSON(x *Int32) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*MapLike)(nil) - _ json.Marshaler = (*MapLike)(nil) + _ json.Unmarshaler = (*Int32)(nil) + _ json.Marshaler = (*Int32)(nil) ) -func (r *MapLike) MarshalJSON() ([]byte, error) { +func (r *Int32) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONMapLike(*r) + return r._marshalJSONInt32(*r) } -func (r *MapLike) _marshalJSONMapLike(x MapLike) ([]byte, error) { +func (r *Int32) _marshalJSONInt32(x Int32) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldKey []byte - fieldKey, err = r._marshalJSONShape(x.Key) - if err != nil { - return nil, fmt.Errorf("shape: MapLike._marshalJSONMapLike: field name Key; %w", err) - } - partial["Key"] = fieldKey - var fieldVal []byte - fieldVal, err = r._marshalJSONShape(x.Val) - if err != nil { - return nil, fmt.Errorf("shape: MapLike._marshalJSONMapLike: field name Val; %w", err) - } - partial["Val"] = fieldVal result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: MapLike._marshalJSONMapLike: struct; %w", err) - } - return result, nil -} -func (r *MapLike) _marshalJSONShape(x Shape) ([]byte, error) { - result, err := shared.JSONMarshal[Shape](x) - if err != nil { - return nil, fmt.Errorf("shape: MapLike._marshalJSONShape:; %w", err) + return nil, fmt.Errorf("shape: Int32._marshalJSONInt32: struct; %w", err) } return result, nil } -func (r *MapLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONMapLike(data) +func (r *Int32) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONInt32(data) if err != nil { - return fmt.Errorf("shape: MapLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: Int32.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *MapLike) _unmarshalJSONMapLike(data []byte) (MapLike, error) { - result := MapLike{} +func (r *Int32) _unmarshalJSONInt32(data []byte) (Int32, error) { + result := Int32{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: MapLike._unmarshalJSONMapLike: native struct unwrap; %w", err) - } - if fieldKey, ok := partial["Key"]; ok { - result.Key, err = r._unmarshalJSONShape(fieldKey) - if err != nil { - return result, fmt.Errorf("shape: MapLike._unmarshalJSONMapLike: field Key; %w", err) - } - } - if fieldVal, ok := partial["Val"]; ok { - result.Val, err = r._unmarshalJSONShape(fieldVal) - if err != nil { - return result, fmt.Errorf("shape: MapLike._unmarshalJSONMapLike: field Val; %w", err) - } - } - return result, nil -} -func (r *MapLike) _unmarshalJSONShape(data []byte) (Shape, error) { - result, err := shared.JSONUnmarshal[Shape](data) - if err != nil { - return result, fmt.Errorf("shape: MapLike._unmarshalJSONShape: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: Int32._unmarshalJSONInt32: native struct unwrap; %w", err) } return result, nil } -func StructLikeFromJSON(x []byte) (*StructLike, error) { - result := new(StructLike) +func Int64FromJSON(x []byte) (*Int64, error) { + result := new(Int64) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1514,293 +955,336 @@ func StructLikeFromJSON(x []byte) (*StructLike, error) { return result, nil } -func StructLikeToJSON(x *StructLike) ([]byte, error) { +func Int64ToJSON(x *Int64) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*StructLike)(nil) - _ json.Marshaler = (*StructLike)(nil) + _ json.Unmarshaler = (*Int64)(nil) + _ json.Marshaler = (*Int64)(nil) ) -func (r *StructLike) MarshalJSON() ([]byte, error) { +func (r *Int64) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONStructLike(*r) + return r._marshalJSONInt64(*r) } -func (r *StructLike) _marshalJSONStructLike(x StructLike) ([]byte, error) { +func (r *Int64) _marshalJSONInt64(x Int64) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldName []byte - fieldName, err = r._marshalJSONstring(x.Name) + result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name Name; %w", err) - } - partial["Name"] = fieldName - var fieldPkgName []byte - fieldPkgName, err = r._marshalJSONstring(x.PkgName) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name PkgName; %w", err) - } - partial["PkgName"] = fieldPkgName - var fieldPkgImportName []byte - fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name PkgImportName; %w", err) - } - partial["PkgImportName"] = fieldPkgImportName - var fieldTypeParams []byte - fieldTypeParams, err = r._marshalJSONSliceTypeParam(x.TypeParams) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name TypeParams; %w", err) - } - partial["TypeParams"] = fieldTypeParams - var fieldFields []byte - fieldFields, err = r._marshalJSONSlicePtrFieldLike(x.Fields) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name Fields; %w", err) - } - partial["Fields"] = fieldFields - var fieldTags []byte - fieldTags, err = r._marshalJSONmapLb_string_bLTag(x.Tags) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name Tags; %w", err) - } - partial["Tags"] = fieldTags - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: struct; %w", err) + return nil, fmt.Errorf("shape: Int64._marshalJSONInt64: struct; %w", err) } return result, nil } -func (r *StructLike) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) +func (r *Int64) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONInt64(data) if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONstring:; %w", err) + return fmt.Errorf("shape: Int64.UnmarshalJSON: %w", err) } - return result, nil + *r = result + return nil } -func (r *StructLike) _marshalJSONSliceTypeParam(x []TypeParam) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONTypeParam(v) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONSliceTypeParam: at index %d; %w", i, err) - } - partial[i] = item - } - result, err := json.Marshal(partial) +func (r *Int64) _unmarshalJSONInt64(data []byte) (Int64, error) { + result := Int64{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONSliceTypeParam:; %w", err) + return result, fmt.Errorf("shape: Int64._unmarshalJSONInt64: native struct unwrap; %w", err) } return result, nil } -func (r *StructLike) _marshalJSONTypeParam(x TypeParam) ([]byte, error) { - result, err := shared.JSONMarshal[TypeParam](x) + +func Float32FromJSON(x []byte) (*Float32, error) { + result := new(Float32) + err := result.UnmarshalJSON(x) if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONTypeParam:; %w", err) + return nil, err } + return result, nil } -func (r *StructLike) _marshalJSONSlicePtrFieldLike(x []*FieldLike) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONPtrFieldLike(v) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONSlicePtrFieldLike: at index %d; %w", i, err) - } - partial[i] = item - } - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONSlicePtrFieldLike:; %w", err) - } - return result, nil + +func Float32ToJSON(x *Float32) ([]byte, error) { + return x.MarshalJSON() } -func (r *StructLike) _marshalJSONPtrFieldLike(x *FieldLike) ([]byte, error) { - if x == nil { + +var ( + _ json.Unmarshaler = (*Float32)(nil) + _ json.Marshaler = (*Float32)(nil) +) + +func (r *Float32) MarshalJSON() ([]byte, error) { + if r == nil { return nil, nil } - return r._marshalJSONFieldLike(*x) -} -func (r *StructLike) _marshalJSONFieldLike(x FieldLike) ([]byte, error) { - result, err := shared.JSONMarshal[FieldLike](x) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONFieldLike:; %w", err) - } - return result, nil + return r._marshalJSONFloat32(*r) } -func (r *StructLike) _marshalJSONmapLb_string_bLTag(x map[string]Tag) ([]byte, error) { +func (r *Float32) _marshalJSONFloat32(x Float32) ([]byte, error) { partial := make(map[string]json.RawMessage) - for k, v := range x { - key := string(k) - value, err := r._marshalJSONTag(v) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONmapLb_string_bLTag: value; %w", err) - } - partial[string(key)] = value - } + var err error result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONmapLb_string_bLTag:; %w", err) - } - return result, nil -} -func (r *StructLike) _marshalJSONTag(x Tag) ([]byte, error) { - result, err := shared.JSONMarshal[Tag](x) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._marshalJSONTag:; %w", err) + return nil, fmt.Errorf("shape: Float32._marshalJSONFloat32: struct; %w", err) } return result, nil } -func (r *StructLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONStructLike(data) +func (r *Float32) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONFloat32(data) if err != nil { - return fmt.Errorf("shape: StructLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: Float32.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *StructLike) _unmarshalJSONStructLike(data []byte) (StructLike, error) { - result := StructLike{} +func (r *Float32) _unmarshalJSONFloat32(data []byte) (Float32, error) { + result := Float32{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: native struct unwrap; %w", err) - } - if fieldName, ok := partial["Name"]; ok { - result.Name, err = r._unmarshalJSONstring(fieldName) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field Name; %w", err) - } - } - if fieldPkgName, ok := partial["PkgName"]; ok { - result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field PkgName; %w", err) - } - } - if fieldPkgImportName, ok := partial["PkgImportName"]; ok { - result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field PkgImportName; %w", err) - } - } - if fieldTypeParams, ok := partial["TypeParams"]; ok { - result.TypeParams, err = r._unmarshalJSONSliceTypeParam(fieldTypeParams) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field TypeParams; %w", err) - } - } - if fieldFields, ok := partial["Fields"]; ok { - result.Fields, err = r._unmarshalJSONSlicePtrFieldLike(fieldFields) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field Fields; %w", err) - } - } - if fieldTags, ok := partial["Tags"]; ok { - result.Tags, err = r._unmarshalJSONmapLb_string_bLTag(fieldTags) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field Tags; %w", err) - } + return result, fmt.Errorf("shape: Float32._unmarshalJSONFloat32: native struct unwrap; %w", err) } return result, nil } -func (r *StructLike) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) + +func Float64FromJSON(x []byte) (*Float64, error) { + result := new(Float64) + err := result.UnmarshalJSON(x) if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONstring: native primitive unwrap; %w", err) + return nil, err } + return result, nil } -func (r *StructLike) _unmarshalJSONSliceTypeParam(data []byte) ([]TypeParam, error) { - result := make([]TypeParam, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONSliceTypeParam: native list unwrap; %w", err) - } - for i, v := range partial { - item, err := r._unmarshalJSONTypeParam(v) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONSliceTypeParam: at index %d; %w", i, err) - } - result = append(result, item) - } - return result, nil + +func Float64ToJSON(x *Float64) ([]byte, error) { + return x.MarshalJSON() } -func (r *StructLike) _unmarshalJSONTypeParam(data []byte) (TypeParam, error) { - result, err := shared.JSONUnmarshal[TypeParam](data) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONTypeParam: native ref unwrap; %w", err) + +var ( + _ json.Unmarshaler = (*Float64)(nil) + _ json.Marshaler = (*Float64)(nil) +) + +func (r *Float64) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } - return result, nil + return r._marshalJSONFloat64(*r) } -func (r *StructLike) _unmarshalJSONSlicePtrFieldLike(data []byte) ([]*FieldLike, error) { - result := make([]*FieldLike, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) +func (r *Float64) _marshalJSONFloat64(x Float64) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + result, err := json.Marshal(partial) if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONSlicePtrFieldLike: native list unwrap; %w", err) - } - for i, v := range partial { - item, err := r._unmarshalJSONPtrFieldLike(v) - if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONSlicePtrFieldLike: at index %d; %w", i, err) - } - result = append(result, item) + return nil, fmt.Errorf("shape: Float64._marshalJSONFloat64: struct; %w", err) } return result, nil } -func (r *StructLike) _unmarshalJSONPtrFieldLike(data []byte) (*FieldLike, error) { - if len(data) == 0 { - return nil, nil - } - if string(data[:4]) == "null" { - return nil, nil - } - result, err := r._unmarshalJSONFieldLike(data) +func (r *Float64) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONFloat64(data) if err != nil { - return nil, fmt.Errorf("shape: StructLike._unmarshalJSONPtrFieldLike: pointer; %w", err) + return fmt.Errorf("shape: Float64.UnmarshalJSON: %w", err) } - return &result, nil + *r = result + return nil } -func (r *StructLike) _unmarshalJSONFieldLike(data []byte) (FieldLike, error) { - result, err := shared.JSONUnmarshal[FieldLike](data) +func (r *Float64) _unmarshalJSONFloat64(data []byte) (Float64, error) { + result := Float64{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONFieldLike: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: Float64._unmarshalJSONFloat64: native struct unwrap; %w", err) } return result, nil } -func (r *StructLike) _unmarshalJSONmapLb_string_bLTag(data []byte) (map[string]Tag, error) { - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._unmarshalJSONmapLb_string_bLTag: native map unwrap; %w", err) + +type GuardVisitor interface { + VisitEnum(v *Enum) any + VisitRequired(v *Required) any + VisitAndGuard(v *AndGuard) any +} + +type Guard interface { + AcceptGuard(g GuardVisitor) any +} + +var ( + _ Guard = (*Enum)(nil) + _ Guard = (*Required)(nil) + _ Guard = (*AndGuard)(nil) +) + +func (r *Enum) AcceptGuard(v GuardVisitor) any { return v.VisitEnum(r) } +func (r *Required) AcceptGuard(v GuardVisitor) any { return v.VisitRequired(r) } +func (r *AndGuard) AcceptGuard(v GuardVisitor) any { return v.VisitAndGuard(r) } + +func MatchGuardR3[T0, T1, T2 any]( + x Guard, + f1 func(x *Enum) (T0, T1, T2), + f2 func(x *Required) (T0, T1, T2), + f3 func(x *AndGuard) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *Enum: + return f1(v) + case *Required: + return f2(v) + case *AndGuard: + return f3(v) } - result := make(map[string]Tag) - for k, v := range partial { - key := string(k) - value, err := r._unmarshalJSONTag(v) - if err != nil { - return nil, fmt.Errorf("shape: StructLike._unmarshalJSONmapLb_string_bLTag: value; %w", err) - } - result[key] = value + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchGuardR2[T0, T1 any]( + x Guard, + f1 func(x *Enum) (T0, T1), + f2 func(x *Required) (T0, T1), + f3 func(x *AndGuard) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *Enum: + return f1(v) + case *Required: + return f2(v) + case *AndGuard: + return f3(v) } - return result, nil + var result1 T0 + var result2 T1 + return result1, result2 } -func (r *StructLike) _unmarshalJSONTag(data []byte) (Tag, error) { - result, err := shared.JSONUnmarshal[Tag](data) + +func MatchGuardR1[T0 any]( + x Guard, + f1 func(x *Enum) T0, + f2 func(x *Required) T0, + f3 func(x *AndGuard) T0, +) T0 { + switch v := x.(type) { + case *Enum: + return f1(v) + case *Required: + return f2(v) + case *AndGuard: + return f3(v) + } + var result1 T0 + return result1 +} + +func MatchGuardR0( + x Guard, + f1 func(x *Enum), + f2 func(x *Required), + f3 func(x *AndGuard), +) { + switch v := x.(type) { + case *Enum: + f1(v) + case *Required: + f2(v) + case *AndGuard: + f3(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Guard", GuardFromJSON, GuardToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Enum", EnumFromJSON, EnumToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Required", RequiredFromJSON, RequiredToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.AndGuard", AndGuardFromJSON, AndGuardToJSON) +} + +type GuardUnionJSON struct { + Type string `json:"$type,omitempty"` + Enum json.RawMessage `json:"shape.Enum,omitempty"` + Required json.RawMessage `json:"shape.Required,omitempty"` + AndGuard json.RawMessage `json:"shape.AndGuard,omitempty"` +} + +func GuardFromJSON(x []byte) (Guard, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data GuardUnionJSON + err := json.Unmarshal(x, &data) if err != nil { - return result, fmt.Errorf("shape: StructLike._unmarshalJSONTag: native ref unwrap; %w", err) + return nil, err } - return result, nil + + switch data.Type { + case "shape.Enum": + return EnumFromJSON(data.Enum) + case "shape.Required": + return RequiredFromJSON(data.Required) + case "shape.AndGuard": + return AndGuardFromJSON(data.AndGuard) + } + + if data.Enum != nil { + return EnumFromJSON(data.Enum) + } else if data.Required != nil { + return RequiredFromJSON(data.Required) + } else if data.AndGuard != nil { + return AndGuardFromJSON(data.AndGuard) + } + + return nil, fmt.Errorf("shape.Guard: unknown type %s", data.Type) } -func UnionLikeFromJSON(x []byte) (*UnionLike, error) { - result := new(UnionLike) +func GuardToJSON(x Guard) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchGuardR2( + x, + func(x *Enum) ([]byte, error) { + body, err := EnumToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(GuardUnionJSON{ + Type: "shape.Enum", + Enum: body, + }) + }, + func(x *Required) ([]byte, error) { + body, err := RequiredToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(GuardUnionJSON{ + Type: "shape.Required", + Required: body, + }) + }, + func(x *AndGuard) ([]byte, error) { + body, err := AndGuardToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(GuardUnionJSON{ + Type: "shape.AndGuard", + AndGuard: body, + }) + }, + ) +} + +func EnumFromJSON(x []byte) (*Enum, error) { + result := new(Enum) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1809,248 +1293,336 @@ func UnionLikeFromJSON(x []byte) (*UnionLike, error) { return result, nil } -func UnionLikeToJSON(x *UnionLike) ([]byte, error) { +func EnumToJSON(x *Enum) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*UnionLike)(nil) - _ json.Marshaler = (*UnionLike)(nil) + _ json.Unmarshaler = (*Enum)(nil) + _ json.Marshaler = (*Enum)(nil) ) -func (r *UnionLike) MarshalJSON() ([]byte, error) { +func (r *Enum) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONUnionLike(*r) + return r._marshalJSONEnum(*r) } -func (r *UnionLike) _marshalJSONUnionLike(x UnionLike) ([]byte, error) { +func (r *Enum) _marshalJSONEnum(x Enum) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldName []byte - fieldName, err = r._marshalJSONstring(x.Name) - if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name Name; %w", err) - } - partial["Name"] = fieldName - var fieldPkgName []byte - fieldPkgName, err = r._marshalJSONstring(x.PkgName) - if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name PkgName; %w", err) - } - partial["PkgName"] = fieldPkgName - var fieldPkgImportName []byte - fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) - if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name PkgImportName; %w", err) - } - partial["PkgImportName"] = fieldPkgImportName - var fieldVariant []byte - fieldVariant, err = r._marshalJSONSliceShape(x.Variant) - if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name Variant; %w", err) - } - partial["Variant"] = fieldVariant - var fieldTags []byte - fieldTags, err = r._marshalJSONmapLb_string_bLTag(x.Tags) + var fieldVal []byte + fieldVal, err = r._marshalJSONSlicestring(x.Val) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name Tags; %w", err) + return nil, fmt.Errorf("shape: Enum._marshalJSONEnum: field name Val; %w", err) } - partial["Tags"] = fieldTags + partial["Val"] = fieldVal result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: struct; %w", err) - } - return result, nil -} -func (r *UnionLike) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONstring:; %w", err) + return nil, fmt.Errorf("shape: Enum._marshalJSONEnum: struct; %w", err) } return result, nil } -func (r *UnionLike) _marshalJSONSliceShape(x []Shape) ([]byte, error) { +func (r *Enum) _marshalJSONSlicestring(x []string) ([]byte, error) { partial := make([]json.RawMessage, len(x)) for i, v := range x { - item, err := r._marshalJSONShape(v) + item, err := r._marshalJSONstring(v) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONSliceShape: at index %d; %w", i, err) + return nil, fmt.Errorf("shape: Enum._marshalJSONSlicestring: at index %d; %w", i, err) } partial[i] = item } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONSliceShape:; %w", err) + return nil, fmt.Errorf("shape: Enum._marshalJSONSlicestring:; %w", err) } return result, nil } -func (r *UnionLike) _marshalJSONShape(x Shape) ([]byte, error) { - result, err := shared.JSONMarshal[Shape](x) +func (r *Enum) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONShape:; %w", err) + return nil, fmt.Errorf("shape: Enum._marshalJSONstring:; %w", err) } return result, nil } -func (r *UnionLike) _marshalJSONmapLb_string_bLTag(x map[string]Tag) ([]byte, error) { - partial := make(map[string]json.RawMessage) - for k, v := range x { - key := string(k) - value, err := r._marshalJSONTag(v) +func (r *Enum) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONEnum(data) + if err != nil { + return fmt.Errorf("shape: Enum.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Enum) _unmarshalJSONEnum(data []byte) (Enum, error) { + result := Enum{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("shape: Enum._unmarshalJSONEnum: native struct unwrap; %w", err) + } + if fieldVal, ok := partial["Val"]; ok { + result.Val, err = r._unmarshalJSONSlicestring(fieldVal) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONmapLb_string_bLTag: value; %w", err) + return result, fmt.Errorf("shape: Enum._unmarshalJSONEnum: field Val; %w", err) } - partial[string(key)] = value } - result, err := json.Marshal(partial) + return result, nil +} +func (r *Enum) _unmarshalJSONSlicestring(data []byte) ([]string, error) { + result := make([]string, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONmapLb_string_bLTag:; %w", err) + return result, fmt.Errorf("shape: Enum._unmarshalJSONSlicestring: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONstring(v) + if err != nil { + return result, fmt.Errorf("shape: Enum._unmarshalJSONSlicestring: at index %d; %w", i, err) + } + result = append(result, item) } return result, nil } -func (r *UnionLike) _marshalJSONTag(x Tag) ([]byte, error) { - result, err := shared.JSONMarshal[Tag](x) +func (r *Enum) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._marshalJSONTag:; %w", err) + return result, fmt.Errorf("shape: Enum._unmarshalJSONstring: native primitive unwrap; %w", err) } return result, nil } -func (r *UnionLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONUnionLike(data) + +func RequiredFromJSON(x []byte) (*Required, error) { + result := new(Required) + err := result.UnmarshalJSON(x) if err != nil { - return fmt.Errorf("shape: UnionLike.UnmarshalJSON: %w", err) + return nil, err + } + + return result, nil +} + +func RequiredToJSON(x *Required) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Required)(nil) + _ json.Marshaler = (*Required)(nil) +) + +func (r *Required) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONRequired(*r) +} +func (r *Required) _marshalJSONRequired(x Required) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: Required._marshalJSONRequired: struct; %w", err) + } + return result, nil +} +func (r *Required) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONRequired(data) + if err != nil { + return fmt.Errorf("shape: Required.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *UnionLike) _unmarshalJSONUnionLike(data []byte) (UnionLike, error) { - result := UnionLike{} +func (r *Required) _unmarshalJSONRequired(data []byte) (Required, error) { + result := Required{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: Required._unmarshalJSONRequired: native struct unwrap; %w", err) } - if fieldName, ok := partial["Name"]; ok { - result.Name, err = r._unmarshalJSONstring(fieldName) - if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field Name; %w", err) - } + return result, nil +} + +func AndGuardFromJSON(x []byte) (*AndGuard, error) { + result := new(AndGuard) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err } - if fieldPkgName, ok := partial["PkgName"]; ok { - result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) - if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field PkgName; %w", err) - } + + return result, nil +} + +func AndGuardToJSON(x *AndGuard) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AndGuard)(nil) + _ json.Marshaler = (*AndGuard)(nil) +) + +func (r *AndGuard) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } - if fieldPkgImportName, ok := partial["PkgImportName"]; ok { - result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) - if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field PkgImportName; %w", err) - } + return r._marshalJSONAndGuard(*r) +} +func (r *AndGuard) _marshalJSONAndGuard(x AndGuard) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldL []byte + fieldL, err = r._marshalJSONSliceGuard(x.L) + if err != nil { + return nil, fmt.Errorf("shape: AndGuard._marshalJSONAndGuard: field name L; %w", err) } - if fieldVariant, ok := partial["Variant"]; ok { - result.Variant, err = r._unmarshalJSONSliceShape(fieldVariant) - if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field Variant; %w", err) - } + partial["L"] = fieldL + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: AndGuard._marshalJSONAndGuard: struct; %w", err) } - if fieldTags, ok := partial["Tags"]; ok { - result.Tags, err = r._unmarshalJSONmapLb_string_bLTag(fieldTags) + return result, nil +} +func (r *AndGuard) _marshalJSONSliceGuard(x []Guard) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONGuard(v) if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field Tags; %w", err) + return nil, fmt.Errorf("shape: AndGuard._marshalJSONSliceGuard: at index %d; %w", i, err) } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: AndGuard._marshalJSONSliceGuard:; %w", err) } return result, nil } -func (r *UnionLike) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) +func (r *AndGuard) _marshalJSONGuard(x Guard) ([]byte, error) { + result, err := shared.JSONMarshal[Guard](x) if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONstring: native primitive unwrap; %w", err) + return nil, fmt.Errorf("shape: AndGuard._marshalJSONGuard:; %w", err) } return result, nil } -func (r *UnionLike) _unmarshalJSONSliceShape(data []byte) ([]Shape, error) { - result := make([]Shape, 0) - var partial []json.RawMessage +func (r *AndGuard) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAndGuard(data) + if err != nil { + return fmt.Errorf("shape: AndGuard.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AndGuard) _unmarshalJSONAndGuard(data []byte) (AndGuard, error) { + result := AndGuard{} + var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONSliceShape: native list unwrap; %w", err) + return result, fmt.Errorf("shape: AndGuard._unmarshalJSONAndGuard: native struct unwrap; %w", err) } - for i, v := range partial { - item, err := r._unmarshalJSONShape(v) + if fieldL, ok := partial["L"]; ok { + result.L, err = r._unmarshalJSONSliceGuard(fieldL) if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONSliceShape: at index %d; %w", i, err) + return result, fmt.Errorf("shape: AndGuard._unmarshalJSONAndGuard: field L; %w", err) } - result = append(result, item) - } - return result, nil -} -func (r *UnionLike) _unmarshalJSONShape(data []byte) (Shape, error) { - result, err := shared.JSONUnmarshal[Shape](data) - if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONShape: native ref unwrap; %w", err) } return result, nil } -func (r *UnionLike) _unmarshalJSONmapLb_string_bLTag(data []byte) (map[string]Tag, error) { - var partial map[string]json.RawMessage +func (r *AndGuard) _unmarshalJSONSliceGuard(data []byte) ([]Guard, error) { + result := make([]Guard, 0) + var partial []json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._unmarshalJSONmapLb_string_bLTag: native map unwrap; %w", err) + return result, fmt.Errorf("shape: AndGuard._unmarshalJSONSliceGuard: native list unwrap; %w", err) } - result := make(map[string]Tag) - for k, v := range partial { - key := string(k) - value, err := r._unmarshalJSONTag(v) + for i, v := range partial { + item, err := r._unmarshalJSONGuard(v) if err != nil { - return nil, fmt.Errorf("shape: UnionLike._unmarshalJSONmapLb_string_bLTag: value; %w", err) + return result, fmt.Errorf("shape: AndGuard._unmarshalJSONSliceGuard: at index %d; %w", i, err) } - result[key] = value + result = append(result, item) } return result, nil } -func (r *UnionLike) _unmarshalJSONTag(data []byte) (Tag, error) { - result, err := shared.JSONUnmarshal[Tag](data) +func (r *AndGuard) _unmarshalJSONGuard(data []byte) (Guard, error) { + result, err := shared.JSONUnmarshal[Guard](data) if err != nil { - return result, fmt.Errorf("shape: UnionLike._unmarshalJSONTag: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: AndGuard._unmarshalJSONGuard: native ref unwrap; %w", err) } return result, nil } -type PrimitiveKindVisitor interface { - VisitBooleanLike(v *BooleanLike) any - VisitStringLike(v *StringLike) any - VisitNumberLike(v *NumberLike) any +type ShapeVisitor interface { + VisitAny(v *Any) any + VisitRefName(v *RefName) any + VisitPointerLike(v *PointerLike) any + VisitAliasLike(v *AliasLike) any + VisitPrimitiveLike(v *PrimitiveLike) any + VisitListLike(v *ListLike) any + VisitMapLike(v *MapLike) any + VisitStructLike(v *StructLike) any + VisitUnionLike(v *UnionLike) any } -type PrimitiveKind interface { - AcceptPrimitiveKind(g PrimitiveKindVisitor) any +type Shape interface { + AcceptShape(g ShapeVisitor) any } var ( - _ PrimitiveKind = (*BooleanLike)(nil) - _ PrimitiveKind = (*StringLike)(nil) - _ PrimitiveKind = (*NumberLike)(nil) + _ Shape = (*Any)(nil) + _ Shape = (*RefName)(nil) + _ Shape = (*PointerLike)(nil) + _ Shape = (*AliasLike)(nil) + _ Shape = (*PrimitiveLike)(nil) + _ Shape = (*ListLike)(nil) + _ Shape = (*MapLike)(nil) + _ Shape = (*StructLike)(nil) + _ Shape = (*UnionLike)(nil) ) -func (r *BooleanLike) AcceptPrimitiveKind(v PrimitiveKindVisitor) any { return v.VisitBooleanLike(r) } -func (r *StringLike) AcceptPrimitiveKind(v PrimitiveKindVisitor) any { return v.VisitStringLike(r) } -func (r *NumberLike) AcceptPrimitiveKind(v PrimitiveKindVisitor) any { return v.VisitNumberLike(r) } +func (r *Any) AcceptShape(v ShapeVisitor) any { return v.VisitAny(r) } +func (r *RefName) AcceptShape(v ShapeVisitor) any { return v.VisitRefName(r) } +func (r *PointerLike) AcceptShape(v ShapeVisitor) any { return v.VisitPointerLike(r) } +func (r *AliasLike) AcceptShape(v ShapeVisitor) any { return v.VisitAliasLike(r) } +func (r *PrimitiveLike) AcceptShape(v ShapeVisitor) any { return v.VisitPrimitiveLike(r) } +func (r *ListLike) AcceptShape(v ShapeVisitor) any { return v.VisitListLike(r) } +func (r *MapLike) AcceptShape(v ShapeVisitor) any { return v.VisitMapLike(r) } +func (r *StructLike) AcceptShape(v ShapeVisitor) any { return v.VisitStructLike(r) } +func (r *UnionLike) AcceptShape(v ShapeVisitor) any { return v.VisitUnionLike(r) } -func MatchPrimitiveKindR3[T0, T1, T2 any]( - x PrimitiveKind, - f1 func(x *BooleanLike) (T0, T1, T2), - f2 func(x *StringLike) (T0, T1, T2), - f3 func(x *NumberLike) (T0, T1, T2), +func MatchShapeR3[T0, T1, T2 any]( + x Shape, + f1 func(x *Any) (T0, T1, T2), + f2 func(x *RefName) (T0, T1, T2), + f3 func(x *PointerLike) (T0, T1, T2), + f4 func(x *AliasLike) (T0, T1, T2), + f5 func(x *PrimitiveLike) (T0, T1, T2), + f6 func(x *ListLike) (T0, T1, T2), + f7 func(x *MapLike) (T0, T1, T2), + f8 func(x *StructLike) (T0, T1, T2), + f9 func(x *UnionLike) (T0, T1, T2), ) (T0, T1, T2) { switch v := x.(type) { - case *BooleanLike: + case *Any: return f1(v) - case *StringLike: + case *RefName: return f2(v) - case *NumberLike: + case *PointerLike: return f3(v) + case *AliasLike: + return f4(v) + case *PrimitiveLike: + return f5(v) + case *ListLike: + return f6(v) + case *MapLike: + return f7(v) + case *StructLike: + return f8(v) + case *UnionLike: + return f9(v) } var result1 T0 var result2 T1 @@ -2058,120 +1630,139 @@ func MatchPrimitiveKindR3[T0, T1, T2 any]( return result1, result2, result3 } -func MatchPrimitiveKindR2[T0, T1 any]( - x PrimitiveKind, - f1 func(x *BooleanLike) (T0, T1), - f2 func(x *StringLike) (T0, T1), - f3 func(x *NumberLike) (T0, T1), +func MatchShapeR2[T0, T1 any]( + x Shape, + f1 func(x *Any) (T0, T1), + f2 func(x *RefName) (T0, T1), + f3 func(x *PointerLike) (T0, T1), + f4 func(x *AliasLike) (T0, T1), + f5 func(x *PrimitiveLike) (T0, T1), + f6 func(x *ListLike) (T0, T1), + f7 func(x *MapLike) (T0, T1), + f8 func(x *StructLike) (T0, T1), + f9 func(x *UnionLike) (T0, T1), ) (T0, T1) { switch v := x.(type) { - case *BooleanLike: + case *Any: return f1(v) - case *StringLike: + case *RefName: return f2(v) - case *NumberLike: + case *PointerLike: return f3(v) + case *AliasLike: + return f4(v) + case *PrimitiveLike: + return f5(v) + case *ListLike: + return f6(v) + case *MapLike: + return f7(v) + case *StructLike: + return f8(v) + case *UnionLike: + return f9(v) } var result1 T0 var result2 T1 return result1, result2 } -func MatchPrimitiveKindR1[T0 any]( - x PrimitiveKind, - f1 func(x *BooleanLike) T0, - f2 func(x *StringLike) T0, - f3 func(x *NumberLike) T0, +func MatchShapeR1[T0 any]( + x Shape, + f1 func(x *Any) T0, + f2 func(x *RefName) T0, + f3 func(x *PointerLike) T0, + f4 func(x *AliasLike) T0, + f5 func(x *PrimitiveLike) T0, + f6 func(x *ListLike) T0, + f7 func(x *MapLike) T0, + f8 func(x *StructLike) T0, + f9 func(x *UnionLike) T0, ) T0 { switch v := x.(type) { - case *BooleanLike: + case *Any: return f1(v) - case *StringLike: + case *RefName: return f2(v) - case *NumberLike: + case *PointerLike: return f3(v) + case *AliasLike: + return f4(v) + case *PrimitiveLike: + return f5(v) + case *ListLike: + return f6(v) + case *MapLike: + return f7(v) + case *StructLike: + return f8(v) + case *UnionLike: + return f9(v) } var result1 T0 return result1 } -func MatchPrimitiveKindR0( - x PrimitiveKind, - f1 func(x *BooleanLike), - f2 func(x *StringLike), - f3 func(x *NumberLike), +func MatchShapeR0( + x Shape, + f1 func(x *Any), + f2 func(x *RefName), + f3 func(x *PointerLike), + f4 func(x *AliasLike), + f5 func(x *PrimitiveLike), + f6 func(x *ListLike), + f7 func(x *MapLike), + f8 func(x *StructLike), + f9 func(x *UnionLike), ) { switch v := x.(type) { - case *BooleanLike: + case *Any: f1(v) - case *StringLike: + case *RefName: f2(v) - case *NumberLike: + case *PointerLike: f3(v) - } -} - -func PrimitiveKindShape() Shape { - return &UnionLike{ - Name: "PrimitiveKind", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Variant: []Shape{ - BooleanLikeShape(), - StringLikeShape(), - NumberLikeShape(), - }, - } -} - -func BooleanLikeShape() Shape { - return &StructLike{ - Name: "BooleanLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } -} - -func StringLikeShape() Shape { - return &StructLike{ - Name: "StringLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } -} - -func NumberLikeShape() Shape { - return &StructLike{ - Name: "NumberLike", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Kind", - Type: &RefName{ - Name: "NumberKind", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, + case *AliasLike: + f4(v) + case *PrimitiveLike: + f5(v) + case *ListLike: + f6(v) + case *MapLike: + f7(v) + case *StructLike: + f8(v) + case *UnionLike: + f9(v) } } func init() { - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.PrimitiveKind", PrimitiveKindFromJSON, PrimitiveKindToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.BooleanLike", BooleanLikeFromJSON, BooleanLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.StringLike", StringLikeFromJSON, StringLikeToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.NumberLike", NumberLikeFromJSON, NumberLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Shape", ShapeFromJSON, ShapeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Any", AnyFromJSON, AnyToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.RefName", RefNameFromJSON, RefNameToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.PointerLike", PointerLikeFromJSON, PointerLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.AliasLike", AliasLikeFromJSON, AliasLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.PrimitiveLike", PrimitiveLikeFromJSON, PrimitiveLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.ListLike", ListLikeFromJSON, ListLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.MapLike", MapLikeFromJSON, MapLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.StructLike", StructLikeFromJSON, StructLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UnionLike", UnionLikeFromJSON, UnionLikeToJSON) } -type PrimitiveKindUnionJSON struct { - Type string `json:"$type,omitempty"` - BooleanLike json.RawMessage `json:"shape.BooleanLike,omitempty"` - StringLike json.RawMessage `json:"shape.StringLike,omitempty"` - NumberLike json.RawMessage `json:"shape.NumberLike,omitempty"` +type ShapeUnionJSON struct { + Type string `json:"$type,omitempty"` + Any json.RawMessage `json:"shape.Any,omitempty"` + RefName json.RawMessage `json:"shape.RefName,omitempty"` + PointerLike json.RawMessage `json:"shape.PointerLike,omitempty"` + AliasLike json.RawMessage `json:"shape.AliasLike,omitempty"` + PrimitiveLike json.RawMessage `json:"shape.PrimitiveLike,omitempty"` + ListLike json.RawMessage `json:"shape.ListLike,omitempty"` + MapLike json.RawMessage `json:"shape.MapLike,omitempty"` + StructLike json.RawMessage `json:"shape.StructLike,omitempty"` + UnionLike json.RawMessage `json:"shape.UnionLike,omitempty"` } -func PrimitiveKindFromJSON(x []byte) (PrimitiveKind, error) { +func ShapeFromJSON(x []byte) (Shape, error) { if x == nil || len(x) == 0 { return nil, nil } @@ -2179,76 +1770,166 @@ func PrimitiveKindFromJSON(x []byte) (PrimitiveKind, error) { return nil, nil } - var data PrimitiveKindUnionJSON + var data ShapeUnionJSON err := json.Unmarshal(x, &data) if err != nil { return nil, err } switch data.Type { - case "shape.BooleanLike": - return BooleanLikeFromJSON(data.BooleanLike) - case "shape.StringLike": - return StringLikeFromJSON(data.StringLike) - case "shape.NumberLike": - return NumberLikeFromJSON(data.NumberLike) + case "shape.Any": + return AnyFromJSON(data.Any) + case "shape.RefName": + return RefNameFromJSON(data.RefName) + case "shape.PointerLike": + return PointerLikeFromJSON(data.PointerLike) + case "shape.AliasLike": + return AliasLikeFromJSON(data.AliasLike) + case "shape.PrimitiveLike": + return PrimitiveLikeFromJSON(data.PrimitiveLike) + case "shape.ListLike": + return ListLikeFromJSON(data.ListLike) + case "shape.MapLike": + return MapLikeFromJSON(data.MapLike) + case "shape.StructLike": + return StructLikeFromJSON(data.StructLike) + case "shape.UnionLike": + return UnionLikeFromJSON(data.UnionLike) } - if data.BooleanLike != nil { - return BooleanLikeFromJSON(data.BooleanLike) - } else if data.StringLike != nil { - return StringLikeFromJSON(data.StringLike) - } else if data.NumberLike != nil { - return NumberLikeFromJSON(data.NumberLike) + if data.Any != nil { + return AnyFromJSON(data.Any) + } else if data.RefName != nil { + return RefNameFromJSON(data.RefName) + } else if data.PointerLike != nil { + return PointerLikeFromJSON(data.PointerLike) + } else if data.AliasLike != nil { + return AliasLikeFromJSON(data.AliasLike) + } else if data.PrimitiveLike != nil { + return PrimitiveLikeFromJSON(data.PrimitiveLike) + } else if data.ListLike != nil { + return ListLikeFromJSON(data.ListLike) + } else if data.MapLike != nil { + return MapLikeFromJSON(data.MapLike) + } else if data.StructLike != nil { + return StructLikeFromJSON(data.StructLike) + } else if data.UnionLike != nil { + return UnionLikeFromJSON(data.UnionLike) } - return nil, fmt.Errorf("shape.PrimitiveKind: unknown type %s", data.Type) + return nil, fmt.Errorf("shape.Shape: unknown type %s", data.Type) } -func PrimitiveKindToJSON(x PrimitiveKind) ([]byte, error) { +func ShapeToJSON(x Shape) ([]byte, error) { if x == nil { return nil, nil } - return MatchPrimitiveKindR2( + return MatchShapeR2( x, - func(x *BooleanLike) ([]byte, error) { - body, err := BooleanLikeToJSON(x) + func(x *Any) ([]byte, error) { + body, err := AnyToJSON(x) if err != nil { return nil, err } - return json.Marshal(PrimitiveKindUnionJSON{ - Type: "shape.BooleanLike", - BooleanLike: body, + return json.Marshal(ShapeUnionJSON{ + Type: "shape.Any", + Any: body, }) }, - func(x *StringLike) ([]byte, error) { - body, err := StringLikeToJSON(x) + func(x *RefName) ([]byte, error) { + body, err := RefNameToJSON(x) if err != nil { return nil, err } - return json.Marshal(PrimitiveKindUnionJSON{ - Type: "shape.StringLike", - StringLike: body, + return json.Marshal(ShapeUnionJSON{ + Type: "shape.RefName", + RefName: body, }) }, - func(x *NumberLike) ([]byte, error) { - body, err := NumberLikeToJSON(x) + func(x *PointerLike) ([]byte, error) { + body, err := PointerLikeToJSON(x) if err != nil { return nil, err } - return json.Marshal(PrimitiveKindUnionJSON{ - Type: "shape.NumberLike", - NumberLike: body, + return json.Marshal(ShapeUnionJSON{ + Type: "shape.PointerLike", + PointerLike: body, + }) + }, + func(x *AliasLike) ([]byte, error) { + body, err := AliasLikeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ShapeUnionJSON{ + Type: "shape.AliasLike", + AliasLike: body, + }) + }, + func(x *PrimitiveLike) ([]byte, error) { + body, err := PrimitiveLikeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ShapeUnionJSON{ + Type: "shape.PrimitiveLike", + PrimitiveLike: body, + }) + }, + func(x *ListLike) ([]byte, error) { + body, err := ListLikeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ShapeUnionJSON{ + Type: "shape.ListLike", + ListLike: body, + }) + }, + func(x *MapLike) ([]byte, error) { + body, err := MapLikeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ShapeUnionJSON{ + Type: "shape.MapLike", + MapLike: body, + }) + }, + func(x *StructLike) ([]byte, error) { + body, err := StructLikeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ShapeUnionJSON{ + Type: "shape.StructLike", + StructLike: body, + }) + }, + func(x *UnionLike) ([]byte, error) { + body, err := UnionLikeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ShapeUnionJSON{ + Type: "shape.UnionLike", + UnionLike: body, }) }, ) } -func BooleanLikeFromJSON(x []byte) (*BooleanLike, error) { - result := new(BooleanLike) +func AnyFromJSON(x []byte) (*Any, error) { + result := new(Any) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -2257,50 +1938,50 @@ func BooleanLikeFromJSON(x []byte) (*BooleanLike, error) { return result, nil } -func BooleanLikeToJSON(x *BooleanLike) ([]byte, error) { +func AnyToJSON(x *Any) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*BooleanLike)(nil) - _ json.Marshaler = (*BooleanLike)(nil) + _ json.Unmarshaler = (*Any)(nil) + _ json.Marshaler = (*Any)(nil) ) -func (r *BooleanLike) MarshalJSON() ([]byte, error) { +func (r *Any) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONBooleanLike(*r) + return r._marshalJSONAny(*r) } -func (r *BooleanLike) _marshalJSONBooleanLike(x BooleanLike) ([]byte, error) { +func (r *Any) _marshalJSONAny(x Any) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: BooleanLike._marshalJSONBooleanLike: struct; %w", err) + return nil, fmt.Errorf("shape: Any._marshalJSONAny: struct; %w", err) } return result, nil } -func (r *BooleanLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONBooleanLike(data) +func (r *Any) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAny(data) if err != nil { - return fmt.Errorf("shape: BooleanLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: Any.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *BooleanLike) _unmarshalJSONBooleanLike(data []byte) (BooleanLike, error) { - result := BooleanLike{} +func (r *Any) _unmarshalJSONAny(data []byte) (Any, error) { + result := Any{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: BooleanLike._unmarshalJSONBooleanLike: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: Any._unmarshalJSONAny: native struct unwrap; %w", err) } return result, nil } -func StringLikeFromJSON(x []byte) (*StringLike, error) { - result := new(StringLike) +func RefNameFromJSON(x []byte) (*RefName, error) { + result := new(RefName) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -2309,768 +1990,451 @@ func StringLikeFromJSON(x []byte) (*StringLike, error) { return result, nil } -func StringLikeToJSON(x *StringLike) ([]byte, error) { +func RefNameToJSON(x *RefName) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*StringLike)(nil) - _ json.Marshaler = (*StringLike)(nil) + _ json.Unmarshaler = (*RefName)(nil) + _ json.Marshaler = (*RefName)(nil) ) -func (r *StringLike) MarshalJSON() ([]byte, error) { +func (r *RefName) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONStringLike(*r) + return r._marshalJSONRefName(*r) } -func (r *StringLike) _marshalJSONStringLike(x StringLike) ([]byte, error) { +func (r *RefName) _marshalJSONRefName(x RefName) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - result, err := json.Marshal(partial) + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) if err != nil { - return nil, fmt.Errorf("shape: StringLike._marshalJSONStringLike: struct; %w", err) + return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name Name; %w", err) } - return result, nil -} -func (r *StringLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONStringLike(data) + partial["Name"] = fieldName + var fieldPkgName []byte + fieldPkgName, err = r._marshalJSONstring(x.PkgName) if err != nil { - return fmt.Errorf("shape: StringLike.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name PkgName; %w", err) } - *r = result - return nil -} -func (r *StringLike) _unmarshalJSONStringLike(data []byte) (StringLike, error) { - result := StringLike{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) + partial["PkgName"] = fieldPkgName + var fieldPkgImportName []byte + fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) if err != nil { - return result, fmt.Errorf("shape: StringLike._unmarshalJSONStringLike: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name PkgImportName; %w", err) } - return result, nil -} - -func NumberLikeFromJSON(x []byte) (*NumberLike, error) { - result := new(NumberLike) - err := result.UnmarshalJSON(x) + partial["PkgImportName"] = fieldPkgImportName + var fieldIndexed []byte + fieldIndexed, err = r._marshalJSONSliceShape(x.Indexed) if err != nil { - return nil, err + return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: field name Indexed; %w", err) + } + partial["Indexed"] = fieldIndexed + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: RefName._marshalJSONRefName: struct; %w", err) } - return result, nil } - -func NumberLikeToJSON(x *NumberLike) ([]byte, error) { - return x.MarshalJSON() -} - -var ( - _ json.Unmarshaler = (*NumberLike)(nil) - _ json.Marshaler = (*NumberLike)(nil) -) - -func (r *NumberLike) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil +func (r *RefName) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("shape: RefName._marshalJSONstring:; %w", err) } - return r._marshalJSONNumberLike(*r) + return result, nil } -func (r *NumberLike) _marshalJSONNumberLike(x NumberLike) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - var fieldKind []byte - fieldKind, err = r._marshalJSONNumberKind(x.Kind) - if err != nil { - return nil, fmt.Errorf("shape: NumberLike._marshalJSONNumberLike: field name Kind; %w", err) +func (r *RefName) _marshalJSONSliceShape(x []Shape) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONShape(v) + if err != nil { + return nil, fmt.Errorf("shape: RefName._marshalJSONSliceShape: at index %d; %w", i, err) + } + partial[i] = item } - partial["Kind"] = fieldKind result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: NumberLike._marshalJSONNumberLike: struct; %w", err) + return nil, fmt.Errorf("shape: RefName._marshalJSONSliceShape:; %w", err) } return result, nil } -func (r *NumberLike) _marshalJSONNumberKind(x NumberKind) ([]byte, error) { - result, err := shared.JSONMarshal[NumberKind](x) +func (r *RefName) _marshalJSONShape(x Shape) ([]byte, error) { + result, err := shared.JSONMarshal[Shape](x) if err != nil { - return nil, fmt.Errorf("shape: NumberLike._marshalJSONNumberKind:; %w", err) + return nil, fmt.Errorf("shape: RefName._marshalJSONShape:; %w", err) } return result, nil } -func (r *NumberLike) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONNumberLike(data) +func (r *RefName) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONRefName(data) if err != nil { - return fmt.Errorf("shape: NumberLike.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: RefName.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *NumberLike) _unmarshalJSONNumberLike(data []byte) (NumberLike, error) { - result := NumberLike{} +func (r *RefName) _unmarshalJSONRefName(data []byte) (RefName, error) { + result := RefName{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: NumberLike._unmarshalJSONNumberLike: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: native struct unwrap; %w", err) } - if fieldKind, ok := partial["Kind"]; ok { - result.Kind, err = r._unmarshalJSONNumberKind(fieldKind) + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) if err != nil { - return result, fmt.Errorf("shape: NumberLike._unmarshalJSONNumberLike: field Kind; %w", err) + return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field Name; %w", err) } } - return result, nil -} -func (r *NumberLike) _unmarshalJSONNumberKind(data []byte) (NumberKind, error) { - result, err := shared.JSONUnmarshal[NumberKind](data) - if err != nil { - return result, fmt.Errorf("shape: NumberLike._unmarshalJSONNumberKind: native ref unwrap; %w", err) - } + if fieldPkgName, ok := partial["PkgName"]; ok { + result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field PkgName; %w", err) + } + } + if fieldPkgImportName, ok := partial["PkgImportName"]; ok { + result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field PkgImportName; %w", err) + } + } + if fieldIndexed, ok := partial["Indexed"]; ok { + result.Indexed, err = r._unmarshalJSONSliceShape(fieldIndexed) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONRefName: field Indexed; %w", err) + } + } + return result, nil +} +func (r *RefName) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *RefName) _unmarshalJSONSliceShape(data []byte) ([]Shape, error) { + result := make([]Shape, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONSliceShape: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONShape(v) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONSliceShape: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *RefName) _unmarshalJSONShape(data []byte) (Shape, error) { + result, err := shared.JSONUnmarshal[Shape](data) + if err != nil { + return result, fmt.Errorf("shape: RefName._unmarshalJSONShape: native ref unwrap; %w", err) + } return result, nil } -type NumberKindVisitor interface { - VisitUInt(v *UInt) any - VisitUInt8(v *UInt8) any - VisitUInt16(v *UInt16) any - VisitUInt32(v *UInt32) any - VisitUInt64(v *UInt64) any - VisitInt(v *Int) any - VisitInt8(v *Int8) any - VisitInt16(v *Int16) any - VisitInt32(v *Int32) any - VisitInt64(v *Int64) any - VisitFloat32(v *Float32) any - VisitFloat64(v *Float64) any +func PointerLikeFromJSON(x []byte) (*PointerLike, error) { + result := new(PointerLike) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil } -type NumberKind interface { - AcceptNumberKind(g NumberKindVisitor) any +func PointerLikeToJSON(x *PointerLike) ([]byte, error) { + return x.MarshalJSON() } var ( - _ NumberKind = (*UInt)(nil) - _ NumberKind = (*UInt8)(nil) - _ NumberKind = (*UInt16)(nil) - _ NumberKind = (*UInt32)(nil) - _ NumberKind = (*UInt64)(nil) - _ NumberKind = (*Int)(nil) - _ NumberKind = (*Int8)(nil) - _ NumberKind = (*Int16)(nil) - _ NumberKind = (*Int32)(nil) - _ NumberKind = (*Int64)(nil) - _ NumberKind = (*Float32)(nil) - _ NumberKind = (*Float64)(nil) + _ json.Unmarshaler = (*PointerLike)(nil) + _ json.Marshaler = (*PointerLike)(nil) ) -func (r *UInt) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt(r) } -func (r *UInt8) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt8(r) } -func (r *UInt16) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt16(r) } -func (r *UInt32) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt32(r) } -func (r *UInt64) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitUInt64(r) } -func (r *Int) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt(r) } -func (r *Int8) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt8(r) } -func (r *Int16) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt16(r) } -func (r *Int32) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt32(r) } -func (r *Int64) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitInt64(r) } -func (r *Float32) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitFloat32(r) } -func (r *Float64) AcceptNumberKind(v NumberKindVisitor) any { return v.VisitFloat64(r) } - -func MatchNumberKindR3[T0, T1, T2 any]( - x NumberKind, - f1 func(x *UInt) (T0, T1, T2), - f2 func(x *UInt8) (T0, T1, T2), - f3 func(x *UInt16) (T0, T1, T2), - f4 func(x *UInt32) (T0, T1, T2), - f5 func(x *UInt64) (T0, T1, T2), - f6 func(x *Int) (T0, T1, T2), - f7 func(x *Int8) (T0, T1, T2), - f8 func(x *Int16) (T0, T1, T2), - f9 func(x *Int32) (T0, T1, T2), - f10 func(x *Int64) (T0, T1, T2), - f11 func(x *Float32) (T0, T1, T2), - f12 func(x *Float64) (T0, T1, T2), -) (T0, T1, T2) { - switch v := x.(type) { - case *UInt: - return f1(v) - case *UInt8: - return f2(v) - case *UInt16: - return f3(v) - case *UInt32: - return f4(v) - case *UInt64: - return f5(v) - case *Int: - return f6(v) - case *Int8: - return f7(v) - case *Int16: - return f8(v) - case *Int32: - return f9(v) - case *Int64: - return f10(v) - case *Float32: - return f11(v) - case *Float64: - return f12(v) +func (r *PointerLike) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } - var result1 T0 - var result2 T1 - var result3 T2 - return result1, result2, result3 + return r._marshalJSONPointerLike(*r) } - -func MatchNumberKindR2[T0, T1 any]( - x NumberKind, - f1 func(x *UInt) (T0, T1), - f2 func(x *UInt8) (T0, T1), - f3 func(x *UInt16) (T0, T1), - f4 func(x *UInt32) (T0, T1), - f5 func(x *UInt64) (T0, T1), - f6 func(x *Int) (T0, T1), - f7 func(x *Int8) (T0, T1), - f8 func(x *Int16) (T0, T1), - f9 func(x *Int32) (T0, T1), - f10 func(x *Int64) (T0, T1), - f11 func(x *Float32) (T0, T1), - f12 func(x *Float64) (T0, T1), -) (T0, T1) { - switch v := x.(type) { - case *UInt: - return f1(v) - case *UInt8: - return f2(v) - case *UInt16: - return f3(v) - case *UInt32: - return f4(v) - case *UInt64: - return f5(v) - case *Int: - return f6(v) - case *Int8: - return f7(v) - case *Int16: - return f8(v) - case *Int32: - return f9(v) - case *Int64: - return f10(v) - case *Float32: - return f11(v) - case *Float64: - return f12(v) +func (r *PointerLike) _marshalJSONPointerLike(x PointerLike) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldType []byte + fieldType, err = r._marshalJSONShape(x.Type) + if err != nil { + return nil, fmt.Errorf("shape: PointerLike._marshalJSONPointerLike: field name Type; %w", err) } - var result1 T0 - var result2 T1 - return result1, result2 + partial["Type"] = fieldType + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: PointerLike._marshalJSONPointerLike: struct; %w", err) + } + return result, nil } - -func MatchNumberKindR1[T0 any]( - x NumberKind, - f1 func(x *UInt) T0, - f2 func(x *UInt8) T0, - f3 func(x *UInt16) T0, - f4 func(x *UInt32) T0, - f5 func(x *UInt64) T0, - f6 func(x *Int) T0, - f7 func(x *Int8) T0, - f8 func(x *Int16) T0, - f9 func(x *Int32) T0, - f10 func(x *Int64) T0, - f11 func(x *Float32) T0, - f12 func(x *Float64) T0, -) T0 { - switch v := x.(type) { - case *UInt: - return f1(v) - case *UInt8: - return f2(v) - case *UInt16: - return f3(v) - case *UInt32: - return f4(v) - case *UInt64: - return f5(v) - case *Int: - return f6(v) - case *Int8: - return f7(v) - case *Int16: - return f8(v) - case *Int32: - return f9(v) - case *Int64: - return f10(v) - case *Float32: - return f11(v) - case *Float64: - return f12(v) +func (r *PointerLike) _marshalJSONShape(x Shape) ([]byte, error) { + result, err := shared.JSONMarshal[Shape](x) + if err != nil { + return nil, fmt.Errorf("shape: PointerLike._marshalJSONShape:; %w", err) } - var result1 T0 - return result1 + return result, nil } - -func MatchNumberKindR0( - x NumberKind, - f1 func(x *UInt), - f2 func(x *UInt8), - f3 func(x *UInt16), - f4 func(x *UInt32), - f5 func(x *UInt64), - f6 func(x *Int), - f7 func(x *Int8), - f8 func(x *Int16), - f9 func(x *Int32), - f10 func(x *Int64), - f11 func(x *Float32), - f12 func(x *Float64), -) { - switch v := x.(type) { - case *UInt: - f1(v) - case *UInt8: - f2(v) - case *UInt16: - f3(v) - case *UInt32: - f4(v) - case *UInt64: - f5(v) - case *Int: - f6(v) - case *Int8: - f7(v) - case *Int16: - f8(v) - case *Int32: - f9(v) - case *Int64: - f10(v) - case *Float32: - f11(v) - case *Float64: - f12(v) +func (r *PointerLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONPointerLike(data) + if err != nil { + return fmt.Errorf("shape: PointerLike.UnmarshalJSON: %w", err) } + *r = result + return nil } - -func NumberKindShape() Shape { - return &UnionLike{ - Name: "NumberKind", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Variant: []Shape{ - UIntShape(), - UInt8Shape(), - UInt16Shape(), - UInt32Shape(), - UInt64Shape(), - IntShape(), - Int8Shape(), - Int16Shape(), - Int32Shape(), - Int64Shape(), - Float32Shape(), - Float64Shape(), - }, +func (r *PointerLike) _unmarshalJSONPointerLike(data []byte) (PointerLike, error) { + result := PointerLike{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("shape: PointerLike._unmarshalJSONPointerLike: native struct unwrap; %w", err) } -} - -func UIntShape() Shape { - return &StructLike{ - Name: "UInt", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", + if fieldType, ok := partial["Type"]; ok { + result.Type, err = r._unmarshalJSONShape(fieldType) + if err != nil { + return result, fmt.Errorf("shape: PointerLike._unmarshalJSONPointerLike: field Type; %w", err) + } } + return result, nil } - -func UInt8Shape() Shape { - return &StructLike{ - Name: "UInt8", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", +func (r *PointerLike) _unmarshalJSONShape(data []byte) (Shape, error) { + result, err := shared.JSONUnmarshal[Shape](data) + if err != nil { + return result, fmt.Errorf("shape: PointerLike._unmarshalJSONShape: native ref unwrap; %w", err) } + return result, nil } -func UInt16Shape() Shape { - return &StructLike{ - Name: "UInt16", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", +func AliasLikeFromJSON(x []byte) (*AliasLike, error) { + result := new(AliasLike) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err } -} -func UInt32Shape() Shape { - return &StructLike{ - Name: "UInt32", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } + return result, nil } -func UInt64Shape() Shape { - return &StructLike{ - Name: "UInt64", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } +func AliasLikeToJSON(x *AliasLike) ([]byte, error) { + return x.MarshalJSON() } -func IntShape() Shape { - return &StructLike{ - Name: "Int", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } -} +var ( + _ json.Unmarshaler = (*AliasLike)(nil) + _ json.Marshaler = (*AliasLike)(nil) +) -func Int8Shape() Shape { - return &StructLike{ - Name: "Int8", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", +func (r *AliasLike) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } + return r._marshalJSONAliasLike(*r) } - -func Int16Shape() Shape { - return &StructLike{ - Name: "Int16", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", +func (r *AliasLike) _marshalJSONAliasLike(x AliasLike) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name Name; %w", err) } -} - -func Int32Shape() Shape { - return &StructLike{ - Name: "Int32", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", + partial["Name"] = fieldName + var fieldPkgName []byte + fieldPkgName, err = r._marshalJSONstring(x.PkgName) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name PkgName; %w", err) } -} - -func Int64Shape() Shape { - return &StructLike{ - Name: "Int64", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", + partial["PkgName"] = fieldPkgName + var fieldPkgImportName []byte + fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name PkgImportName; %w", err) } -} - -func Float32Shape() Shape { - return &StructLike{ - Name: "Float32", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", + partial["PkgImportName"] = fieldPkgImportName + var fieldIsAlias []byte + fieldIsAlias, err = r._marshalJSONbool(x.IsAlias) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name IsAlias; %w", err) } -} - -func Float64Shape() Shape { - return &StructLike{ - Name: "Float64", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", + partial["IsAlias"] = fieldIsAlias + var fieldType []byte + fieldType, err = r._marshalJSONShape(x.Type) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name Type; %w", err) + } + partial["Type"] = fieldType + var fieldTags []byte + fieldTags, err = r._marshalJSONmapLb_string_bLTag(x.Tags) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: field name Tags; %w", err) + } + partial["Tags"] = fieldTags + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONAliasLike: struct; %w", err) } + return result, nil } -func init() { - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.NumberKind", NumberKindFromJSON, NumberKindToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt", UIntFromJSON, UIntToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt8", UInt8FromJSON, UInt8ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt16", UInt16FromJSON, UInt16ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt32", UInt32FromJSON, UInt32ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.UInt64", UInt64FromJSON, UInt64ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int", IntFromJSON, IntToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int8", Int8FromJSON, Int8ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int16", Int16FromJSON, Int16ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int32", Int32FromJSON, Int32ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Int64", Int64FromJSON, Int64ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Float32", Float32FromJSON, Float32ToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Float64", Float64FromJSON, Float64ToJSON) +func (r *AliasLike) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONstring:; %w", err) + } + return result, nil } - -type NumberKindUnionJSON struct { - Type string `json:"$type,omitempty"` - UInt json.RawMessage `json:"shape.UInt,omitempty"` - UInt8 json.RawMessage `json:"shape.UInt8,omitempty"` - UInt16 json.RawMessage `json:"shape.UInt16,omitempty"` - UInt32 json.RawMessage `json:"shape.UInt32,omitempty"` - UInt64 json.RawMessage `json:"shape.UInt64,omitempty"` - Int json.RawMessage `json:"shape.Int,omitempty"` - Int8 json.RawMessage `json:"shape.Int8,omitempty"` - Int16 json.RawMessage `json:"shape.Int16,omitempty"` - Int32 json.RawMessage `json:"shape.Int32,omitempty"` - Int64 json.RawMessage `json:"shape.Int64,omitempty"` - Float32 json.RawMessage `json:"shape.Float32,omitempty"` - Float64 json.RawMessage `json:"shape.Float64,omitempty"` +func (r *AliasLike) _marshalJSONbool(x bool) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONbool:; %w", err) + } + return result, nil } - -func NumberKindFromJSON(x []byte) (NumberKind, error) { - if x == nil || len(x) == 0 { - return nil, nil +func (r *AliasLike) _marshalJSONShape(x Shape) ([]byte, error) { + result, err := shared.JSONMarshal[Shape](x) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONShape:; %w", err) } - if string(x[:4]) == "null" { - return nil, nil + return result, nil +} +func (r *AliasLike) _marshalJSONmapLb_string_bLTag(x map[string]Tag) ([]byte, error) { + partial := make(map[string]json.RawMessage) + for k, v := range x { + key := string(k) + value, err := r._marshalJSONTag(v) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONmapLb_string_bLTag: value; %w", err) + } + partial[string(key)] = value } - - var data NumberKindUnionJSON - err := json.Unmarshal(x, &data) + result, err := json.Marshal(partial) if err != nil { - return nil, err - } - - switch data.Type { - case "shape.UInt": - return UIntFromJSON(data.UInt) - case "shape.UInt8": - return UInt8FromJSON(data.UInt8) - case "shape.UInt16": - return UInt16FromJSON(data.UInt16) - case "shape.UInt32": - return UInt32FromJSON(data.UInt32) - case "shape.UInt64": - return UInt64FromJSON(data.UInt64) - case "shape.Int": - return IntFromJSON(data.Int) - case "shape.Int8": - return Int8FromJSON(data.Int8) - case "shape.Int16": - return Int16FromJSON(data.Int16) - case "shape.Int32": - return Int32FromJSON(data.Int32) - case "shape.Int64": - return Int64FromJSON(data.Int64) - case "shape.Float32": - return Float32FromJSON(data.Float32) - case "shape.Float64": - return Float64FromJSON(data.Float64) + return nil, fmt.Errorf("shape: AliasLike._marshalJSONmapLb_string_bLTag:; %w", err) } - - if data.UInt != nil { - return UIntFromJSON(data.UInt) - } else if data.UInt8 != nil { - return UInt8FromJSON(data.UInt8) - } else if data.UInt16 != nil { - return UInt16FromJSON(data.UInt16) - } else if data.UInt32 != nil { - return UInt32FromJSON(data.UInt32) - } else if data.UInt64 != nil { - return UInt64FromJSON(data.UInt64) - } else if data.Int != nil { - return IntFromJSON(data.Int) - } else if data.Int8 != nil { - return Int8FromJSON(data.Int8) - } else if data.Int16 != nil { - return Int16FromJSON(data.Int16) - } else if data.Int32 != nil { - return Int32FromJSON(data.Int32) - } else if data.Int64 != nil { - return Int64FromJSON(data.Int64) - } else if data.Float32 != nil { - return Float32FromJSON(data.Float32) - } else if data.Float64 != nil { - return Float64FromJSON(data.Float64) + return result, nil +} +func (r *AliasLike) _marshalJSONTag(x Tag) ([]byte, error) { + result, err := shared.JSONMarshal[Tag](x) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._marshalJSONTag:; %w", err) } - - return nil, fmt.Errorf("shape.NumberKind: unknown type %s", data.Type) + return result, nil } - -func NumberKindToJSON(x NumberKind) ([]byte, error) { - if x == nil { - return nil, nil +func (r *AliasLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAliasLike(data) + if err != nil { + return fmt.Errorf("shape: AliasLike.UnmarshalJSON: %w", err) } - return MatchNumberKindR2( - x, - func(x *UInt) ([]byte, error) { - body, err := UIntToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.UInt", - UInt: body, - }) - }, - func(x *UInt8) ([]byte, error) { - body, err := UInt8ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.UInt8", - UInt8: body, - }) - }, - func(x *UInt16) ([]byte, error) { - body, err := UInt16ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.UInt16", - UInt16: body, - }) - }, - func(x *UInt32) ([]byte, error) { - body, err := UInt32ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.UInt32", - UInt32: body, - }) - }, - func(x *UInt64) ([]byte, error) { - body, err := UInt64ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.UInt64", - UInt64: body, - }) - }, - func(x *Int) ([]byte, error) { - body, err := IntToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Int", - Int: body, - }) - }, - func(x *Int8) ([]byte, error) { - body, err := Int8ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Int8", - Int8: body, - }) - }, - func(x *Int16) ([]byte, error) { - body, err := Int16ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Int16", - Int16: body, - }) - }, - func(x *Int32) ([]byte, error) { - body, err := Int32ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Int32", - Int32: body, - }) - }, - func(x *Int64) ([]byte, error) { - body, err := Int64ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Int64", - Int64: body, - }) - }, - func(x *Float32) ([]byte, error) { - body, err := Float32ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Float32", - Float32: body, - }) - }, - func(x *Float64) ([]byte, error) { - body, err := Float64ToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(NumberKindUnionJSON{ - Type: "shape.Float64", - Float64: body, - }) - }, - ) + *r = result + return nil } - -func UIntFromJSON(x []byte) (*UInt, error) { - result := new(UInt) - err := result.UnmarshalJSON(x) +func (r *AliasLike) _unmarshalJSONAliasLike(data []byte) (AliasLike, error) { + result := AliasLike{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return nil, err + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: native struct unwrap; %w", err) + } + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field Name; %w", err) + } + } + if fieldPkgName, ok := partial["PkgName"]; ok { + result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field PkgName; %w", err) + } + } + if fieldPkgImportName, ok := partial["PkgImportName"]; ok { + result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field PkgImportName; %w", err) + } + } + if fieldIsAlias, ok := partial["IsAlias"]; ok { + result.IsAlias, err = r._unmarshalJSONbool(fieldIsAlias) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field IsAlias; %w", err) + } + } + if fieldType, ok := partial["Type"]; ok { + result.Type, err = r._unmarshalJSONShape(fieldType) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field Type; %w", err) + } + } + if fieldTags, ok := partial["Tags"]; ok { + result.Tags, err = r._unmarshalJSONmapLb_string_bLTag(fieldTags) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONAliasLike: field Tags; %w", err) + } } - return result, nil } - -func UIntToJSON(x *UInt) ([]byte, error) { - return x.MarshalJSON() -} - -var ( - _ json.Unmarshaler = (*UInt)(nil) - _ json.Marshaler = (*UInt)(nil) -) - -func (r *UInt) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil +func (r *AliasLike) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONstring: native primitive unwrap; %w", err) } - return r._marshalJSONUInt(*r) + return result, nil } -func (r *UInt) _marshalJSONUInt(x UInt) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - result, err := json.Marshal(partial) +func (r *AliasLike) _unmarshalJSONbool(data []byte) (bool, error) { + var result bool + err := json.Unmarshal(data, &result) if err != nil { - return nil, fmt.Errorf("shape: UInt._marshalJSONUInt: struct; %w", err) + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONbool: native primitive unwrap; %w", err) } return result, nil } -func (r *UInt) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONUInt(data) +func (r *AliasLike) _unmarshalJSONShape(data []byte) (Shape, error) { + result, err := shared.JSONUnmarshal[Shape](data) if err != nil { - return fmt.Errorf("shape: UInt.UnmarshalJSON: %w", err) + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONShape: native ref unwrap; %w", err) } - *r = result - return nil + return result, nil } -func (r *UInt) _unmarshalJSONUInt(data []byte) (UInt, error) { - result := UInt{} +func (r *AliasLike) _unmarshalJSONmapLb_string_bLTag(data []byte) (map[string]Tag, error) { var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: UInt._unmarshalJSONUInt: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: AliasLike._unmarshalJSONmapLb_string_bLTag: native map unwrap; %w", err) + } + result := make(map[string]Tag) + for k, v := range partial { + key := string(k) + value, err := r._unmarshalJSONTag(v) + if err != nil { + return nil, fmt.Errorf("shape: AliasLike._unmarshalJSONmapLb_string_bLTag: value; %w", err) + } + result[key] = value + } + return result, nil +} +func (r *AliasLike) _unmarshalJSONTag(data []byte) (Tag, error) { + result, err := shared.JSONUnmarshal[Tag](data) + if err != nil { + return result, fmt.Errorf("shape: AliasLike._unmarshalJSONTag: native ref unwrap; %w", err) } return result, nil } -func UInt8FromJSON(x []byte) (*UInt8, error) { - result := new(UInt8) +func PrimitiveLikeFromJSON(x []byte) (*PrimitiveLike, error) { + result := new(PrimitiveLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -3079,50 +2443,76 @@ func UInt8FromJSON(x []byte) (*UInt8, error) { return result, nil } -func UInt8ToJSON(x *UInt8) ([]byte, error) { +func PrimitiveLikeToJSON(x *PrimitiveLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*UInt8)(nil) - _ json.Marshaler = (*UInt8)(nil) + _ json.Unmarshaler = (*PrimitiveLike)(nil) + _ json.Marshaler = (*PrimitiveLike)(nil) ) -func (r *UInt8) MarshalJSON() ([]byte, error) { +func (r *PrimitiveLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONUInt8(*r) + return r._marshalJSONPrimitiveLike(*r) } -func (r *UInt8) _marshalJSONUInt8(x UInt8) ([]byte, error) { +func (r *PrimitiveLike) _marshalJSONPrimitiveLike(x PrimitiveLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error + var fieldKind []byte + fieldKind, err = r._marshalJSONPrimitiveKind(x.Kind) + if err != nil { + return nil, fmt.Errorf("shape: PrimitiveLike._marshalJSONPrimitiveLike: field name Kind; %w", err) + } + partial["Kind"] = fieldKind result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: UInt8._marshalJSONUInt8: struct; %w", err) + return nil, fmt.Errorf("shape: PrimitiveLike._marshalJSONPrimitiveLike: struct; %w", err) } return result, nil } -func (r *UInt8) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONUInt8(data) +func (r *PrimitiveLike) _marshalJSONPrimitiveKind(x PrimitiveKind) ([]byte, error) { + result, err := shared.JSONMarshal[PrimitiveKind](x) if err != nil { - return fmt.Errorf("shape: UInt8.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: PrimitiveLike._marshalJSONPrimitiveKind:; %w", err) + } + return result, nil +} +func (r *PrimitiveLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONPrimitiveLike(data) + if err != nil { + return fmt.Errorf("shape: PrimitiveLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *UInt8) _unmarshalJSONUInt8(data []byte) (UInt8, error) { - result := UInt8{} +func (r *PrimitiveLike) _unmarshalJSONPrimitiveLike(data []byte) (PrimitiveLike, error) { + result := PrimitiveLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: UInt8._unmarshalJSONUInt8: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: PrimitiveLike._unmarshalJSONPrimitiveLike: native struct unwrap; %w", err) + } + if fieldKind, ok := partial["Kind"]; ok { + result.Kind, err = r._unmarshalJSONPrimitiveKind(fieldKind) + if err != nil { + return result, fmt.Errorf("shape: PrimitiveLike._unmarshalJSONPrimitiveLike: field Kind; %w", err) + } + } + return result, nil +} +func (r *PrimitiveLike) _unmarshalJSONPrimitiveKind(data []byte) (PrimitiveKind, error) { + result, err := shared.JSONUnmarshal[PrimitiveKind](data) + if err != nil { + return result, fmt.Errorf("shape: PrimitiveLike._unmarshalJSONPrimitiveKind: native ref unwrap; %w", err) } return result, nil } -func UInt16FromJSON(x []byte) (*UInt16, error) { - result := new(UInt16) +func ListLikeFromJSON(x []byte) (*ListLike, error) { + result := new(ListLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -3131,102 +2521,124 @@ func UInt16FromJSON(x []byte) (*UInt16, error) { return result, nil } -func UInt16ToJSON(x *UInt16) ([]byte, error) { +func ListLikeToJSON(x *ListLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*UInt16)(nil) - _ json.Marshaler = (*UInt16)(nil) + _ json.Unmarshaler = (*ListLike)(nil) + _ json.Marshaler = (*ListLike)(nil) ) -func (r *UInt16) MarshalJSON() ([]byte, error) { +func (r *ListLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONUInt16(*r) + return r._marshalJSONListLike(*r) } -func (r *UInt16) _marshalJSONUInt16(x UInt16) ([]byte, error) { +func (r *ListLike) _marshalJSONListLike(x ListLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - result, err := json.Marshal(partial) + var fieldElement []byte + fieldElement, err = r._marshalJSONShape(x.Element) if err != nil { - return nil, fmt.Errorf("shape: UInt16._marshalJSONUInt16: struct; %w", err) + return nil, fmt.Errorf("shape: ListLike._marshalJSONListLike: field name Element; %w", err) } - return result, nil -} -func (r *UInt16) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONUInt16(data) + partial["Element"] = fieldElement + var fieldArrayLen []byte + fieldArrayLen, err = r._marshalJSONPtrint(x.ArrayLen) if err != nil { - return fmt.Errorf("shape: UInt16.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: ListLike._marshalJSONListLike: field name ArrayLen; %w", err) } - *r = result - return nil -} -func (r *UInt16) _unmarshalJSONUInt16(data []byte) (UInt16, error) { - result := UInt16{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) + if fieldArrayLen != nil { + partial["ArrayLen"] = fieldArrayLen + } + result, err := json.Marshal(partial) if err != nil { - return result, fmt.Errorf("shape: UInt16._unmarshalJSONUInt16: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: ListLike._marshalJSONListLike: struct; %w", err) } return result, nil } - -func UInt32FromJSON(x []byte) (*UInt32, error) { - result := new(UInt32) - err := result.UnmarshalJSON(x) +func (r *ListLike) _marshalJSONShape(x Shape) ([]byte, error) { + result, err := shared.JSONMarshal[Shape](x) if err != nil { - return nil, err + return nil, fmt.Errorf("shape: ListLike._marshalJSONShape:; %w", err) } - return result, nil } - -func UInt32ToJSON(x *UInt32) ([]byte, error) { - return x.MarshalJSON() -} - -var ( - _ json.Unmarshaler = (*UInt32)(nil) - _ json.Marshaler = (*UInt32)(nil) -) - -func (r *UInt32) MarshalJSON() ([]byte, error) { - if r == nil { +func (r *ListLike) _marshalJSONPtrint(x *int) ([]byte, error) { + if x == nil { return nil, nil } - return r._marshalJSONUInt32(*r) + return r._marshalJSONint(*x) } -func (r *UInt32) _marshalJSONUInt32(x UInt32) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - result, err := json.Marshal(partial) +func (r *ListLike) _marshalJSONint(x int) ([]byte, error) { + result, err := json.Marshal(x) if err != nil { - return nil, fmt.Errorf("shape: UInt32._marshalJSONUInt32: struct; %w", err) + return nil, fmt.Errorf("shape: ListLike._marshalJSONint:; %w", err) } return result, nil } -func (r *UInt32) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONUInt32(data) +func (r *ListLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONListLike(data) if err != nil { - return fmt.Errorf("shape: UInt32.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: ListLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *UInt32) _unmarshalJSONUInt32(data []byte) (UInt32, error) { - result := UInt32{} +func (r *ListLike) _unmarshalJSONListLike(data []byte) (ListLike, error) { + result := ListLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: UInt32._unmarshalJSONUInt32: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: ListLike._unmarshalJSONListLike: native struct unwrap; %w", err) + } + if fieldElement, ok := partial["Element"]; ok { + result.Element, err = r._unmarshalJSONShape(fieldElement) + if err != nil { + return result, fmt.Errorf("shape: ListLike._unmarshalJSONListLike: field Element; %w", err) + } + } + if fieldArrayLen, ok := partial["ArrayLen"]; ok { + result.ArrayLen, err = r._unmarshalJSONPtrint(fieldArrayLen) + if err != nil { + return result, fmt.Errorf("shape: ListLike._unmarshalJSONListLike: field ArrayLen; %w", err) + } + } + return result, nil +} +func (r *ListLike) _unmarshalJSONShape(data []byte) (Shape, error) { + result, err := shared.JSONUnmarshal[Shape](data) + if err != nil { + return result, fmt.Errorf("shape: ListLike._unmarshalJSONShape: native ref unwrap; %w", err) + } + return result, nil +} +func (r *ListLike) _unmarshalJSONPtrint(data []byte) (*int, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONint(data) + if err != nil { + return nil, fmt.Errorf("shape: ListLike._unmarshalJSONPtrint: pointer; %w", err) + } + return &result, nil +} +func (r *ListLike) _unmarshalJSONint(data []byte) (int, error) { + var result int + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("shape: ListLike._unmarshalJSONint: native primitive unwrap; %w", err) } return result, nil } -func UInt64FromJSON(x []byte) (*UInt64, error) { - result := new(UInt64) +func MapLikeFromJSON(x []byte) (*MapLike, error) { + result := new(MapLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -3235,50 +2647,88 @@ func UInt64FromJSON(x []byte) (*UInt64, error) { return result, nil } -func UInt64ToJSON(x *UInt64) ([]byte, error) { +func MapLikeToJSON(x *MapLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*UInt64)(nil) - _ json.Marshaler = (*UInt64)(nil) + _ json.Unmarshaler = (*MapLike)(nil) + _ json.Marshaler = (*MapLike)(nil) ) -func (r *UInt64) MarshalJSON() ([]byte, error) { +func (r *MapLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONUInt64(*r) + return r._marshalJSONMapLike(*r) } -func (r *UInt64) _marshalJSONUInt64(x UInt64) ([]byte, error) { +func (r *MapLike) _marshalJSONMapLike(x MapLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error + var fieldKey []byte + fieldKey, err = r._marshalJSONShape(x.Key) + if err != nil { + return nil, fmt.Errorf("shape: MapLike._marshalJSONMapLike: field name Key; %w", err) + } + partial["Key"] = fieldKey + var fieldVal []byte + fieldVal, err = r._marshalJSONShape(x.Val) + if err != nil { + return nil, fmt.Errorf("shape: MapLike._marshalJSONMapLike: field name Val; %w", err) + } + partial["Val"] = fieldVal result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: UInt64._marshalJSONUInt64: struct; %w", err) + return nil, fmt.Errorf("shape: MapLike._marshalJSONMapLike: struct; %w", err) } return result, nil } -func (r *UInt64) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONUInt64(data) +func (r *MapLike) _marshalJSONShape(x Shape) ([]byte, error) { + result, err := shared.JSONMarshal[Shape](x) if err != nil { - return fmt.Errorf("shape: UInt64.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: MapLike._marshalJSONShape:; %w", err) + } + return result, nil +} +func (r *MapLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONMapLike(data) + if err != nil { + return fmt.Errorf("shape: MapLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *UInt64) _unmarshalJSONUInt64(data []byte) (UInt64, error) { - result := UInt64{} +func (r *MapLike) _unmarshalJSONMapLike(data []byte) (MapLike, error) { + result := MapLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: UInt64._unmarshalJSONUInt64: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: MapLike._unmarshalJSONMapLike: native struct unwrap; %w", err) + } + if fieldKey, ok := partial["Key"]; ok { + result.Key, err = r._unmarshalJSONShape(fieldKey) + if err != nil { + return result, fmt.Errorf("shape: MapLike._unmarshalJSONMapLike: field Key; %w", err) + } + } + if fieldVal, ok := partial["Val"]; ok { + result.Val, err = r._unmarshalJSONShape(fieldVal) + if err != nil { + return result, fmt.Errorf("shape: MapLike._unmarshalJSONMapLike: field Val; %w", err) + } + } + return result, nil +} +func (r *MapLike) _unmarshalJSONShape(data []byte) (Shape, error) { + result, err := shared.JSONUnmarshal[Shape](data) + if err != nil { + return result, fmt.Errorf("shape: MapLike._unmarshalJSONShape: native ref unwrap; %w", err) } return result, nil } -func IntFromJSON(x []byte) (*Int, error) { - result := new(Int) +func StructLikeFromJSON(x []byte) (*StructLike, error) { + result := new(StructLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -3287,154 +2737,293 @@ func IntFromJSON(x []byte) (*Int, error) { return result, nil } -func IntToJSON(x *Int) ([]byte, error) { +func StructLikeToJSON(x *StructLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Int)(nil) - _ json.Marshaler = (*Int)(nil) + _ json.Unmarshaler = (*StructLike)(nil) + _ json.Marshaler = (*StructLike)(nil) ) -func (r *Int) MarshalJSON() ([]byte, error) { +func (r *StructLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONInt(*r) + return r._marshalJSONStructLike(*r) } -func (r *Int) _marshalJSONInt(x Int) ([]byte, error) { +func (r *StructLike) _marshalJSONStructLike(x StructLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name Name; %w", err) + } + partial["Name"] = fieldName + var fieldPkgName []byte + fieldPkgName, err = r._marshalJSONstring(x.PkgName) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name PkgName; %w", err) + } + partial["PkgName"] = fieldPkgName + var fieldPkgImportName []byte + fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name PkgImportName; %w", err) + } + partial["PkgImportName"] = fieldPkgImportName + var fieldTypeParams []byte + fieldTypeParams, err = r._marshalJSONSliceTypeParam(x.TypeParams) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name TypeParams; %w", err) + } + partial["TypeParams"] = fieldTypeParams + var fieldFields []byte + fieldFields, err = r._marshalJSONSlicePtrFieldLike(x.Fields) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name Fields; %w", err) + } + partial["Fields"] = fieldFields + var fieldTags []byte + fieldTags, err = r._marshalJSONmapLb_string_bLTag(x.Tags) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: field name Tags; %w", err) + } + partial["Tags"] = fieldTags result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Int._marshalJSONInt: struct; %w", err) + return nil, fmt.Errorf("shape: StructLike._marshalJSONStructLike: struct; %w", err) } return result, nil } -func (r *Int) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONInt(data) +func (r *StructLike) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) if err != nil { - return fmt.Errorf("shape: Int.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: StructLike._marshalJSONstring:; %w", err) } - *r = result - return nil + return result, nil } -func (r *Int) _unmarshalJSONInt(data []byte) (Int, error) { - result := Int{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) +func (r *StructLike) _marshalJSONSliceTypeParam(x []TypeParam) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONTypeParam(v) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONSliceTypeParam: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) if err != nil { - return result, fmt.Errorf("shape: Int._unmarshalJSONInt: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: StructLike._marshalJSONSliceTypeParam:; %w", err) } return result, nil } - -func Int8FromJSON(x []byte) (*Int8, error) { - result := new(Int8) - err := result.UnmarshalJSON(x) +func (r *StructLike) _marshalJSONTypeParam(x TypeParam) ([]byte, error) { + result, err := shared.JSONMarshal[TypeParam](x) if err != nil { - return nil, err + return nil, fmt.Errorf("shape: StructLike._marshalJSONTypeParam:; %w", err) } - return result, nil } - -func Int8ToJSON(x *Int8) ([]byte, error) { - return x.MarshalJSON() +func (r *StructLike) _marshalJSONSlicePtrFieldLike(x []*FieldLike) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONPtrFieldLike(v) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONSlicePtrFieldLike: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONSlicePtrFieldLike:; %w", err) + } + return result, nil } - -var ( - _ json.Unmarshaler = (*Int8)(nil) - _ json.Marshaler = (*Int8)(nil) -) - -func (r *Int8) MarshalJSON() ([]byte, error) { - if r == nil { +func (r *StructLike) _marshalJSONPtrFieldLike(x *FieldLike) ([]byte, error) { + if x == nil { return nil, nil } - return r._marshalJSONInt8(*r) + return r._marshalJSONFieldLike(*x) } -func (r *Int8) _marshalJSONInt8(x Int8) ([]byte, error) { +func (r *StructLike) _marshalJSONFieldLike(x FieldLike) ([]byte, error) { + result, err := shared.JSONMarshal[FieldLike](x) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONFieldLike:; %w", err) + } + return result, nil +} +func (r *StructLike) _marshalJSONmapLb_string_bLTag(x map[string]Tag) ([]byte, error) { partial := make(map[string]json.RawMessage) - var err error + for k, v := range x { + key := string(k) + value, err := r._marshalJSONTag(v) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONmapLb_string_bLTag: value; %w", err) + } + partial[string(key)] = value + } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Int8._marshalJSONInt8: struct; %w", err) + return nil, fmt.Errorf("shape: StructLike._marshalJSONmapLb_string_bLTag:; %w", err) + } + return result, nil +} +func (r *StructLike) _marshalJSONTag(x Tag) ([]byte, error) { + result, err := shared.JSONMarshal[Tag](x) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._marshalJSONTag:; %w", err) + } + return result, nil +} +func (r *StructLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONStructLike(data) + if err != nil { + return fmt.Errorf("shape: StructLike.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *StructLike) _unmarshalJSONStructLike(data []byte) (StructLike, error) { + result := StructLike{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: native struct unwrap; %w", err) + } + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field Name; %w", err) + } + } + if fieldPkgName, ok := partial["PkgName"]; ok { + result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field PkgName; %w", err) + } + } + if fieldPkgImportName, ok := partial["PkgImportName"]; ok { + result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field PkgImportName; %w", err) + } + } + if fieldTypeParams, ok := partial["TypeParams"]; ok { + result.TypeParams, err = r._unmarshalJSONSliceTypeParam(fieldTypeParams) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field TypeParams; %w", err) + } + } + if fieldFields, ok := partial["Fields"]; ok { + result.Fields, err = r._unmarshalJSONSlicePtrFieldLike(fieldFields) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field Fields; %w", err) + } + } + if fieldTags, ok := partial["Tags"]; ok { + result.Tags, err = r._unmarshalJSONmapLb_string_bLTag(fieldTags) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONStructLike: field Tags; %w", err) + } } return result, nil } -func (r *Int8) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONInt8(data) +func (r *StructLike) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) if err != nil { - return fmt.Errorf("shape: Int8.UnmarshalJSON: %w", err) + return result, fmt.Errorf("shape: StructLike._unmarshalJSONstring: native primitive unwrap; %w", err) } - *r = result - return nil + return result, nil } -func (r *Int8) _unmarshalJSONInt8(data []byte) (Int8, error) { - result := Int8{} - var partial map[string]json.RawMessage +func (r *StructLike) _unmarshalJSONSliceTypeParam(data []byte) ([]TypeParam, error) { + result := make([]TypeParam, 0) + var partial []json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Int8._unmarshalJSONInt8: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: StructLike._unmarshalJSONSliceTypeParam: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONTypeParam(v) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONSliceTypeParam: at index %d; %w", i, err) + } + result = append(result, item) } return result, nil } - -func Int16FromJSON(x []byte) (*Int16, error) { - result := new(Int16) - err := result.UnmarshalJSON(x) +func (r *StructLike) _unmarshalJSONTypeParam(data []byte) (TypeParam, error) { + result, err := shared.JSONUnmarshal[TypeParam](data) if err != nil { - return nil, err + return result, fmt.Errorf("shape: StructLike._unmarshalJSONTypeParam: native ref unwrap; %w", err) } - return result, nil } - -func Int16ToJSON(x *Int16) ([]byte, error) { - return x.MarshalJSON() +func (r *StructLike) _unmarshalJSONSlicePtrFieldLike(data []byte) ([]*FieldLike, error) { + result := make([]*FieldLike, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONSlicePtrFieldLike: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONPtrFieldLike(v) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONSlicePtrFieldLike: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil } - -var ( - _ json.Unmarshaler = (*Int16)(nil) - _ json.Marshaler = (*Int16)(nil) -) - -func (r *Int16) MarshalJSON() ([]byte, error) { - if r == nil { +func (r *StructLike) _unmarshalJSONPtrFieldLike(data []byte) (*FieldLike, error) { + if len(data) == 0 { return nil, nil } - return r._marshalJSONInt16(*r) -} -func (r *Int16) _marshalJSONInt16(x Int16) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - result, err := json.Marshal(partial) + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONFieldLike(data) if err != nil { - return nil, fmt.Errorf("shape: Int16._marshalJSONInt16: struct; %w", err) + return nil, fmt.Errorf("shape: StructLike._unmarshalJSONPtrFieldLike: pointer; %w", err) } - return result, nil + return &result, nil } -func (r *Int16) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONInt16(data) +func (r *StructLike) _unmarshalJSONFieldLike(data []byte) (FieldLike, error) { + result, err := shared.JSONUnmarshal[FieldLike](data) if err != nil { - return fmt.Errorf("shape: Int16.UnmarshalJSON: %w", err) + return result, fmt.Errorf("shape: StructLike._unmarshalJSONFieldLike: native ref unwrap; %w", err) } - *r = result - return nil + return result, nil } -func (r *Int16) _unmarshalJSONInt16(data []byte) (Int16, error) { - result := Int16{} +func (r *StructLike) _unmarshalJSONmapLb_string_bLTag(data []byte) (map[string]Tag, error) { var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Int16._unmarshalJSONInt16: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: StructLike._unmarshalJSONmapLb_string_bLTag: native map unwrap; %w", err) + } + result := make(map[string]Tag) + for k, v := range partial { + key := string(k) + value, err := r._unmarshalJSONTag(v) + if err != nil { + return nil, fmt.Errorf("shape: StructLike._unmarshalJSONmapLb_string_bLTag: value; %w", err) + } + result[key] = value + } + return result, nil +} +func (r *StructLike) _unmarshalJSONTag(data []byte) (Tag, error) { + result, err := shared.JSONUnmarshal[Tag](data) + if err != nil { + return result, fmt.Errorf("shape: StructLike._unmarshalJSONTag: native ref unwrap; %w", err) } return result, nil } -func Int32FromJSON(x []byte) (*Int32, error) { - result := new(Int32) +func UnionLikeFromJSON(x []byte) (*UnionLike, error) { + result := new(UnionLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -3443,236 +3032,247 @@ func Int32FromJSON(x []byte) (*Int32, error) { return result, nil } -func Int32ToJSON(x *Int32) ([]byte, error) { +func UnionLikeToJSON(x *UnionLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Int32)(nil) - _ json.Marshaler = (*Int32)(nil) + _ json.Unmarshaler = (*UnionLike)(nil) + _ json.Marshaler = (*UnionLike)(nil) ) -func (r *Int32) MarshalJSON() ([]byte, error) { +func (r *UnionLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONInt32(*r) + return r._marshalJSONUnionLike(*r) } -func (r *Int32) _marshalJSONInt32(x Int32) ([]byte, error) { +func (r *UnionLike) _marshalJSONUnionLike(x UnionLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - result, err := json.Marshal(partial) + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) if err != nil { - return nil, fmt.Errorf("shape: Int32._marshalJSONInt32: struct; %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name Name; %w", err) } - return result, nil -} -func (r *Int32) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONInt32(data) + partial["Name"] = fieldName + var fieldPkgName []byte + fieldPkgName, err = r._marshalJSONstring(x.PkgName) if err != nil { - return fmt.Errorf("shape: Int32.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name PkgName; %w", err) } - *r = result - return nil -} -func (r *Int32) _unmarshalJSONInt32(data []byte) (Int32, error) { - result := Int32{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) + partial["PkgName"] = fieldPkgName + var fieldPkgImportName []byte + fieldPkgImportName, err = r._marshalJSONstring(x.PkgImportName) if err != nil { - return result, fmt.Errorf("shape: Int32._unmarshalJSONInt32: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name PkgImportName; %w", err) } - return result, nil -} - -func Int64FromJSON(x []byte) (*Int64, error) { - result := new(Int64) - err := result.UnmarshalJSON(x) + partial["PkgImportName"] = fieldPkgImportName + var fieldVariant []byte + fieldVariant, err = r._marshalJSONSliceShape(x.Variant) if err != nil { - return nil, err + return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name Variant; %w", err) } - - return result, nil -} - -func Int64ToJSON(x *Int64) ([]byte, error) { - return x.MarshalJSON() -} - -var ( - _ json.Unmarshaler = (*Int64)(nil) - _ json.Marshaler = (*Int64)(nil) -) - -func (r *Int64) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil + partial["Variant"] = fieldVariant + var fieldTags []byte + fieldTags, err = r._marshalJSONmapLb_string_bLTag(x.Tags) + if err != nil { + return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: field name Tags; %w", err) } - return r._marshalJSONInt64(*r) -} -func (r *Int64) _marshalJSONInt64(x Int64) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error + partial["Tags"] = fieldTags result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Int64._marshalJSONInt64: struct; %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONUnionLike: struct; %w", err) } return result, nil } -func (r *Int64) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONInt64(data) +func (r *UnionLike) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) if err != nil { - return fmt.Errorf("shape: Int64.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONstring:; %w", err) } - *r = result - return nil + return result, nil } -func (r *Int64) _unmarshalJSONInt64(data []byte) (Int64, error) { - result := Int64{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) +func (r *UnionLike) _marshalJSONSliceShape(x []Shape) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONShape(v) + if err != nil { + return nil, fmt.Errorf("shape: UnionLike._marshalJSONSliceShape: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) if err != nil { - return result, fmt.Errorf("shape: Int64._unmarshalJSONInt64: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONSliceShape:; %w", err) } return result, nil } - -func Float32FromJSON(x []byte) (*Float32, error) { - result := new(Float32) - err := result.UnmarshalJSON(x) +func (r *UnionLike) _marshalJSONShape(x Shape) ([]byte, error) { + result, err := shared.JSONMarshal[Shape](x) if err != nil { - return nil, err + return nil, fmt.Errorf("shape: UnionLike._marshalJSONShape:; %w", err) } - return result, nil } - -func Float32ToJSON(x *Float32) ([]byte, error) { - return x.MarshalJSON() -} - -var ( - _ json.Unmarshaler = (*Float32)(nil) - _ json.Marshaler = (*Float32)(nil) -) - -func (r *Float32) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil - } - return r._marshalJSONFloat32(*r) -} -func (r *Float32) _marshalJSONFloat32(x Float32) ([]byte, error) { +func (r *UnionLike) _marshalJSONmapLb_string_bLTag(x map[string]Tag) ([]byte, error) { partial := make(map[string]json.RawMessage) - var err error + for k, v := range x { + key := string(k) + value, err := r._marshalJSONTag(v) + if err != nil { + return nil, fmt.Errorf("shape: UnionLike._marshalJSONmapLb_string_bLTag: value; %w", err) + } + partial[string(key)] = value + } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Float32._marshalJSONFloat32: struct; %w", err) + return nil, fmt.Errorf("shape: UnionLike._marshalJSONmapLb_string_bLTag:; %w", err) + } + return result, nil +} +func (r *UnionLike) _marshalJSONTag(x Tag) ([]byte, error) { + result, err := shared.JSONMarshal[Tag](x) + if err != nil { + return nil, fmt.Errorf("shape: UnionLike._marshalJSONTag:; %w", err) } return result, nil } -func (r *Float32) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONFloat32(data) +func (r *UnionLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONUnionLike(data) if err != nil { - return fmt.Errorf("shape: Float32.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: UnionLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Float32) _unmarshalJSONFloat32(data []byte) (Float32, error) { - result := Float32{} +func (r *UnionLike) _unmarshalJSONUnionLike(data []byte) (UnionLike, error) { + result := UnionLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Float32._unmarshalJSONFloat32: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: native struct unwrap; %w", err) + } + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field Name; %w", err) + } + } + if fieldPkgName, ok := partial["PkgName"]; ok { + result.PkgName, err = r._unmarshalJSONstring(fieldPkgName) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field PkgName; %w", err) + } + } + if fieldPkgImportName, ok := partial["PkgImportName"]; ok { + result.PkgImportName, err = r._unmarshalJSONstring(fieldPkgImportName) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field PkgImportName; %w", err) + } + } + if fieldVariant, ok := partial["Variant"]; ok { + result.Variant, err = r._unmarshalJSONSliceShape(fieldVariant) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field Variant; %w", err) + } + } + if fieldTags, ok := partial["Tags"]; ok { + result.Tags, err = r._unmarshalJSONmapLb_string_bLTag(fieldTags) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONUnionLike: field Tags; %w", err) + } } return result, nil } - -func Float64FromJSON(x []byte) (*Float64, error) { - result := new(Float64) - err := result.UnmarshalJSON(x) +func (r *UnionLike) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) if err != nil { - return nil, err + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONstring: native primitive unwrap; %w", err) } - return result, nil } - -func Float64ToJSON(x *Float64) ([]byte, error) { - return x.MarshalJSON() -} - -var ( - _ json.Unmarshaler = (*Float64)(nil) - _ json.Marshaler = (*Float64)(nil) -) - -func (r *Float64) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil - } - return r._marshalJSONFloat64(*r) -} -func (r *Float64) _marshalJSONFloat64(x Float64) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - result, err := json.Marshal(partial) +func (r *UnionLike) _unmarshalJSONSliceShape(data []byte) ([]Shape, error) { + result := make([]Shape, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return nil, fmt.Errorf("shape: Float64._marshalJSONFloat64: struct; %w", err) + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONSliceShape: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONShape(v) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONSliceShape: at index %d; %w", i, err) + } + result = append(result, item) } return result, nil } -func (r *Float64) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONFloat64(data) +func (r *UnionLike) _unmarshalJSONShape(data []byte) (Shape, error) { + result, err := shared.JSONUnmarshal[Shape](data) if err != nil { - return fmt.Errorf("shape: Float64.UnmarshalJSON: %w", err) + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONShape: native ref unwrap; %w", err) } - *r = result - return nil + return result, nil } -func (r *Float64) _unmarshalJSONFloat64(data []byte) (Float64, error) { - result := Float64{} +func (r *UnionLike) _unmarshalJSONmapLb_string_bLTag(data []byte) (map[string]Tag, error) { var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Float64._unmarshalJSONFloat64: native struct unwrap; %w", err) + return nil, fmt.Errorf("shape: UnionLike._unmarshalJSONmapLb_string_bLTag: native map unwrap; %w", err) + } + result := make(map[string]Tag) + for k, v := range partial { + key := string(k) + value, err := r._unmarshalJSONTag(v) + if err != nil { + return nil, fmt.Errorf("shape: UnionLike._unmarshalJSONmapLb_string_bLTag: value; %w", err) + } + result[key] = value + } + return result, nil +} +func (r *UnionLike) _unmarshalJSONTag(data []byte) (Tag, error) { + result, err := shared.JSONUnmarshal[Tag](data) + if err != nil { + return result, fmt.Errorf("shape: UnionLike._unmarshalJSONTag: native ref unwrap; %w", err) } return result, nil } -type GuardVisitor interface { - VisitEnum(v *Enum) any - VisitRequired(v *Required) any - VisitAndGuard(v *AndGuard) any +type PrimitiveKindVisitor interface { + VisitBooleanLike(v *BooleanLike) any + VisitStringLike(v *StringLike) any + VisitNumberLike(v *NumberLike) any } -type Guard interface { - AcceptGuard(g GuardVisitor) any +type PrimitiveKind interface { + AcceptPrimitiveKind(g PrimitiveKindVisitor) any } var ( - _ Guard = (*Enum)(nil) - _ Guard = (*Required)(nil) - _ Guard = (*AndGuard)(nil) + _ PrimitiveKind = (*BooleanLike)(nil) + _ PrimitiveKind = (*StringLike)(nil) + _ PrimitiveKind = (*NumberLike)(nil) ) -func (r *Enum) AcceptGuard(v GuardVisitor) any { return v.VisitEnum(r) } -func (r *Required) AcceptGuard(v GuardVisitor) any { return v.VisitRequired(r) } -func (r *AndGuard) AcceptGuard(v GuardVisitor) any { return v.VisitAndGuard(r) } +func (r *BooleanLike) AcceptPrimitiveKind(v PrimitiveKindVisitor) any { return v.VisitBooleanLike(r) } +func (r *StringLike) AcceptPrimitiveKind(v PrimitiveKindVisitor) any { return v.VisitStringLike(r) } +func (r *NumberLike) AcceptPrimitiveKind(v PrimitiveKindVisitor) any { return v.VisitNumberLike(r) } -func MatchGuardR3[T0, T1, T2 any]( - x Guard, - f1 func(x *Enum) (T0, T1, T2), - f2 func(x *Required) (T0, T1, T2), - f3 func(x *AndGuard) (T0, T1, T2), +func MatchPrimitiveKindR3[T0, T1, T2 any]( + x PrimitiveKind, + f1 func(x *BooleanLike) (T0, T1, T2), + f2 func(x *StringLike) (T0, T1, T2), + f3 func(x *NumberLike) (T0, T1, T2), ) (T0, T1, T2) { switch v := x.(type) { - case *Enum: + case *BooleanLike: return f1(v) - case *Required: + case *StringLike: return f2(v) - case *AndGuard: + case *NumberLike: return f3(v) } var result1 T0 @@ -3681,18 +3281,18 @@ func MatchGuardR3[T0, T1, T2 any]( return result1, result2, result3 } -func MatchGuardR2[T0, T1 any]( - x Guard, - f1 func(x *Enum) (T0, T1), - f2 func(x *Required) (T0, T1), - f3 func(x *AndGuard) (T0, T1), +func MatchPrimitiveKindR2[T0, T1 any]( + x PrimitiveKind, + f1 func(x *BooleanLike) (T0, T1), + f2 func(x *StringLike) (T0, T1), + f3 func(x *NumberLike) (T0, T1), ) (T0, T1) { switch v := x.(type) { - case *Enum: + case *BooleanLike: return f1(v) - case *Required: + case *StringLike: return f2(v) - case *AndGuard: + case *NumberLike: return f3(v) } var result1 T0 @@ -3700,111 +3300,54 @@ func MatchGuardR2[T0, T1 any]( return result1, result2 } -func MatchGuardR1[T0 any]( - x Guard, - f1 func(x *Enum) T0, - f2 func(x *Required) T0, - f3 func(x *AndGuard) T0, +func MatchPrimitiveKindR1[T0 any]( + x PrimitiveKind, + f1 func(x *BooleanLike) T0, + f2 func(x *StringLike) T0, + f3 func(x *NumberLike) T0, ) T0 { switch v := x.(type) { - case *Enum: + case *BooleanLike: return f1(v) - case *Required: + case *StringLike: return f2(v) - case *AndGuard: + case *NumberLike: return f3(v) } var result1 T0 return result1 } -func MatchGuardR0( - x Guard, - f1 func(x *Enum), - f2 func(x *Required), - f3 func(x *AndGuard), +func MatchPrimitiveKindR0( + x PrimitiveKind, + f1 func(x *BooleanLike), + f2 func(x *StringLike), + f3 func(x *NumberLike), ) { switch v := x.(type) { - case *Enum: + case *BooleanLike: f1(v) - case *Required: + case *StringLike: f2(v) - case *AndGuard: + case *NumberLike: f3(v) } } - -func GuardShape() Shape { - return &UnionLike{ - Name: "Guard", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Variant: []Shape{ - EnumShape(), - RequiredShape(), - AndGuardShape(), - }, - } -} - -func EnumShape() Shape { - return &StructLike{ - Name: "Enum", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "Val", - Type: &ListLike{ - Element: &PrimitiveLike{Kind: &StringLike{}}, - }, - }, - }, - } -} - -func RequiredShape() Shape { - return &StructLike{ - Name: "Required", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - } -} - -func AndGuardShape() Shape { - return &StructLike{ - Name: "AndGuard", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - Fields: []*FieldLike{ - { - Name: "L", - Type: &ListLike{ - Element: &RefName{ - Name: "Guard", - PkgName: "shape", - PkgImportName: "github.com/widmogrod/mkunion/x/shape", - }, - }, - }, - }, - } -} func init() { - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Guard", GuardFromJSON, GuardToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Enum", EnumFromJSON, EnumToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.Required", RequiredFromJSON, RequiredToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.AndGuard", AndGuardFromJSON, AndGuardToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.PrimitiveKind", PrimitiveKindFromJSON, PrimitiveKindToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.BooleanLike", BooleanLikeFromJSON, BooleanLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.StringLike", StringLikeFromJSON, StringLikeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/shape.NumberLike", NumberLikeFromJSON, NumberLikeToJSON) } -type GuardUnionJSON struct { - Type string `json:"$type,omitempty"` - Enum json.RawMessage `json:"shape.Enum,omitempty"` - Required json.RawMessage `json:"shape.Required,omitempty"` - AndGuard json.RawMessage `json:"shape.AndGuard,omitempty"` +type PrimitiveKindUnionJSON struct { + Type string `json:"$type,omitempty"` + BooleanLike json.RawMessage `json:"shape.BooleanLike,omitempty"` + StringLike json.RawMessage `json:"shape.StringLike,omitempty"` + NumberLike json.RawMessage `json:"shape.NumberLike,omitempty"` } -func GuardFromJSON(x []byte) (Guard, error) { +func PrimitiveKindFromJSON(x []byte) (PrimitiveKind, error) { if x == nil || len(x) == 0 { return nil, nil } @@ -3812,76 +3355,76 @@ func GuardFromJSON(x []byte) (Guard, error) { return nil, nil } - var data GuardUnionJSON + var data PrimitiveKindUnionJSON err := json.Unmarshal(x, &data) if err != nil { return nil, err } switch data.Type { - case "shape.Enum": - return EnumFromJSON(data.Enum) - case "shape.Required": - return RequiredFromJSON(data.Required) - case "shape.AndGuard": - return AndGuardFromJSON(data.AndGuard) + case "shape.BooleanLike": + return BooleanLikeFromJSON(data.BooleanLike) + case "shape.StringLike": + return StringLikeFromJSON(data.StringLike) + case "shape.NumberLike": + return NumberLikeFromJSON(data.NumberLike) } - if data.Enum != nil { - return EnumFromJSON(data.Enum) - } else if data.Required != nil { - return RequiredFromJSON(data.Required) - } else if data.AndGuard != nil { - return AndGuardFromJSON(data.AndGuard) + if data.BooleanLike != nil { + return BooleanLikeFromJSON(data.BooleanLike) + } else if data.StringLike != nil { + return StringLikeFromJSON(data.StringLike) + } else if data.NumberLike != nil { + return NumberLikeFromJSON(data.NumberLike) } - return nil, fmt.Errorf("shape.Guard: unknown type %s", data.Type) + return nil, fmt.Errorf("shape.PrimitiveKind: unknown type %s", data.Type) } -func GuardToJSON(x Guard) ([]byte, error) { +func PrimitiveKindToJSON(x PrimitiveKind) ([]byte, error) { if x == nil { return nil, nil } - return MatchGuardR2( + return MatchPrimitiveKindR2( x, - func(x *Enum) ([]byte, error) { - body, err := EnumToJSON(x) + func(x *BooleanLike) ([]byte, error) { + body, err := BooleanLikeToJSON(x) if err != nil { return nil, err } - return json.Marshal(GuardUnionJSON{ - Type: "shape.Enum", - Enum: body, + return json.Marshal(PrimitiveKindUnionJSON{ + Type: "shape.BooleanLike", + BooleanLike: body, }) }, - func(x *Required) ([]byte, error) { - body, err := RequiredToJSON(x) + func(x *StringLike) ([]byte, error) { + body, err := StringLikeToJSON(x) if err != nil { return nil, err } - return json.Marshal(GuardUnionJSON{ - Type: "shape.Required", - Required: body, + return json.Marshal(PrimitiveKindUnionJSON{ + Type: "shape.StringLike", + StringLike: body, }) }, - func(x *AndGuard) ([]byte, error) { - body, err := AndGuardToJSON(x) + func(x *NumberLike) ([]byte, error) { + body, err := NumberLikeToJSON(x) if err != nil { return nil, err } - return json.Marshal(GuardUnionJSON{ - Type: "shape.AndGuard", - AndGuard: body, + return json.Marshal(PrimitiveKindUnionJSON{ + Type: "shape.NumberLike", + NumberLike: body, }) }, ) } -func EnumFromJSON(x []byte) (*Enum, error) { - result := new(Enum) +func BooleanLikeFromJSON(x []byte) (*BooleanLike, error) { + result := new(BooleanLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -3890,108 +3433,50 @@ func EnumFromJSON(x []byte) (*Enum, error) { return result, nil } -func EnumToJSON(x *Enum) ([]byte, error) { +func BooleanLikeToJSON(x *BooleanLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Enum)(nil) - _ json.Marshaler = (*Enum)(nil) + _ json.Unmarshaler = (*BooleanLike)(nil) + _ json.Marshaler = (*BooleanLike)(nil) ) -func (r *Enum) MarshalJSON() ([]byte, error) { +func (r *BooleanLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONEnum(*r) + return r._marshalJSONBooleanLike(*r) } -func (r *Enum) _marshalJSONEnum(x Enum) ([]byte, error) { +func (r *BooleanLike) _marshalJSONBooleanLike(x BooleanLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldVal []byte - fieldVal, err = r._marshalJSONSlicestring(x.Val) - if err != nil { - return nil, fmt.Errorf("shape: Enum._marshalJSONEnum: field name Val; %w", err) - } - partial["Val"] = fieldVal - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("shape: Enum._marshalJSONEnum: struct; %w", err) - } - return result, nil -} -func (r *Enum) _marshalJSONSlicestring(x []string) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONstring(v) - if err != nil { - return nil, fmt.Errorf("shape: Enum._marshalJSONSlicestring: at index %d; %w", i, err) - } - partial[i] = item - } result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Enum._marshalJSONSlicestring:; %w", err) - } - return result, nil -} -func (r *Enum) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("shape: Enum._marshalJSONstring:; %w", err) + return nil, fmt.Errorf("shape: BooleanLike._marshalJSONBooleanLike: struct; %w", err) } return result, nil } -func (r *Enum) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONEnum(data) +func (r *BooleanLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONBooleanLike(data) if err != nil { - return fmt.Errorf("shape: Enum.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: BooleanLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Enum) _unmarshalJSONEnum(data []byte) (Enum, error) { - result := Enum{} +func (r *BooleanLike) _unmarshalJSONBooleanLike(data []byte) (BooleanLike, error) { + result := BooleanLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Enum._unmarshalJSONEnum: native struct unwrap; %w", err) - } - if fieldVal, ok := partial["Val"]; ok { - result.Val, err = r._unmarshalJSONSlicestring(fieldVal) - if err != nil { - return result, fmt.Errorf("shape: Enum._unmarshalJSONEnum: field Val; %w", err) - } - } - return result, nil -} -func (r *Enum) _unmarshalJSONSlicestring(data []byte) ([]string, error) { - result := make([]string, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("shape: Enum._unmarshalJSONSlicestring: native list unwrap; %w", err) - } - for i, v := range partial { - item, err := r._unmarshalJSONstring(v) - if err != nil { - return result, fmt.Errorf("shape: Enum._unmarshalJSONSlicestring: at index %d; %w", i, err) - } - result = append(result, item) - } - return result, nil -} -func (r *Enum) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("shape: Enum._unmarshalJSONstring: native primitive unwrap; %w", err) + return result, fmt.Errorf("shape: BooleanLike._unmarshalJSONBooleanLike: native struct unwrap; %w", err) } return result, nil } -func RequiredFromJSON(x []byte) (*Required, error) { - result := new(Required) +func StringLikeFromJSON(x []byte) (*StringLike, error) { + result := new(StringLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -4000,50 +3485,50 @@ func RequiredFromJSON(x []byte) (*Required, error) { return result, nil } -func RequiredToJSON(x *Required) ([]byte, error) { +func StringLikeToJSON(x *StringLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Required)(nil) - _ json.Marshaler = (*Required)(nil) + _ json.Unmarshaler = (*StringLike)(nil) + _ json.Marshaler = (*StringLike)(nil) ) -func (r *Required) MarshalJSON() ([]byte, error) { +func (r *StringLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONRequired(*r) + return r._marshalJSONStringLike(*r) } -func (r *Required) _marshalJSONRequired(x Required) ([]byte, error) { +func (r *StringLike) _marshalJSONStringLike(x StringLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: Required._marshalJSONRequired: struct; %w", err) + return nil, fmt.Errorf("shape: StringLike._marshalJSONStringLike: struct; %w", err) } return result, nil } -func (r *Required) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONRequired(data) +func (r *StringLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONStringLike(data) if err != nil { - return fmt.Errorf("shape: Required.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: StringLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Required) _unmarshalJSONRequired(data []byte) (Required, error) { - result := Required{} +func (r *StringLike) _unmarshalJSONStringLike(data []byte) (StringLike, error) { + result := StringLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: Required._unmarshalJSONRequired: native struct unwrap; %w", err) + return result, fmt.Errorf("shape: StringLike._unmarshalJSONStringLike: native struct unwrap; %w", err) } return result, nil } -func AndGuardFromJSON(x []byte) (*AndGuard, error) { - result := new(AndGuard) +func NumberLikeFromJSON(x []byte) (*NumberLike, error) { + result := new(NumberLike) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -4052,101 +3537,70 @@ func AndGuardFromJSON(x []byte) (*AndGuard, error) { return result, nil } -func AndGuardToJSON(x *AndGuard) ([]byte, error) { +func NumberLikeToJSON(x *NumberLike) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*AndGuard)(nil) - _ json.Marshaler = (*AndGuard)(nil) + _ json.Unmarshaler = (*NumberLike)(nil) + _ json.Marshaler = (*NumberLike)(nil) ) -func (r *AndGuard) MarshalJSON() ([]byte, error) { +func (r *NumberLike) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONAndGuard(*r) + return r._marshalJSONNumberLike(*r) } -func (r *AndGuard) _marshalJSONAndGuard(x AndGuard) ([]byte, error) { +func (r *NumberLike) _marshalJSONNumberLike(x NumberLike) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldL []byte - fieldL, err = r._marshalJSONSliceGuard(x.L) - if err != nil { - return nil, fmt.Errorf("shape: AndGuard._marshalJSONAndGuard: field name L; %w", err) - } - partial["L"] = fieldL - result, err := json.Marshal(partial) + var fieldKind []byte + fieldKind, err = r._marshalJSONNumberKind(x.Kind) if err != nil { - return nil, fmt.Errorf("shape: AndGuard._marshalJSONAndGuard: struct; %w", err) - } - return result, nil -} -func (r *AndGuard) _marshalJSONSliceGuard(x []Guard) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONGuard(v) - if err != nil { - return nil, fmt.Errorf("shape: AndGuard._marshalJSONSliceGuard: at index %d; %w", i, err) - } - partial[i] = item + return nil, fmt.Errorf("shape: NumberLike._marshalJSONNumberLike: field name Kind; %w", err) } + partial["Kind"] = fieldKind result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("shape: AndGuard._marshalJSONSliceGuard:; %w", err) + return nil, fmt.Errorf("shape: NumberLike._marshalJSONNumberLike: struct; %w", err) } return result, nil } -func (r *AndGuard) _marshalJSONGuard(x Guard) ([]byte, error) { - result, err := shared.JSONMarshal[Guard](x) +func (r *NumberLike) _marshalJSONNumberKind(x NumberKind) ([]byte, error) { + result, err := shared.JSONMarshal[NumberKind](x) if err != nil { - return nil, fmt.Errorf("shape: AndGuard._marshalJSONGuard:; %w", err) + return nil, fmt.Errorf("shape: NumberLike._marshalJSONNumberKind:; %w", err) } return result, nil } -func (r *AndGuard) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONAndGuard(data) +func (r *NumberLike) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONNumberLike(data) if err != nil { - return fmt.Errorf("shape: AndGuard.UnmarshalJSON: %w", err) + return fmt.Errorf("shape: NumberLike.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *AndGuard) _unmarshalJSONAndGuard(data []byte) (AndGuard, error) { - result := AndGuard{} +func (r *NumberLike) _unmarshalJSONNumberLike(data []byte) (NumberLike, error) { + result := NumberLike{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("shape: AndGuard._unmarshalJSONAndGuard: native struct unwrap; %w", err) - } - if fieldL, ok := partial["L"]; ok { - result.L, err = r._unmarshalJSONSliceGuard(fieldL) - if err != nil { - return result, fmt.Errorf("shape: AndGuard._unmarshalJSONAndGuard: field L; %w", err) - } - } - return result, nil -} -func (r *AndGuard) _unmarshalJSONSliceGuard(data []byte) ([]Guard, error) { - result := make([]Guard, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("shape: AndGuard._unmarshalJSONSliceGuard: native list unwrap; %w", err) + return result, fmt.Errorf("shape: NumberLike._unmarshalJSONNumberLike: native struct unwrap; %w", err) } - for i, v := range partial { - item, err := r._unmarshalJSONGuard(v) + if fieldKind, ok := partial["Kind"]; ok { + result.Kind, err = r._unmarshalJSONNumberKind(fieldKind) if err != nil { - return result, fmt.Errorf("shape: AndGuard._unmarshalJSONSliceGuard: at index %d; %w", i, err) + return result, fmt.Errorf("shape: NumberLike._unmarshalJSONNumberLike: field Kind; %w", err) } - result = append(result, item) } return result, nil } -func (r *AndGuard) _unmarshalJSONGuard(data []byte) (Guard, error) { - result, err := shared.JSONUnmarshal[Guard](data) +func (r *NumberLike) _unmarshalJSONNumberKind(data []byte) (NumberKind, error) { + result, err := shared.JSONUnmarshal[NumberKind](data) if err != nil { - return result, fmt.Errorf("shape: AndGuard._unmarshalJSONGuard: native ref unwrap; %w", err) + return result, fmt.Errorf("shape: NumberLike._unmarshalJSONNumberKind: native ref unwrap; %w", err) } return result, nil } diff --git a/x/shape/testasset/type_example.go b/x/shape/testasset/type_example.go index e5dce276..ea1d6e09 100644 --- a/x/shape/testasset/type_example.go +++ b/x/shape/testasset/type_example.go @@ -5,7 +5,6 @@ import ( ) //go:generate go run ../../../cmd/mkunion/main.go -//go:generate go run ../../../cmd/mkunion/main.go serde //go:tag mkunion:"Example" type ( @@ -25,8 +24,6 @@ type ( I []Example J [2]string K A - // L Example is not allowed, since Example is interface, - // and interface cannot have methods implemented as Visitor pattern requires L = List //go:tag json:"m_list,omitempty" M List @@ -35,9 +32,15 @@ type ( P ListOf2[ListOf[any], *ListOf2[int64, *time.Duration]] ) +//go:tag mkunion:"AliasExample" +type ( + A2 = A + B2 = B +) + // List is a list of elements // -//go:tag json:"list,omitempty" +//go:tag json:"list,omitempty" serde:"json" type List struct{} //go:tag serde:"json" json:"list_of,omitempty" diff --git a/x/shape/togo.go b/x/shape/togo.go index a4ab02b4..62828750 100644 --- a/x/shape/togo.go +++ b/x/shape/togo.go @@ -419,3 +419,69 @@ func joinMaps(x map[string]string, maps ...map[string]string) map[string]string } return x } + +func IsNamedShape(x Shape) bool { + return MatchShapeR1( + x, + func(x *Any) bool { + return false + }, + func(x *RefName) bool { + return true + }, + func(x *PointerLike) bool { + return IsNamedShape(x.Type) + }, + func(x *AliasLike) bool { + return true + }, + func(x *PrimitiveLike) bool { + return false + }, + func(x *ListLike) bool { + return false + }, + func(x *MapLike) bool { + return false + }, + func(x *StructLike) bool { + return true + }, + func(x *UnionLike) bool { + return true + }, + ) +} + +func Name(x Shape) string { + return MatchShapeR1( + x, + func(x *Any) string { + return "" + }, + func(x *RefName) string { + return x.Name + }, + func(x *PointerLike) string { + return Name(x.Type) + }, + func(x *AliasLike) string { + return x.Name + }, + func(x *PrimitiveLike) string { + return "" + }, + func(x *ListLike) string { + return "" + }, + func(x *MapLike) string { + return "" + }, + func(x *StructLike) string { + return x.Name + }, + func(x *UnionLike) string { + return x.Name + }, + ) +} diff --git a/x/shape/totypescript.go b/x/shape/totypescript.go index c5c52800..02062c56 100644 --- a/x/shape/totypescript.go +++ b/x/shape/totypescript.go @@ -5,6 +5,7 @@ import ( log "github.com/sirupsen/logrus" "os" "path" + "sort" "strings" ) @@ -327,14 +328,29 @@ func (r *TypeScriptRenderer) initContentsFor(pkgImportName string) *strings.Buil } func (r *TypeScriptRenderer) WriteToDir(dir string) error { - for pkgImportName, content := range r.contents { + sorted := make([]string, 0, len(r.contents)) + for pkgImportName := range r.contents { + sorted = append(sorted, pkgImportName) + } + sort.Strings(sorted) + + for _, pkgImportName := range sorted { + content := r.contents[pkgImportName] imports := r.imports[pkgImportName] if imports == nil { continue } importsContent := &strings.Builder{} - for pkg, imp := range imports.imports { + + sortedImports := make([]string, 0, len(imports.imports)) + for pkg := range imports.imports { + sortedImports = append(sortedImports, pkg) + } + sort.Strings(sortedImports) + + for _, pkg := range sortedImports { + imp := imports.imports[pkg] _, err := fmt.Fprintf(importsContent, "//eslint-disable-next-line\n") _, err = fmt.Fprintf(importsContent, "import * as %s from '%s'\n", pkg, r.normaliseImport(imp)) if err != nil { diff --git a/x/storage/predicate/predicate.go b/x/storage/predicate/predicate.go index bb0ffbf3..0ea9c7c4 100644 --- a/x/storage/predicate/predicate.go +++ b/x/storage/predicate/predicate.go @@ -5,7 +5,6 @@ import ( ) //go:generate go run ../../../cmd/mkunion/main.go -//go:generate go run ../../../cmd/mkunion/main.go serde //go:tag mkunion:"Predicate" type ( diff --git a/x/storage/predicate/predicate_serde_gen.go b/x/storage/predicate/predicate_serde_gen.go index 231b116f..81e0c0cc 100644 --- a/x/storage/predicate/predicate_serde_gen.go +++ b/x/storage/predicate/predicate_serde_gen.go @@ -5,14 +5,9 @@ import ( "encoding/json" "fmt" "github.com/widmogrod/mkunion/x/schema" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(ParamBindsShape()) -} - var ( _ json.Unmarshaler = (*ParamBinds)(nil) _ json.Marshaler = (*ParamBinds)(nil) @@ -126,27 +121,3 @@ func (r *ParamBinds) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, er } return result, nil } -func ParamBindsShape() shape.Shape { - return &shape.AliasLike{ - Name: "ParamBinds", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - Type: &shape.MapLike{ - Key: &shape.RefName{ - Name: "BindName", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - Val: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - } -} diff --git a/x/storage/predicate/predicate_union_gen.go b/x/storage/predicate/predicate_union_gen.go index 2bf58965..db21ed9a 100644 --- a/x/storage/predicate/predicate_union_gen.go +++ b/x/storage/predicate/predicate_union_gen.go @@ -5,61 +5,42 @@ import ( "encoding/json" "fmt" "github.com/widmogrod/mkunion/x/schema" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(PredicateShape()) - shape.Register(AndShape()) - shape.Register(OrShape()) - shape.Register(NotShape()) - shape.Register(CompareShape()) - shape.Register(BindableShape()) - shape.Register(BindValueShape()) - shape.Register(LiteralShape()) - shape.Register(LocatableShape()) -} - -type PredicateVisitor interface { - VisitAnd(v *And) any - VisitOr(v *Or) any - VisitNot(v *Not) any - VisitCompare(v *Compare) any +type BindableVisitor interface { + VisitBindValue(v *BindValue) any + VisitLiteral(v *Literal) any + VisitLocatable(v *Locatable) any } -type Predicate interface { - AcceptPredicate(g PredicateVisitor) any +type Bindable interface { + AcceptBindable(g BindableVisitor) any } var ( - _ Predicate = (*And)(nil) - _ Predicate = (*Or)(nil) - _ Predicate = (*Not)(nil) - _ Predicate = (*Compare)(nil) + _ Bindable = (*BindValue)(nil) + _ Bindable = (*Literal)(nil) + _ Bindable = (*Locatable)(nil) ) -func (r *And) AcceptPredicate(v PredicateVisitor) any { return v.VisitAnd(r) } -func (r *Or) AcceptPredicate(v PredicateVisitor) any { return v.VisitOr(r) } -func (r *Not) AcceptPredicate(v PredicateVisitor) any { return v.VisitNot(r) } -func (r *Compare) AcceptPredicate(v PredicateVisitor) any { return v.VisitCompare(r) } +func (r *BindValue) AcceptBindable(v BindableVisitor) any { return v.VisitBindValue(r) } +func (r *Literal) AcceptBindable(v BindableVisitor) any { return v.VisitLiteral(r) } +func (r *Locatable) AcceptBindable(v BindableVisitor) any { return v.VisitLocatable(r) } -func MatchPredicateR3[T0, T1, T2 any]( - x Predicate, - f1 func(x *And) (T0, T1, T2), - f2 func(x *Or) (T0, T1, T2), - f3 func(x *Not) (T0, T1, T2), - f4 func(x *Compare) (T0, T1, T2), +func MatchBindableR3[T0, T1, T2 any]( + x Bindable, + f1 func(x *BindValue) (T0, T1, T2), + f2 func(x *Literal) (T0, T1, T2), + f3 func(x *Locatable) (T0, T1, T2), ) (T0, T1, T2) { switch v := x.(type) { - case *And: + case *BindValue: return f1(v) - case *Or: + case *Literal: return f2(v) - case *Not: + case *Locatable: return f3(v) - case *Compare: - return f4(v) } var result1 T0 var result2 T1 @@ -67,182 +48,73 @@ func MatchPredicateR3[T0, T1, T2 any]( return result1, result2, result3 } -func MatchPredicateR2[T0, T1 any]( - x Predicate, - f1 func(x *And) (T0, T1), - f2 func(x *Or) (T0, T1), - f3 func(x *Not) (T0, T1), - f4 func(x *Compare) (T0, T1), +func MatchBindableR2[T0, T1 any]( + x Bindable, + f1 func(x *BindValue) (T0, T1), + f2 func(x *Literal) (T0, T1), + f3 func(x *Locatable) (T0, T1), ) (T0, T1) { switch v := x.(type) { - case *And: + case *BindValue: return f1(v) - case *Or: + case *Literal: return f2(v) - case *Not: + case *Locatable: return f3(v) - case *Compare: - return f4(v) } var result1 T0 var result2 T1 return result1, result2 } -func MatchPredicateR1[T0 any]( - x Predicate, - f1 func(x *And) T0, - f2 func(x *Or) T0, - f3 func(x *Not) T0, - f4 func(x *Compare) T0, +func MatchBindableR1[T0 any]( + x Bindable, + f1 func(x *BindValue) T0, + f2 func(x *Literal) T0, + f3 func(x *Locatable) T0, ) T0 { switch v := x.(type) { - case *And: + case *BindValue: return f1(v) - case *Or: + case *Literal: return f2(v) - case *Not: + case *Locatable: return f3(v) - case *Compare: - return f4(v) } var result1 T0 return result1 } -func MatchPredicateR0( - x Predicate, - f1 func(x *And), - f2 func(x *Or), - f3 func(x *Not), - f4 func(x *Compare), +func MatchBindableR0( + x Bindable, + f1 func(x *BindValue), + f2 func(x *Literal), + f3 func(x *Locatable), ) { switch v := x.(type) { - case *And: + case *BindValue: f1(v) - case *Or: + case *Literal: f2(v) - case *Not: + case *Locatable: f3(v) - case *Compare: - f4(v) - } -} - -func PredicateShape() shape.Shape { - return &shape.UnionLike{ - Name: "Predicate", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Variant: []shape.Shape{ - AndShape(), - OrShape(), - NotShape(), - CompareShape(), - }, - } -} - -func AndShape() shape.Shape { - return &shape.StructLike{ - Name: "And", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "L", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "Predicate", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - }, - }, - } -} - -func OrShape() shape.Shape { - return &shape.StructLike{ - Name: "Or", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "L", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "Predicate", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - }, - }, - } -} - -func NotShape() shape.Shape { - return &shape.StructLike{ - Name: "Not", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "P", - Type: &shape.RefName{ - Name: "Predicate", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - }, - } -} - -func CompareShape() shape.Shape { - return &shape.StructLike{ - Name: "Compare", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "Location", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Operation", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "BindValue", - Type: &shape.RefName{ - Name: "Bindable", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - }, } } func init() { - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Predicate", PredicateFromJSON, PredicateToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.And", AndFromJSON, AndToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Or", OrFromJSON, OrToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Not", NotFromJSON, NotToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Compare", CompareFromJSON, CompareToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Bindable", BindableFromJSON, BindableToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.BindValue", BindValueFromJSON, BindValueToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Literal", LiteralFromJSON, LiteralToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Locatable", LocatableFromJSON, LocatableToJSON) } -type PredicateUnionJSON struct { - Type string `json:"$type,omitempty"` - And json.RawMessage `json:"predicate.And,omitempty"` - Or json.RawMessage `json:"predicate.Or,omitempty"` - Not json.RawMessage `json:"predicate.Not,omitempty"` - Compare json.RawMessage `json:"predicate.Compare,omitempty"` +type BindableUnionJSON struct { + Type string `json:"$type,omitempty"` + BindValue json.RawMessage `json:"predicate.BindValue,omitempty"` + Literal json.RawMessage `json:"predicate.Literal,omitempty"` + Locatable json.RawMessage `json:"predicate.Locatable,omitempty"` } -func PredicateFromJSON(x []byte) (Predicate, error) { +func BindableFromJSON(x []byte) (Bindable, error) { if x == nil || len(x) == 0 { return nil, nil } @@ -250,91 +122,76 @@ func PredicateFromJSON(x []byte) (Predicate, error) { return nil, nil } - var data PredicateUnionJSON + var data BindableUnionJSON err := json.Unmarshal(x, &data) if err != nil { return nil, err } switch data.Type { - case "predicate.And": - return AndFromJSON(data.And) - case "predicate.Or": - return OrFromJSON(data.Or) - case "predicate.Not": - return NotFromJSON(data.Not) - case "predicate.Compare": - return CompareFromJSON(data.Compare) + case "predicate.BindValue": + return BindValueFromJSON(data.BindValue) + case "predicate.Literal": + return LiteralFromJSON(data.Literal) + case "predicate.Locatable": + return LocatableFromJSON(data.Locatable) } - if data.And != nil { - return AndFromJSON(data.And) - } else if data.Or != nil { - return OrFromJSON(data.Or) - } else if data.Not != nil { - return NotFromJSON(data.Not) - } else if data.Compare != nil { - return CompareFromJSON(data.Compare) + if data.BindValue != nil { + return BindValueFromJSON(data.BindValue) + } else if data.Literal != nil { + return LiteralFromJSON(data.Literal) + } else if data.Locatable != nil { + return LocatableFromJSON(data.Locatable) } - return nil, fmt.Errorf("predicate.Predicate: unknown type %s", data.Type) + return nil, fmt.Errorf("predicate.Bindable: unknown type %s", data.Type) } -func PredicateToJSON(x Predicate) ([]byte, error) { +func BindableToJSON(x Bindable) ([]byte, error) { if x == nil { return nil, nil } - return MatchPredicateR2( + return MatchBindableR2( x, - func(x *And) ([]byte, error) { - body, err := AndToJSON(x) - if err != nil { - return nil, err - } - - return json.Marshal(PredicateUnionJSON{ - Type: "predicate.And", - And: body, - }) - }, - func(x *Or) ([]byte, error) { - body, err := OrToJSON(x) + func(x *BindValue) ([]byte, error) { + body, err := BindValueToJSON(x) if err != nil { return nil, err } - return json.Marshal(PredicateUnionJSON{ - Type: "predicate.Or", - Or: body, + return json.Marshal(BindableUnionJSON{ + Type: "predicate.BindValue", + BindValue: body, }) }, - func(x *Not) ([]byte, error) { - body, err := NotToJSON(x) + func(x *Literal) ([]byte, error) { + body, err := LiteralToJSON(x) if err != nil { return nil, err } - return json.Marshal(PredicateUnionJSON{ - Type: "predicate.Not", - Not: body, + return json.Marshal(BindableUnionJSON{ + Type: "predicate.Literal", + Literal: body, }) }, - func(x *Compare) ([]byte, error) { - body, err := CompareToJSON(x) + func(x *Locatable) ([]byte, error) { + body, err := LocatableToJSON(x) if err != nil { return nil, err } - return json.Marshal(PredicateUnionJSON{ - Type: "predicate.Compare", - Compare: body, + return json.Marshal(BindableUnionJSON{ + Type: "predicate.Locatable", + Locatable: body, }) }, ) } -func AndFromJSON(x []byte) (*And, error) { - result := new(And) +func BindValueFromJSON(x []byte) (*BindValue, error) { + result := new(BindValue) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -343,107 +200,76 @@ func AndFromJSON(x []byte) (*And, error) { return result, nil } -func AndToJSON(x *And) ([]byte, error) { +func BindValueToJSON(x *BindValue) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*And)(nil) - _ json.Marshaler = (*And)(nil) + _ json.Unmarshaler = (*BindValue)(nil) + _ json.Marshaler = (*BindValue)(nil) ) -func (r *And) MarshalJSON() ([]byte, error) { +func (r *BindValue) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONAnd(*r) + return r._marshalJSONBindValue(*r) } -func (r *And) _marshalJSONAnd(x And) ([]byte, error) { +func (r *BindValue) _marshalJSONBindValue(x BindValue) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldL []byte - fieldL, err = r._marshalJSONSlicePredicate(x.L) + var fieldBindName []byte + fieldBindName, err = r._marshalJSONBindName(x.BindName) if err != nil { - return nil, fmt.Errorf("predicate: And._marshalJSONAnd: field name L; %w", err) + return nil, fmt.Errorf("predicate: BindValue._marshalJSONBindValue: field name BindName; %w", err) } - partial["L"] = fieldL + partial["BindName"] = fieldBindName result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: And._marshalJSONAnd: struct; %w", err) + return nil, fmt.Errorf("predicate: BindValue._marshalJSONBindValue: struct; %w", err) } return result, nil } -func (r *And) _marshalJSONSlicePredicate(x []Predicate) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONPredicate(v) - if err != nil { - return nil, fmt.Errorf("predicate: And._marshalJSONSlicePredicate: at index %d; %w", i, err) - } - partial[i] = item - } - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("predicate: And._marshalJSONSlicePredicate:; %w", err) - } - return result, nil -} -func (r *And) _marshalJSONPredicate(x Predicate) ([]byte, error) { - result, err := shared.JSONMarshal[Predicate](x) +func (r *BindValue) _marshalJSONBindName(x BindName) ([]byte, error) { + result, err := shared.JSONMarshal[BindName](x) if err != nil { - return nil, fmt.Errorf("predicate: And._marshalJSONPredicate:; %w", err) + return nil, fmt.Errorf("predicate: BindValue._marshalJSONBindName:; %w", err) } return result, nil } -func (r *And) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONAnd(data) +func (r *BindValue) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONBindValue(data) if err != nil { - return fmt.Errorf("predicate: And.UnmarshalJSON: %w", err) + return fmt.Errorf("predicate: BindValue.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *And) _unmarshalJSONAnd(data []byte) (And, error) { - result := And{} +func (r *BindValue) _unmarshalJSONBindValue(data []byte) (BindValue, error) { + result := BindValue{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: And._unmarshalJSONAnd: native struct unwrap; %w", err) - } - if fieldL, ok := partial["L"]; ok { - result.L, err = r._unmarshalJSONSlicePredicate(fieldL) - if err != nil { - return result, fmt.Errorf("predicate: And._unmarshalJSONAnd: field L; %w", err) - } - } - return result, nil -} -func (r *And) _unmarshalJSONSlicePredicate(data []byte) ([]Predicate, error) { - result := make([]Predicate, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("predicate: And._unmarshalJSONSlicePredicate: native list unwrap; %w", err) + return result, fmt.Errorf("predicate: BindValue._unmarshalJSONBindValue: native struct unwrap; %w", err) } - for i, v := range partial { - item, err := r._unmarshalJSONPredicate(v) + if fieldBindName, ok := partial["BindName"]; ok { + result.BindName, err = r._unmarshalJSONBindName(fieldBindName) if err != nil { - return result, fmt.Errorf("predicate: And._unmarshalJSONSlicePredicate: at index %d; %w", i, err) + return result, fmt.Errorf("predicate: BindValue._unmarshalJSONBindValue: field BindName; %w", err) } - result = append(result, item) } return result, nil } -func (r *And) _unmarshalJSONPredicate(data []byte) (Predicate, error) { - result, err := shared.JSONUnmarshal[Predicate](data) +func (r *BindValue) _unmarshalJSONBindName(data []byte) (BindName, error) { + result, err := shared.JSONUnmarshal[BindName](data) if err != nil { - return result, fmt.Errorf("predicate: And._unmarshalJSONPredicate: native ref unwrap; %w", err) + return result, fmt.Errorf("predicate: BindValue._unmarshalJSONBindName: native ref unwrap; %w", err) } return result, nil } -func OrFromJSON(x []byte) (*Or, error) { - result := new(Or) +func LiteralFromJSON(x []byte) (*Literal, error) { + result := new(Literal) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -452,107 +278,76 @@ func OrFromJSON(x []byte) (*Or, error) { return result, nil } -func OrToJSON(x *Or) ([]byte, error) { +func LiteralToJSON(x *Literal) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Or)(nil) - _ json.Marshaler = (*Or)(nil) + _ json.Unmarshaler = (*Literal)(nil) + _ json.Marshaler = (*Literal)(nil) ) -func (r *Or) MarshalJSON() ([]byte, error) { +func (r *Literal) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONOr(*r) + return r._marshalJSONLiteral(*r) } -func (r *Or) _marshalJSONOr(x Or) ([]byte, error) { +func (r *Literal) _marshalJSONLiteral(x Literal) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldL []byte - fieldL, err = r._marshalJSONSlicePredicate(x.L) - if err != nil { - return nil, fmt.Errorf("predicate: Or._marshalJSONOr: field name L; %w", err) - } - partial["L"] = fieldL - result, err := json.Marshal(partial) + var fieldValue []byte + fieldValue, err = r._marshalJSONschema_Schema(x.Value) if err != nil { - return nil, fmt.Errorf("predicate: Or._marshalJSONOr: struct; %w", err) - } - return result, nil -} -func (r *Or) _marshalJSONSlicePredicate(x []Predicate) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONPredicate(v) - if err != nil { - return nil, fmt.Errorf("predicate: Or._marshalJSONSlicePredicate: at index %d; %w", i, err) - } - partial[i] = item + return nil, fmt.Errorf("predicate: Literal._marshalJSONLiteral: field name Value; %w", err) } + partial["Value"] = fieldValue result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: Or._marshalJSONSlicePredicate:; %w", err) + return nil, fmt.Errorf("predicate: Literal._marshalJSONLiteral: struct; %w", err) } return result, nil } -func (r *Or) _marshalJSONPredicate(x Predicate) ([]byte, error) { - result, err := shared.JSONMarshal[Predicate](x) +func (r *Literal) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) if err != nil { - return nil, fmt.Errorf("predicate: Or._marshalJSONPredicate:; %w", err) + return nil, fmt.Errorf("predicate: Literal._marshalJSONschema_Schema:; %w", err) } return result, nil } -func (r *Or) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONOr(data) +func (r *Literal) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONLiteral(data) if err != nil { - return fmt.Errorf("predicate: Or.UnmarshalJSON: %w", err) + return fmt.Errorf("predicate: Literal.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Or) _unmarshalJSONOr(data []byte) (Or, error) { - result := Or{} +func (r *Literal) _unmarshalJSONLiteral(data []byte) (Literal, error) { + result := Literal{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: Or._unmarshalJSONOr: native struct unwrap; %w", err) - } - if fieldL, ok := partial["L"]; ok { - result.L, err = r._unmarshalJSONSlicePredicate(fieldL) - if err != nil { - return result, fmt.Errorf("predicate: Or._unmarshalJSONOr: field L; %w", err) - } - } - return result, nil -} -func (r *Or) _unmarshalJSONSlicePredicate(data []byte) ([]Predicate, error) { - result := make([]Predicate, 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("predicate: Or._unmarshalJSONSlicePredicate: native list unwrap; %w", err) + return result, fmt.Errorf("predicate: Literal._unmarshalJSONLiteral: native struct unwrap; %w", err) } - for i, v := range partial { - item, err := r._unmarshalJSONPredicate(v) + if fieldValue, ok := partial["Value"]; ok { + result.Value, err = r._unmarshalJSONschema_Schema(fieldValue) if err != nil { - return result, fmt.Errorf("predicate: Or._unmarshalJSONSlicePredicate: at index %d; %w", i, err) + return result, fmt.Errorf("predicate: Literal._unmarshalJSONLiteral: field Value; %w", err) } - result = append(result, item) } return result, nil } -func (r *Or) _unmarshalJSONPredicate(data []byte) (Predicate, error) { - result, err := shared.JSONUnmarshal[Predicate](data) +func (r *Literal) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) if err != nil { - return result, fmt.Errorf("predicate: Or._unmarshalJSONPredicate: native ref unwrap; %w", err) + return result, fmt.Errorf("predicate: Literal._unmarshalJSONschema_Schema: native ref unwrap; %w", err) } return result, nil } -func NotFromJSON(x []byte) (*Not, error) { - result := new(Not) +func LocatableFromJSON(x []byte) (*Locatable, error) { + result := new(Locatable) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -561,361 +356,199 @@ func NotFromJSON(x []byte) (*Not, error) { return result, nil } -func NotToJSON(x *Not) ([]byte, error) { +func LocatableToJSON(x *Locatable) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Not)(nil) - _ json.Marshaler = (*Not)(nil) + _ json.Unmarshaler = (*Locatable)(nil) + _ json.Marshaler = (*Locatable)(nil) ) -func (r *Not) MarshalJSON() ([]byte, error) { +func (r *Locatable) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONNot(*r) + return r._marshalJSONLocatable(*r) } -func (r *Not) _marshalJSONNot(x Not) ([]byte, error) { +func (r *Locatable) _marshalJSONLocatable(x Locatable) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldP []byte - fieldP, err = r._marshalJSONPredicate(x.P) + var fieldLocation []byte + fieldLocation, err = r._marshalJSONstring(x.Location) if err != nil { - return nil, fmt.Errorf("predicate: Not._marshalJSONNot: field name P; %w", err) + return nil, fmt.Errorf("predicate: Locatable._marshalJSONLocatable: field name Location; %w", err) } - partial["P"] = fieldP + partial["Location"] = fieldLocation result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: Not._marshalJSONNot: struct; %w", err) + return nil, fmt.Errorf("predicate: Locatable._marshalJSONLocatable: struct; %w", err) } return result, nil } -func (r *Not) _marshalJSONPredicate(x Predicate) ([]byte, error) { - result, err := shared.JSONMarshal[Predicate](x) +func (r *Locatable) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) if err != nil { - return nil, fmt.Errorf("predicate: Not._marshalJSONPredicate:; %w", err) + return nil, fmt.Errorf("predicate: Locatable._marshalJSONstring:; %w", err) } return result, nil } -func (r *Not) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONNot(data) +func (r *Locatable) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONLocatable(data) if err != nil { - return fmt.Errorf("predicate: Not.UnmarshalJSON: %w", err) + return fmt.Errorf("predicate: Locatable.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Not) _unmarshalJSONNot(data []byte) (Not, error) { - result := Not{} +func (r *Locatable) _unmarshalJSONLocatable(data []byte) (Locatable, error) { + result := Locatable{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: Not._unmarshalJSONNot: native struct unwrap; %w", err) + return result, fmt.Errorf("predicate: Locatable._unmarshalJSONLocatable: native struct unwrap; %w", err) } - if fieldP, ok := partial["P"]; ok { - result.P, err = r._unmarshalJSONPredicate(fieldP) + if fieldLocation, ok := partial["Location"]; ok { + result.Location, err = r._unmarshalJSONstring(fieldLocation) if err != nil { - return result, fmt.Errorf("predicate: Not._unmarshalJSONNot: field P; %w", err) + return result, fmt.Errorf("predicate: Locatable._unmarshalJSONLocatable: field Location; %w", err) } } return result, nil } -func (r *Not) _unmarshalJSONPredicate(data []byte) (Predicate, error) { - result, err := shared.JSONUnmarshal[Predicate](data) +func (r *Locatable) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) if err != nil { - return result, fmt.Errorf("predicate: Not._unmarshalJSONPredicate: native ref unwrap; %w", err) + return result, fmt.Errorf("predicate: Locatable._unmarshalJSONstring: native primitive unwrap; %w", err) } return result, nil } -func CompareFromJSON(x []byte) (*Compare, error) { - result := new(Compare) - err := result.UnmarshalJSON(x) - if err != nil { - return nil, err - } - - return result, nil +type PredicateVisitor interface { + VisitAnd(v *And) any + VisitOr(v *Or) any + VisitNot(v *Not) any + VisitCompare(v *Compare) any } -func CompareToJSON(x *Compare) ([]byte, error) { - return x.MarshalJSON() +type Predicate interface { + AcceptPredicate(g PredicateVisitor) any } var ( - _ json.Unmarshaler = (*Compare)(nil) - _ json.Marshaler = (*Compare)(nil) + _ Predicate = (*And)(nil) + _ Predicate = (*Or)(nil) + _ Predicate = (*Not)(nil) + _ Predicate = (*Compare)(nil) ) -func (r *Compare) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil +func (r *And) AcceptPredicate(v PredicateVisitor) any { return v.VisitAnd(r) } +func (r *Or) AcceptPredicate(v PredicateVisitor) any { return v.VisitOr(r) } +func (r *Not) AcceptPredicate(v PredicateVisitor) any { return v.VisitNot(r) } +func (r *Compare) AcceptPredicate(v PredicateVisitor) any { return v.VisitCompare(r) } + +func MatchPredicateR3[T0, T1, T2 any]( + x Predicate, + f1 func(x *And) (T0, T1, T2), + f2 func(x *Or) (T0, T1, T2), + f3 func(x *Not) (T0, T1, T2), + f4 func(x *Compare) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *And: + return f1(v) + case *Or: + return f2(v) + case *Not: + return f3(v) + case *Compare: + return f4(v) } - return r._marshalJSONCompare(*r) + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 } -func (r *Compare) _marshalJSONCompare(x Compare) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - var fieldLocation []byte - fieldLocation, err = r._marshalJSONstring(x.Location) - if err != nil { - return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: field name Location; %w", err) - } - partial["Location"] = fieldLocation - var fieldOperation []byte - fieldOperation, err = r._marshalJSONstring(x.Operation) - if err != nil { - return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: field name Operation; %w", err) - } - partial["Operation"] = fieldOperation - var fieldBindValue []byte - fieldBindValue, err = r._marshalJSONBindable(x.BindValue) - if err != nil { - return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: field name BindValue; %w", err) - } - partial["BindValue"] = fieldBindValue - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: struct; %w", err) - } - return result, nil -} -func (r *Compare) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("predicate: Compare._marshalJSONstring:; %w", err) - } - return result, nil -} -func (r *Compare) _marshalJSONBindable(x Bindable) ([]byte, error) { - result, err := shared.JSONMarshal[Bindable](x) - if err != nil { - return nil, fmt.Errorf("predicate: Compare._marshalJSONBindable:; %w", err) - } - return result, nil -} -func (r *Compare) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONCompare(data) - if err != nil { - return fmt.Errorf("predicate: Compare.UnmarshalJSON: %w", err) - } - *r = result - return nil -} -func (r *Compare) _unmarshalJSONCompare(data []byte) (Compare, error) { - result := Compare{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: native struct unwrap; %w", err) - } - if fieldLocation, ok := partial["Location"]; ok { - result.Location, err = r._unmarshalJSONstring(fieldLocation) - if err != nil { - return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: field Location; %w", err) - } - } - if fieldOperation, ok := partial["Operation"]; ok { - result.Operation, err = r._unmarshalJSONstring(fieldOperation) - if err != nil { - return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: field Operation; %w", err) - } - } - if fieldBindValue, ok := partial["BindValue"]; ok { - result.BindValue, err = r._unmarshalJSONBindable(fieldBindValue) - if err != nil { - return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: field BindValue; %w", err) - } - } - return result, nil -} -func (r *Compare) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("predicate: Compare._unmarshalJSONstring: native primitive unwrap; %w", err) - } - return result, nil -} -func (r *Compare) _unmarshalJSONBindable(data []byte) (Bindable, error) { - result, err := shared.JSONUnmarshal[Bindable](data) - if err != nil { - return result, fmt.Errorf("predicate: Compare._unmarshalJSONBindable: native ref unwrap; %w", err) - } - return result, nil -} - -type BindableVisitor interface { - VisitBindValue(v *BindValue) any - VisitLiteral(v *Literal) any - VisitLocatable(v *Locatable) any -} - -type Bindable interface { - AcceptBindable(g BindableVisitor) any -} - -var ( - _ Bindable = (*BindValue)(nil) - _ Bindable = (*Literal)(nil) - _ Bindable = (*Locatable)(nil) -) - -func (r *BindValue) AcceptBindable(v BindableVisitor) any { return v.VisitBindValue(r) } -func (r *Literal) AcceptBindable(v BindableVisitor) any { return v.VisitLiteral(r) } -func (r *Locatable) AcceptBindable(v BindableVisitor) any { return v.VisitLocatable(r) } -func MatchBindableR3[T0, T1, T2 any]( - x Bindable, - f1 func(x *BindValue) (T0, T1, T2), - f2 func(x *Literal) (T0, T1, T2), - f3 func(x *Locatable) (T0, T1, T2), -) (T0, T1, T2) { - switch v := x.(type) { - case *BindValue: - return f1(v) - case *Literal: - return f2(v) - case *Locatable: - return f3(v) - } - var result1 T0 - var result2 T1 - var result3 T2 - return result1, result2, result3 -} - -func MatchBindableR2[T0, T1 any]( - x Bindable, - f1 func(x *BindValue) (T0, T1), - f2 func(x *Literal) (T0, T1), - f3 func(x *Locatable) (T0, T1), +func MatchPredicateR2[T0, T1 any]( + x Predicate, + f1 func(x *And) (T0, T1), + f2 func(x *Or) (T0, T1), + f3 func(x *Not) (T0, T1), + f4 func(x *Compare) (T0, T1), ) (T0, T1) { switch v := x.(type) { - case *BindValue: + case *And: return f1(v) - case *Literal: + case *Or: return f2(v) - case *Locatable: + case *Not: return f3(v) + case *Compare: + return f4(v) } var result1 T0 var result2 T1 return result1, result2 } -func MatchBindableR1[T0 any]( - x Bindable, - f1 func(x *BindValue) T0, - f2 func(x *Literal) T0, - f3 func(x *Locatable) T0, +func MatchPredicateR1[T0 any]( + x Predicate, + f1 func(x *And) T0, + f2 func(x *Or) T0, + f3 func(x *Not) T0, + f4 func(x *Compare) T0, ) T0 { switch v := x.(type) { - case *BindValue: + case *And: return f1(v) - case *Literal: + case *Or: return f2(v) - case *Locatable: + case *Not: return f3(v) + case *Compare: + return f4(v) } var result1 T0 return result1 } -func MatchBindableR0( - x Bindable, - f1 func(x *BindValue), - f2 func(x *Literal), - f3 func(x *Locatable), +func MatchPredicateR0( + x Predicate, + f1 func(x *And), + f2 func(x *Or), + f3 func(x *Not), + f4 func(x *Compare), ) { switch v := x.(type) { - case *BindValue: + case *And: f1(v) - case *Literal: + case *Or: f2(v) - case *Locatable: + case *Not: f3(v) - } -} - -func BindableShape() shape.Shape { - return &shape.UnionLike{ - Name: "Bindable", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Variant: []shape.Shape{ - BindValueShape(), - LiteralShape(), - LocatableShape(), - }, - } -} - -func BindValueShape() shape.Shape { - return &shape.StructLike{ - Name: "BindValue", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "BindName", - Type: &shape.RefName{ - Name: "BindName", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - }, - } -} - -func LiteralShape() shape.Shape { - return &shape.StructLike{ - Name: "Literal", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "Value", - Type: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - }, - } -} - -func LocatableShape() shape.Shape { - return &shape.StructLike{ - Name: "Locatable", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "Location", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - }, + case *Compare: + f4(v) } } func init() { - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Bindable", BindableFromJSON, BindableToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.BindValue", BindValueFromJSON, BindValueToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Literal", LiteralFromJSON, LiteralToJSON) - shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Locatable", LocatableFromJSON, LocatableToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Predicate", PredicateFromJSON, PredicateToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.And", AndFromJSON, AndToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Or", OrFromJSON, OrToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Not", NotFromJSON, NotToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/predicate.Compare", CompareFromJSON, CompareToJSON) } -type BindableUnionJSON struct { - Type string `json:"$type,omitempty"` - BindValue json.RawMessage `json:"predicate.BindValue,omitempty"` - Literal json.RawMessage `json:"predicate.Literal,omitempty"` - Locatable json.RawMessage `json:"predicate.Locatable,omitempty"` +type PredicateUnionJSON struct { + Type string `json:"$type,omitempty"` + And json.RawMessage `json:"predicate.And,omitempty"` + Or json.RawMessage `json:"predicate.Or,omitempty"` + Not json.RawMessage `json:"predicate.Not,omitempty"` + Compare json.RawMessage `json:"predicate.Compare,omitempty"` } -func BindableFromJSON(x []byte) (Bindable, error) { +func PredicateFromJSON(x []byte) (Predicate, error) { if x == nil || len(x) == 0 { return nil, nil } @@ -923,76 +556,200 @@ func BindableFromJSON(x []byte) (Bindable, error) { return nil, nil } - var data BindableUnionJSON + var data PredicateUnionJSON err := json.Unmarshal(x, &data) if err != nil { return nil, err } switch data.Type { - case "predicate.BindValue": - return BindValueFromJSON(data.BindValue) - case "predicate.Literal": - return LiteralFromJSON(data.Literal) - case "predicate.Locatable": - return LocatableFromJSON(data.Locatable) + case "predicate.And": + return AndFromJSON(data.And) + case "predicate.Or": + return OrFromJSON(data.Or) + case "predicate.Not": + return NotFromJSON(data.Not) + case "predicate.Compare": + return CompareFromJSON(data.Compare) } - if data.BindValue != nil { - return BindValueFromJSON(data.BindValue) - } else if data.Literal != nil { - return LiteralFromJSON(data.Literal) - } else if data.Locatable != nil { - return LocatableFromJSON(data.Locatable) + if data.And != nil { + return AndFromJSON(data.And) + } else if data.Or != nil { + return OrFromJSON(data.Or) + } else if data.Not != nil { + return NotFromJSON(data.Not) + } else if data.Compare != nil { + return CompareFromJSON(data.Compare) } - return nil, fmt.Errorf("predicate.Bindable: unknown type %s", data.Type) + return nil, fmt.Errorf("predicate.Predicate: unknown type %s", data.Type) } -func BindableToJSON(x Bindable) ([]byte, error) { +func PredicateToJSON(x Predicate) ([]byte, error) { if x == nil { return nil, nil } - return MatchBindableR2( + return MatchPredicateR2( x, - func(x *BindValue) ([]byte, error) { - body, err := BindValueToJSON(x) + func(x *And) ([]byte, error) { + body, err := AndToJSON(x) if err != nil { return nil, err } - return json.Marshal(BindableUnionJSON{ - Type: "predicate.BindValue", - BindValue: body, + return json.Marshal(PredicateUnionJSON{ + Type: "predicate.And", + And: body, }) }, - func(x *Literal) ([]byte, error) { - body, err := LiteralToJSON(x) + func(x *Or) ([]byte, error) { + body, err := OrToJSON(x) if err != nil { return nil, err } - return json.Marshal(BindableUnionJSON{ - Type: "predicate.Literal", - Literal: body, + return json.Marshal(PredicateUnionJSON{ + Type: "predicate.Or", + Or: body, }) }, - func(x *Locatable) ([]byte, error) { - body, err := LocatableToJSON(x) + func(x *Not) ([]byte, error) { + body, err := NotToJSON(x) if err != nil { return nil, err } - return json.Marshal(BindableUnionJSON{ - Type: "predicate.Locatable", - Locatable: body, + return json.Marshal(PredicateUnionJSON{ + Type: "predicate.Not", + Not: body, + }) + }, + func(x *Compare) ([]byte, error) { + body, err := CompareToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(PredicateUnionJSON{ + Type: "predicate.Compare", + Compare: body, }) }, ) } -func BindValueFromJSON(x []byte) (*BindValue, error) { - result := new(BindValue) +func AndFromJSON(x []byte) (*And, error) { + result := new(And) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AndToJSON(x *And) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*And)(nil) + _ json.Marshaler = (*And)(nil) +) + +func (r *And) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAnd(*r) +} +func (r *And) _marshalJSONAnd(x And) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldL []byte + fieldL, err = r._marshalJSONSlicePredicate(x.L) + if err != nil { + return nil, fmt.Errorf("predicate: And._marshalJSONAnd: field name L; %w", err) + } + partial["L"] = fieldL + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("predicate: And._marshalJSONAnd: struct; %w", err) + } + return result, nil +} +func (r *And) _marshalJSONSlicePredicate(x []Predicate) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONPredicate(v) + if err != nil { + return nil, fmt.Errorf("predicate: And._marshalJSONSlicePredicate: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("predicate: And._marshalJSONSlicePredicate:; %w", err) + } + return result, nil +} +func (r *And) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) + if err != nil { + return nil, fmt.Errorf("predicate: And._marshalJSONPredicate:; %w", err) + } + return result, nil +} +func (r *And) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAnd(data) + if err != nil { + return fmt.Errorf("predicate: And.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *And) _unmarshalJSONAnd(data []byte) (And, error) { + result := And{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("predicate: And._unmarshalJSONAnd: native struct unwrap; %w", err) + } + if fieldL, ok := partial["L"]; ok { + result.L, err = r._unmarshalJSONSlicePredicate(fieldL) + if err != nil { + return result, fmt.Errorf("predicate: And._unmarshalJSONAnd: field L; %w", err) + } + } + return result, nil +} +func (r *And) _unmarshalJSONSlicePredicate(data []byte) ([]Predicate, error) { + result := make([]Predicate, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("predicate: And._unmarshalJSONSlicePredicate: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONPredicate(v) + if err != nil { + return result, fmt.Errorf("predicate: And._unmarshalJSONSlicePredicate: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *And) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) + if err != nil { + return result, fmt.Errorf("predicate: And._unmarshalJSONPredicate: native ref unwrap; %w", err) + } + return result, nil +} + +func OrFromJSON(x []byte) (*Or, error) { + result := new(Or) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1001,76 +758,107 @@ func BindValueFromJSON(x []byte) (*BindValue, error) { return result, nil } -func BindValueToJSON(x *BindValue) ([]byte, error) { +func OrToJSON(x *Or) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*BindValue)(nil) - _ json.Marshaler = (*BindValue)(nil) + _ json.Unmarshaler = (*Or)(nil) + _ json.Marshaler = (*Or)(nil) ) -func (r *BindValue) MarshalJSON() ([]byte, error) { +func (r *Or) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONBindValue(*r) + return r._marshalJSONOr(*r) } -func (r *BindValue) _marshalJSONBindValue(x BindValue) ([]byte, error) { +func (r *Or) _marshalJSONOr(x Or) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldBindName []byte - fieldBindName, err = r._marshalJSONBindName(x.BindName) + var fieldL []byte + fieldL, err = r._marshalJSONSlicePredicate(x.L) if err != nil { - return nil, fmt.Errorf("predicate: BindValue._marshalJSONBindValue: field name BindName; %w", err) + return nil, fmt.Errorf("predicate: Or._marshalJSONOr: field name L; %w", err) } - partial["BindName"] = fieldBindName + partial["L"] = fieldL result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: BindValue._marshalJSONBindValue: struct; %w", err) + return nil, fmt.Errorf("predicate: Or._marshalJSONOr: struct; %w", err) } return result, nil } -func (r *BindValue) _marshalJSONBindName(x BindName) ([]byte, error) { - result, err := shared.JSONMarshal[BindName](x) +func (r *Or) _marshalJSONSlicePredicate(x []Predicate) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONPredicate(v) + if err != nil { + return nil, fmt.Errorf("predicate: Or._marshalJSONSlicePredicate: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: BindValue._marshalJSONBindName:; %w", err) + return nil, fmt.Errorf("predicate: Or._marshalJSONSlicePredicate:; %w", err) } return result, nil } -func (r *BindValue) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONBindValue(data) +func (r *Or) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) if err != nil { - return fmt.Errorf("predicate: BindValue.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("predicate: Or._marshalJSONPredicate:; %w", err) + } + return result, nil +} +func (r *Or) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONOr(data) + if err != nil { + return fmt.Errorf("predicate: Or.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *BindValue) _unmarshalJSONBindValue(data []byte) (BindValue, error) { - result := BindValue{} +func (r *Or) _unmarshalJSONOr(data []byte) (Or, error) { + result := Or{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: BindValue._unmarshalJSONBindValue: native struct unwrap; %w", err) + return result, fmt.Errorf("predicate: Or._unmarshalJSONOr: native struct unwrap; %w", err) } - if fieldBindName, ok := partial["BindName"]; ok { - result.BindName, err = r._unmarshalJSONBindName(fieldBindName) + if fieldL, ok := partial["L"]; ok { + result.L, err = r._unmarshalJSONSlicePredicate(fieldL) if err != nil { - return result, fmt.Errorf("predicate: BindValue._unmarshalJSONBindValue: field BindName; %w", err) + return result, fmt.Errorf("predicate: Or._unmarshalJSONOr: field L; %w", err) } } return result, nil } -func (r *BindValue) _unmarshalJSONBindName(data []byte) (BindName, error) { - result, err := shared.JSONUnmarshal[BindName](data) +func (r *Or) _unmarshalJSONSlicePredicate(data []byte) ([]Predicate, error) { + result := make([]Predicate, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: BindValue._unmarshalJSONBindName: native ref unwrap; %w", err) + return result, fmt.Errorf("predicate: Or._unmarshalJSONSlicePredicate: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONPredicate(v) + if err != nil { + return result, fmt.Errorf("predicate: Or._unmarshalJSONSlicePredicate: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *Or) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) + if err != nil { + return result, fmt.Errorf("predicate: Or._unmarshalJSONPredicate: native ref unwrap; %w", err) } return result, nil } -func LiteralFromJSON(x []byte) (*Literal, error) { - result := new(Literal) +func NotFromJSON(x []byte) (*Not, error) { + result := new(Not) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1079,76 +867,76 @@ func LiteralFromJSON(x []byte) (*Literal, error) { return result, nil } -func LiteralToJSON(x *Literal) ([]byte, error) { +func NotToJSON(x *Not) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Literal)(nil) - _ json.Marshaler = (*Literal)(nil) + _ json.Unmarshaler = (*Not)(nil) + _ json.Marshaler = (*Not)(nil) ) -func (r *Literal) MarshalJSON() ([]byte, error) { +func (r *Not) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONLiteral(*r) + return r._marshalJSONNot(*r) } -func (r *Literal) _marshalJSONLiteral(x Literal) ([]byte, error) { +func (r *Not) _marshalJSONNot(x Not) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error - var fieldValue []byte - fieldValue, err = r._marshalJSONschema_Schema(x.Value) + var fieldP []byte + fieldP, err = r._marshalJSONPredicate(x.P) if err != nil { - return nil, fmt.Errorf("predicate: Literal._marshalJSONLiteral: field name Value; %w", err) + return nil, fmt.Errorf("predicate: Not._marshalJSONNot: field name P; %w", err) } - partial["Value"] = fieldValue + partial["P"] = fieldP result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: Literal._marshalJSONLiteral: struct; %w", err) + return nil, fmt.Errorf("predicate: Not._marshalJSONNot: struct; %w", err) } return result, nil } -func (r *Literal) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { - result, err := shared.JSONMarshal[schema.Schema](x) +func (r *Not) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) if err != nil { - return nil, fmt.Errorf("predicate: Literal._marshalJSONschema_Schema:; %w", err) + return nil, fmt.Errorf("predicate: Not._marshalJSONPredicate:; %w", err) } return result, nil } -func (r *Literal) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONLiteral(data) +func (r *Not) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONNot(data) if err != nil { - return fmt.Errorf("predicate: Literal.UnmarshalJSON: %w", err) + return fmt.Errorf("predicate: Not.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Literal) _unmarshalJSONLiteral(data []byte) (Literal, error) { - result := Literal{} +func (r *Not) _unmarshalJSONNot(data []byte) (Not, error) { + result := Not{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: Literal._unmarshalJSONLiteral: native struct unwrap; %w", err) + return result, fmt.Errorf("predicate: Not._unmarshalJSONNot: native struct unwrap; %w", err) } - if fieldValue, ok := partial["Value"]; ok { - result.Value, err = r._unmarshalJSONschema_Schema(fieldValue) + if fieldP, ok := partial["P"]; ok { + result.P, err = r._unmarshalJSONPredicate(fieldP) if err != nil { - return result, fmt.Errorf("predicate: Literal._unmarshalJSONLiteral: field Value; %w", err) + return result, fmt.Errorf("predicate: Not._unmarshalJSONNot: field P; %w", err) } } return result, nil } -func (r *Literal) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { - result, err := shared.JSONUnmarshal[schema.Schema](data) +func (r *Not) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) if err != nil { - return result, fmt.Errorf("predicate: Literal._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + return result, fmt.Errorf("predicate: Not._unmarshalJSONPredicate: native ref unwrap; %w", err) } return result, nil } -func LocatableFromJSON(x []byte) (*Locatable, error) { - result := new(Locatable) +func CompareFromJSON(x []byte) (*Compare, error) { + result := new(Compare) err := result.UnmarshalJSON(x) if err != nil { return nil, err @@ -1157,71 +945,109 @@ func LocatableFromJSON(x []byte) (*Locatable, error) { return result, nil } -func LocatableToJSON(x *Locatable) ([]byte, error) { +func CompareToJSON(x *Compare) ([]byte, error) { return x.MarshalJSON() } var ( - _ json.Unmarshaler = (*Locatable)(nil) - _ json.Marshaler = (*Locatable)(nil) + _ json.Unmarshaler = (*Compare)(nil) + _ json.Marshaler = (*Compare)(nil) ) -func (r *Locatable) MarshalJSON() ([]byte, error) { +func (r *Compare) MarshalJSON() ([]byte, error) { if r == nil { return nil, nil } - return r._marshalJSONLocatable(*r) + return r._marshalJSONCompare(*r) } -func (r *Locatable) _marshalJSONLocatable(x Locatable) ([]byte, error) { +func (r *Compare) _marshalJSONCompare(x Compare) ([]byte, error) { partial := make(map[string]json.RawMessage) var err error var fieldLocation []byte fieldLocation, err = r._marshalJSONstring(x.Location) if err != nil { - return nil, fmt.Errorf("predicate: Locatable._marshalJSONLocatable: field name Location; %w", err) + return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: field name Location; %w", err) } partial["Location"] = fieldLocation + var fieldOperation []byte + fieldOperation, err = r._marshalJSONstring(x.Operation) + if err != nil { + return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: field name Operation; %w", err) + } + partial["Operation"] = fieldOperation + var fieldBindValue []byte + fieldBindValue, err = r._marshalJSONBindable(x.BindValue) + if err != nil { + return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: field name BindValue; %w", err) + } + partial["BindValue"] = fieldBindValue result, err := json.Marshal(partial) if err != nil { - return nil, fmt.Errorf("predicate: Locatable._marshalJSONLocatable: struct; %w", err) + return nil, fmt.Errorf("predicate: Compare._marshalJSONCompare: struct; %w", err) } return result, nil } -func (r *Locatable) _marshalJSONstring(x string) ([]byte, error) { +func (r *Compare) _marshalJSONstring(x string) ([]byte, error) { result, err := json.Marshal(x) if err != nil { - return nil, fmt.Errorf("predicate: Locatable._marshalJSONstring:; %w", err) + return nil, fmt.Errorf("predicate: Compare._marshalJSONstring:; %w", err) } return result, nil } -func (r *Locatable) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONLocatable(data) +func (r *Compare) _marshalJSONBindable(x Bindable) ([]byte, error) { + result, err := shared.JSONMarshal[Bindable](x) if err != nil { - return fmt.Errorf("predicate: Locatable.UnmarshalJSON: %w", err) + return nil, fmt.Errorf("predicate: Compare._marshalJSONBindable:; %w", err) + } + return result, nil +} +func (r *Compare) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONCompare(data) + if err != nil { + return fmt.Errorf("predicate: Compare.UnmarshalJSON: %w", err) } *r = result return nil } -func (r *Locatable) _unmarshalJSONLocatable(data []byte) (Locatable, error) { - result := Locatable{} +func (r *Compare) _unmarshalJSONCompare(data []byte) (Compare, error) { + result := Compare{} var partial map[string]json.RawMessage err := json.Unmarshal(data, &partial) if err != nil { - return result, fmt.Errorf("predicate: Locatable._unmarshalJSONLocatable: native struct unwrap; %w", err) + return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: native struct unwrap; %w", err) } if fieldLocation, ok := partial["Location"]; ok { result.Location, err = r._unmarshalJSONstring(fieldLocation) if err != nil { - return result, fmt.Errorf("predicate: Locatable._unmarshalJSONLocatable: field Location; %w", err) + return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: field Location; %w", err) + } + } + if fieldOperation, ok := partial["Operation"]; ok { + result.Operation, err = r._unmarshalJSONstring(fieldOperation) + if err != nil { + return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: field Operation; %w", err) + } + } + if fieldBindValue, ok := partial["BindValue"]; ok { + result.BindValue, err = r._unmarshalJSONBindable(fieldBindValue) + if err != nil { + return result, fmt.Errorf("predicate: Compare._unmarshalJSONCompare: field BindValue; %w", err) } } return result, nil } -func (r *Locatable) _unmarshalJSONstring(data []byte) (string, error) { +func (r *Compare) _unmarshalJSONstring(data []byte) (string, error) { var result string err := json.Unmarshal(data, &result) if err != nil { - return result, fmt.Errorf("predicate: Locatable._unmarshalJSONstring: native primitive unwrap; %w", err) + return result, fmt.Errorf("predicate: Compare._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Compare) _unmarshalJSONBindable(data []byte) (Bindable, error) { + result, err := shared.JSONUnmarshal[Bindable](data) + if err != nil { + return result, fmt.Errorf("predicate: Compare._unmarshalJSONBindable: native ref unwrap; %w", err) } return result, nil } diff --git a/x/storage/predicate/testutil/data.go b/x/storage/predicate/testutil/data.go index ed315ba9..be57c052 100644 --- a/x/storage/predicate/testutil/data.go +++ b/x/storage/predicate/testutil/data.go @@ -2,7 +2,7 @@ package testutil import "github.com/widmogrod/mkunion/x/schema" -//go:generate go run ../../../../cmd/mkunion/main.go serde +//go:generate go run ../../../../cmd/mkunion/main.go //go:tag serde:"json" type SampleStruct struct { @@ -13,7 +13,7 @@ type SampleStruct struct { Visible bool } -//go:generate go run ../../../../cmd/mkunion/main.go -name=Treeish +//go:tag mkunion:"Treeish" type ( Branch struct { Name string diff --git a/x/storage/predicate/where.go b/x/storage/predicate/where.go index 83a78993..e5516f46 100644 --- a/x/storage/predicate/where.go +++ b/x/storage/predicate/where.go @@ -7,7 +7,7 @@ import ( "strings" ) -//go:generate go run ../../../cmd/mkunion/main.go serde +//go:generate go run ../../../cmd/mkunion/main.go //go:tag serde:"json" type WherePredicates struct { diff --git a/x/storage/predicate/where_serde_gen.go b/x/storage/predicate/where_serde_gen.go index 73e1994c..982c0108 100644 --- a/x/storage/predicate/where_serde_gen.go +++ b/x/storage/predicate/where_serde_gen.go @@ -4,14 +4,9 @@ package predicate import ( "encoding/json" "fmt" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(WherePredicatesShape()) -} - var ( _ json.Unmarshaler = (*WherePredicates)(nil) _ json.Marshaler = (*WherePredicates)(nil) @@ -101,33 +96,3 @@ func (r *WherePredicates) _unmarshalJSONParamBinds(data []byte) (ParamBinds, err } return result, nil } -func WherePredicatesShape() shape.Shape { - return &shape.StructLike{ - Name: "WherePredicates", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - Fields: []*shape.FieldLike{ - { - Name: "Predicate", - Type: &shape.RefName{ - Name: "Predicate", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - { - Name: "Params", - Type: &shape.RefName{ - Name: "ParamBinds", - PkgName: "predicate", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} diff --git a/x/storage/schemaless/opensearch.go b/x/storage/schemaless/opensearch.go index 33279a86..56021707 100644 --- a/x/storage/schemaless/opensearch.go +++ b/x/storage/schemaless/opensearch.go @@ -14,7 +14,7 @@ import ( "strings" ) -//go:generate go run ../../../cmd/mkunion/main.go serde +//go:generate go run ../../../cmd/mkunion/main.go func NewOpenSearchRepository[A any](client *opensearch.Client, index string) *OpenSearchRepository[A] { return &OpenSearchRepository[A]{ diff --git a/x/storage/schemaless/opensearch_serde_gen.go b/x/storage/schemaless/opensearch_serde_gen.go index d09c9ed7..1faee751 100644 --- a/x/storage/schemaless/opensearch_serde_gen.go +++ b/x/storage/schemaless/opensearch_serde_gen.go @@ -4,16 +4,9 @@ package schemaless import ( "encoding/json" "fmt" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(OpenSearchSearchResultShape()) - shape.Register(OpenSearchSearchResultHitsShape()) - shape.Register(OpenSearchSearchResultHitShape()) -} - var ( _ json.Unmarshaler = (*OpenSearchSearchResult[any])(nil) _ json.Marshaler = (*OpenSearchSearchResult[any])(nil) @@ -77,183 +70,6 @@ func (r *OpenSearchSearchResult[A]) _unmarshalJSONOpenSearchSearchResultHitsLb_A } return result, nil } -func OpenSearchSearchResultShape() shape.Shape { - return &shape.StructLike{ - Name: "OpenSearchSearchResult", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - TypeParams: []shape.TypeParam{ - shape.TypeParam{ - Name: "A", - Type: &shape.Any{}, - }, - }, - Fields: []*shape.FieldLike{ - { - Name: "Hits", - Type: &shape.RefName{ - Name: "OpenSearchSearchResultHits", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - Indexed: []shape.Shape{ - &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - }, - }, - Tags: map[string]shape.Tag{ - "json": { - Value: "hits", - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} - -var ( - _ json.Unmarshaler = (*OpenSearchSearchResultHits[any])(nil) - _ json.Marshaler = (*OpenSearchSearchResultHits[any])(nil) -) - -func (r *OpenSearchSearchResultHits[A]) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil - } - return r._marshalJSONOpenSearchSearchResultHitsLb_A_bL(*r) -} -func (r *OpenSearchSearchResultHits[A]) _marshalJSONOpenSearchSearchResultHitsLb_A_bL(x OpenSearchSearchResultHits[A]) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - var fieldHits []byte - fieldHits, err = r._marshalJSONSliceOpenSearchSearchResultHitLb_A_bL(x.Hits) - if err != nil { - return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONOpenSearchSearchResultHitsLb_A_bL: field name Hits; %w", err) - } - partial["hits"] = fieldHits - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONOpenSearchSearchResultHitsLb_A_bL: struct; %w", err) - } - return result, nil -} -func (r *OpenSearchSearchResultHits[A]) _marshalJSONSliceOpenSearchSearchResultHitLb_A_bL(x []OpenSearchSearchResultHit[A]) ([]byte, error) { - partial := make([]json.RawMessage, len(x)) - for i, v := range x { - item, err := r._marshalJSONOpenSearchSearchResultHitLb_A_bL(v) - if err != nil { - return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONSliceOpenSearchSearchResultHitLb_A_bL: at index %d; %w", i, err) - } - partial[i] = item - } - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONSliceOpenSearchSearchResultHitLb_A_bL:; %w", err) - } - return result, nil -} -func (r *OpenSearchSearchResultHits[A]) _marshalJSONOpenSearchSearchResultHitLb_A_bL(x OpenSearchSearchResultHit[A]) ([]byte, error) { - result, err := shared.JSONMarshal[OpenSearchSearchResultHit[A]](x) - if err != nil { - return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONOpenSearchSearchResultHitLb_A_bL:; %w", err) - } - return result, nil -} -func (r *OpenSearchSearchResultHits[A]) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONOpenSearchSearchResultHitsLb_A_bL(data) - if err != nil { - return fmt.Errorf("schemaless: OpenSearchSearchResultHits[A].UnmarshalJSON: %w", err) - } - *r = result - return nil -} -func (r *OpenSearchSearchResultHits[A]) _unmarshalJSONOpenSearchSearchResultHitsLb_A_bL(data []byte) (OpenSearchSearchResultHits[A], error) { - result := OpenSearchSearchResultHits[A]{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONOpenSearchSearchResultHitsLb_A_bL: native struct unwrap; %w", err) - } - if fieldHits, ok := partial["hits"]; ok { - result.Hits, err = r._unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL(fieldHits) - if err != nil { - return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONOpenSearchSearchResultHitsLb_A_bL: field Hits; %w", err) - } - } - return result, nil -} -func (r *OpenSearchSearchResultHits[A]) _unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL(data []byte) ([]OpenSearchSearchResultHit[A], error) { - result := make([]OpenSearchSearchResultHit[A], 0) - var partial []json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL: native list unwrap; %w", err) - } - for i, v := range partial { - item, err := r._unmarshalJSONOpenSearchSearchResultHitLb_A_bL(v) - if err != nil { - return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL: at index %d; %w", i, err) - } - result = append(result, item) - } - return result, nil -} -func (r *OpenSearchSearchResultHits[A]) _unmarshalJSONOpenSearchSearchResultHitLb_A_bL(data []byte) (OpenSearchSearchResultHit[A], error) { - result, err := shared.JSONUnmarshal[OpenSearchSearchResultHit[A]](data) - if err != nil { - return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONOpenSearchSearchResultHitLb_A_bL: native ref unwrap; %w", err) - } - return result, nil -} -func OpenSearchSearchResultHitsShape() shape.Shape { - return &shape.StructLike{ - Name: "OpenSearchSearchResultHits", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - TypeParams: []shape.TypeParam{ - shape.TypeParam{ - Name: "A", - Type: &shape.Any{}, - }, - }, - Fields: []*shape.FieldLike{ - { - Name: "Hits", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "OpenSearchSearchResultHit", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - Indexed: []shape.Shape{ - &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "json": { - Value: "hits", - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} var ( _ json.Unmarshaler = (*OpenSearchSearchResultHit[any])(nil) @@ -376,47 +192,98 @@ func (r *OpenSearchSearchResultHit[A]) _unmarshalJSONstring(data []byte) (string } return result, nil } -func OpenSearchSearchResultHitShape() shape.Shape { - return &shape.StructLike{ - Name: "OpenSearchSearchResultHit", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - TypeParams: []shape.TypeParam{ - shape.TypeParam{ - Name: "A", - Type: &shape.Any{}, - }, - }, - Fields: []*shape.FieldLike{ - { - Name: "Item", - Type: &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - Tags: map[string]shape.Tag{ - "json": { - Value: "_source", - }, - }, - }, - { - Name: "Sort", - Type: &shape.ListLike{ - Element: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - Tags: map[string]shape.Tag{ - "json": { - Value: "sort", - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, + +var ( + _ json.Unmarshaler = (*OpenSearchSearchResultHits[any])(nil) + _ json.Marshaler = (*OpenSearchSearchResultHits[any])(nil) +) + +func (r *OpenSearchSearchResultHits[A]) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } + return r._marshalJSONOpenSearchSearchResultHitsLb_A_bL(*r) +} +func (r *OpenSearchSearchResultHits[A]) _marshalJSONOpenSearchSearchResultHitsLb_A_bL(x OpenSearchSearchResultHits[A]) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldHits []byte + fieldHits, err = r._marshalJSONSliceOpenSearchSearchResultHitLb_A_bL(x.Hits) + if err != nil { + return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONOpenSearchSearchResultHitsLb_A_bL: field name Hits; %w", err) + } + partial["hits"] = fieldHits + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONOpenSearchSearchResultHitsLb_A_bL: struct; %w", err) + } + return result, nil +} +func (r *OpenSearchSearchResultHits[A]) _marshalJSONSliceOpenSearchSearchResultHitLb_A_bL(x []OpenSearchSearchResultHit[A]) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONOpenSearchSearchResultHitLb_A_bL(v) + if err != nil { + return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONSliceOpenSearchSearchResultHitLb_A_bL: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONSliceOpenSearchSearchResultHitLb_A_bL:; %w", err) + } + return result, nil +} +func (r *OpenSearchSearchResultHits[A]) _marshalJSONOpenSearchSearchResultHitLb_A_bL(x OpenSearchSearchResultHit[A]) ([]byte, error) { + result, err := shared.JSONMarshal[OpenSearchSearchResultHit[A]](x) + if err != nil { + return nil, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._marshalJSONOpenSearchSearchResultHitLb_A_bL:; %w", err) + } + return result, nil +} +func (r *OpenSearchSearchResultHits[A]) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONOpenSearchSearchResultHitsLb_A_bL(data) + if err != nil { + return fmt.Errorf("schemaless: OpenSearchSearchResultHits[A].UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *OpenSearchSearchResultHits[A]) _unmarshalJSONOpenSearchSearchResultHitsLb_A_bL(data []byte) (OpenSearchSearchResultHits[A], error) { + result := OpenSearchSearchResultHits[A]{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONOpenSearchSearchResultHitsLb_A_bL: native struct unwrap; %w", err) + } + if fieldHits, ok := partial["hits"]; ok { + result.Hits, err = r._unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL(fieldHits) + if err != nil { + return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONOpenSearchSearchResultHitsLb_A_bL: field Hits; %w", err) + } + } + return result, nil +} +func (r *OpenSearchSearchResultHits[A]) _unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL(data []byte) ([]OpenSearchSearchResultHit[A], error) { + result := make([]OpenSearchSearchResultHit[A], 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONOpenSearchSearchResultHitLb_A_bL(v) + if err != nil { + return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONSliceOpenSearchSearchResultHitLb_A_bL: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *OpenSearchSearchResultHits[A]) _unmarshalJSONOpenSearchSearchResultHitLb_A_bL(data []byte) (OpenSearchSearchResultHit[A], error) { + result, err := shared.JSONUnmarshal[OpenSearchSearchResultHit[A]](data) + if err != nil { + return result, fmt.Errorf("schemaless: OpenSearchSearchResultHits[A]._unmarshalJSONOpenSearchSearchResultHitLb_A_bL: native ref unwrap; %w", err) + } + return result, nil } diff --git a/x/storage/schemaless/opensearch_shape_gen.go b/x/storage/schemaless/opensearch_shape_gen.go new file mode 100644 index 00000000..782c9424 --- /dev/null +++ b/x/storage/schemaless/opensearch_shape_gen.go @@ -0,0 +1,160 @@ +// Code generated by mkunion. DO NOT EDIT. +package schemaless + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(OpenSearchRepositoryShape()) + shape.Register(OpenSearchSearchResultHitShape()) + shape.Register(OpenSearchSearchResultHitsShape()) + shape.Register(OpenSearchSearchResultShape()) +} + +//shape:shape +func OpenSearchRepositoryShape() shape.Shape { + return &shape.StructLike{ + Name: "OpenSearchRepository", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + } +} + +//shape:shape +func OpenSearchSearchResultShape() shape.Shape { + return &shape.StructLike{ + Name: "OpenSearchSearchResult", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "Hits", + Type: &shape.RefName{ + Name: "OpenSearchSearchResultHits", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Indexed: []shape.Shape{ + &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + }, + }, + Tags: map[string]shape.Tag{ + "json": { + Value: "hits", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func OpenSearchSearchResultHitsShape() shape.Shape { + return &shape.StructLike{ + Name: "OpenSearchSearchResultHits", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "Hits", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "OpenSearchSearchResultHit", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Indexed: []shape.Shape{ + &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "json": { + Value: "hits", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func OpenSearchSearchResultHitShape() shape.Shape { + return &shape.StructLike{ + Name: "OpenSearchSearchResultHit", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "Item", + Type: &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + Tags: map[string]shape.Tag{ + "json": { + Value: "_source", + }, + }, + }, + { + Name: "Sort", + Type: &shape.ListLike{ + Element: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + Tags: map[string]shape.Tag{ + "json": { + Value: "sort", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} diff --git a/x/storage/schemaless/projection/dag_builder.go b/x/storage/schemaless/projection/dag_builder.go new file mode 100644 index 00000000..15249bc3 --- /dev/null +++ b/x/storage/schemaless/projection/dag_builder.go @@ -0,0 +1,317 @@ +package projection + +import ( + "container/list" + "crypto/md5" + "fmt" + log "github.com/sirupsen/logrus" + "strings" +) + +var _ Builder = &DAGBuilder{} + +func NewDAGBuilder() *DAGBuilder { + return &DAGBuilder{ + nodesFromTo: make(map[Node]*list.List), + nodesToFrom: make(map[Node]*list.List), + dag: nil, + ctx: &DefaultContext{ + name: "root", + }, + } +} + +type DAGBuilder struct { + nodesFromTo map[Node]*list.List + nodesToFrom map[Node]*list.List + dag Node + ctx *DefaultContext +} + +func (d *DAGBuilder) nextNumber() int { + return len(d.nodesFromTo) +} + +func (d *DAGBuilder) addNode(node Node) { + // check if node name is already in use, yes - fail + for n := range d.nodesFromTo { + if n == nil || node == nil { + panic("node is nil") + } + + if GetCtx(n).Name() == GetCtx(node).Name() { + panic(fmt.Sprintf("node name %s is already in use", GetCtx(node).Name())) + } + } + + if _, ok := d.nodesFromTo[node]; !ok { + d.nodesFromTo[node] = list.New() + } + if _, ok := d.nodesToFrom[node]; !ok { + d.nodesToFrom[node] = list.New() + } +} + +func (d *DAGBuilder) addDependency(from, to Node) { + if _, ok := d.nodesFromTo[from]; !ok { + d.addNode(from) + } + if _, ok := d.nodesFromTo[to]; !ok { + d.addNode(to) + } + + d.nodesFromTo[from].PushBack(to) + d.nodesToFrom[to].PushBack(from) +} + +// DoLoad loads data from a source. This node is a root of the DAG. DAG can have many DoLoad nodesFromTo. +func (d *DAGBuilder) Load(f Handler, opts ...ContextOptionFunc) Builder { + ctx := d.ctx.Scope(fmt.Sprintf("DoLoad%d", d.nextNumber())) + for _, opt := range opts { + opt(ctx) + } + + if d.dag != nil { + panic(fmt.Errorf("load must be the first node in the DAG,"+ + "but it's being connected to %s node", GetCtx(d.dag).Name())) + } + + node := &DoLoad{ + Ctx: ctx, + OnLoad: f, + } + + d.addNode(node) + + return &DAGBuilder{ + nodesFromTo: d.nodesFromTo, + nodesToFrom: d.nodesToFrom, + dag: node, + ctx: ctx, + } +} + +func (d *DAGBuilder) Window(opts ...ContextOptionFunc) Builder { + ctx := d.ctx.Scope(fmt.Sprintf("Window%d", d.nextNumber())) + for _, opt := range opts { + opt(ctx) + } + + node := &DoWindow{ + Ctx: ctx, + Input: d.dag, + } + + d.addDependency(d.dag, node) + + return &DAGBuilder{ + nodesFromTo: d.nodesFromTo, + nodesToFrom: d.nodesToFrom, + dag: node, + ctx: ctx, + } +} + +func (d *DAGBuilder) Map(f Handler, opts ...ContextOptionFunc) Builder { + ctx := d.ctx.Scope(fmt.Sprintf("DoWindow%d", d.nextNumber())) + for _, opt := range opts { + opt(ctx) + } + + node := &DoMap{ + Ctx: ctx, + OnMap: f, + Input: d.dag, + } + + d.addDependency(d.dag, node) + + return &DAGBuilder{ + nodesFromTo: d.nodesFromTo, + nodesToFrom: d.nodesToFrom, + dag: node, + ctx: ctx, + } +} + +func (d *DAGBuilder) Join(a, b Builder, opts ...ContextOptionFunc) Builder { + ctx := d.ctx.Scope(fmt.Sprintf("DoJoin%d", d.nextNumber())) + for _, opt := range opts { + opt(ctx) + } + + node := &DoJoin{ + Ctx: ctx, + Input: []Node{ + a.(*DAGBuilder).dag, + b.(*DAGBuilder).dag, + }, + } + + d.addDependency(a.(*DAGBuilder).dag, node) + d.addDependency(b.(*DAGBuilder).dag, node) + + return &DAGBuilder{ + nodesFromTo: d.nodesFromTo, + nodesToFrom: d.nodesToFrom, + dag: node, + ctx: ctx, + } +} +func (d *DAGBuilder) Build() []Node { + result := ReverseSort(Sort(d)) + log.Debugf("Build graph:\n%s\n", ToMermaidGraphWithOrder(d, result)) + + return result +} + +func (d *DAGBuilder) GetByName(name string) (*DAGBuilder, error) { + //TODO fix me! + + for node := range d.nodesFromTo { + if node == nil { + //continue + panic("node is nil") + } + + if GetCtx(node).Name() == name { + return &DAGBuilder{ + nodesFromTo: d.nodesFromTo, + dag: node, + ctx: GetCtx(node), + }, nil + } + } + return nil, ErrNotFound +} + +func HashNode(n Node) string { + return fmt.Sprintf("%x", md5.Sum([]byte(GetCtx(n).Name()))) +} + +func ToMermaidGraph(dag *DAGBuilder) string { + return ToMermaidGraphWithOrder(dag, dag.Build()) +} + +func ToMermaidGraphWithOrder(dag *DAGBuilder, order []Node) string { + var sb strings.Builder + sb.WriteString("graph TD\n") + for _, from := range order { + sb.WriteString(fmt.Sprintf("\t"+`%s["%s: %s"]`+"\n", + HashNode(from), + NodeToString(from), + GetCtx(from).Name())) + } + + for _, from := range order { + tos := dag.nodesFromTo[from] + for to := tos.Front(); to != nil; to = to.Next() { + sb.WriteString(fmt.Sprintf("\t%s --> %s\n", + HashNode(from), + HashNode(to.Value.(Node)))) + } + } + return sb.String() +} + +// Sort sorts nodesFromTo in topological order +// https://en.wikipedia.org/wiki/Topological_sorting +// using Kahn's algorithm +func Sort(dag *DAGBuilder) []Node { + // copy nodesFromTo + nodesFromTo := make(map[Node]*list.List, len(dag.nodesFromTo)) + for node, froms := range dag.nodesFromTo { + nodesFromTo[node] = list.New() + for e := froms.Front(); e != nil; e = e.Next() { + nodesFromTo[node].PushBack(e.Value) + } + } + + // copy nodesToFrom + nodesToFrom := make(map[Node]*list.List, len(dag.nodesToFrom)) + for node, tos := range dag.nodesToFrom { + nodesToFrom[node] = list.New() + for e := tos.Front(); e != nil; e = e.Next() { + nodesToFrom[node].PushBack(e.Value) + } + } + + // L <- Empty list that will contain the sorted elements + L := make([]Node, 0, len(nodesFromTo)) + // S <- Set of all nodesFromTo with no incoming edges + // in our case, those should be only DoLoad nodes + S := make([]Node, 0, len(nodesFromTo)) + Sm := make(map[Node]struct{}, len(nodesFromTo)) + for node, froms := range nodesToFrom { + if froms.Len() == 0 { + // act like a set + if _, ok := Sm[node]; !ok { + S = append(S, node) + Sm[node] = struct{}{} + } + } + } + + // while S is non-empty do + for len(S) > 0 { + // remove a node n from S + n := S[0] + S = S[1:] + delete(Sm, n) + + // add n to tail of L + L = append(L, n) + + // termination nodes, may not have any outgoing edges + if nodesFromTo[n] == nil { + continue + } + + // for each node m with an edge e from n to m do + for mEl := nodesFromTo[n].Front(); mEl != nil; { + m := mEl.Value.(Node) + // remove edge e from the graph + mCopy := mEl + mEl = mEl.Next() + nodesFromTo[n].Remove(mCopy) + + // remove edge e from the graph + for nEl := nodesToFrom[m].Front(); nEl != nil; nEl = nEl.Next() { + if nEl.Value.(Node) == n { + nodesToFrom[m].Remove(nEl) + break + } + } + + // if m has no other incoming edges then insert m into S + if nodesToFrom[m].Len() == 0 { + // act like a set + if _, ok := Sm[m]; !ok { + S = append(S, m) + Sm[m] = struct{}{} + } + } + } + } + // if graph has edges then + for node, tos := range nodesFromTo { + // return error (graph has at least one cycle) + if tos.Len() > 0 { + //for to := tos.Front(); to != nil; to = to.Next() { + // log.Debugf("node %s has edge to %s \n", GetCtx(node).Name(), GetCtx(to.Value.(Node)).Name()) + //} + panic(fmt.Errorf("graph has at least one cycle; node %s has %d edges \n", GetCtx(node).Name(), tos.Len())) + } + } + + // return L (a topologically sorted order) + return L +} + +func ReverseSort(nodes []Node) []Node { + reversed := make([]Node, len(nodes)) + for i, node := range nodes { + reversed[len(nodes)-1-i] = node + } + return reversed +} diff --git a/x/storage/schemaless/projection/dag_builder_test.go b/x/storage/schemaless/projection/dag_builder_test.go new file mode 100644 index 00000000..e3e0972f --- /dev/null +++ b/x/storage/schemaless/projection/dag_builder_test.go @@ -0,0 +1,112 @@ +package projection + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "math" + "testing" + "time" +) + +func TestDabBuilderTest(t *testing.T) { + dag := NewDAGBuilder() + found, err := dag.GetByName("a") + assert.ErrorIs(t, err, ErrNotFound) + assert.Nil(t, found) + + //found, err = dag.GetByName("root") + //assert.NoError(t, err) + //assert.Equal(t, dag, found) + + log := &LogHandler{} + //m := &LogHandler{} + + /* + mermaid + graph TD + a[DoLoad] + b[Window] + c[DoLoad] + d[Window] + e[DoJoin] + f[Window] + a --> b + c --> d + b --> e + d --> e + e --> f + */ + mapped1 := dag. + Load(log, WithName("a")). + Window(WithName("b")) + + mapped2 := dag. + Load(log, WithName("c")). + Window(WithName("d")) + + dag. + Join(mapped1, mapped2, WithName("e")). + Window(WithName("f")) + + found, err = dag.GetByName("a") + assert.NoError(t, err) + assert.Equal(t, log, found.dag.(*DoLoad).OnLoad) + + found, err = dag.GetByName("b") + assert.NoError(t, err) + //assert.Equal(t, m, found.dag.(*DoWindow).OnMap) + + nodes := dag.Build() + assert.Equal(t, 6, len(nodes)) + + //assert.Equal(t, "a", GetCtx(nodesFromTo[0]).Name()) + //assert.Equal(t, "b", GetCtx(nodesFromTo[1]).Name()) + + fmt.Println(ToMermaidGraph(dag)) + + fmt.Println(ToMermaidGraphWithOrder(dag, ReverseSort(Sort(dag)))) +} + +func TestNewContextBuilder(t *testing.T) { + useCases := map[string]struct { + in *DefaultContext + out *DefaultContext + }{ + "should set default values": { + in: NewContextBuilder(), + out: &DefaultContext{ + wd: &FixedWindow{ + // infinite window, + Width: math.MaxInt64, + }, + td: &AtWatermark{}, + fm: &Discard{}, + }, + }, + "should set window duration": { + in: NewContextBuilder( + WithFixedWindow(100*time.Millisecond), + WithTriggers(&AtPeriod{Duration: 10 * time.Millisecond}, &AtWatermark{}), + WithAccumulatingAndRetracting(), + ), + out: &DefaultContext{ + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + td: &AllOf{ + Triggers: []TriggerDescription{ + &AtPeriod{Duration: 10 * time.Millisecond}, + &AtWatermark{}, + }, + }, + fm: &AccumulatingAndRetracting{}, + }, + }, + } + for name, uc := range useCases { + t.Run(name, func(t *testing.T) { + assert.Equal(t, uc.out, uc.in) + }) + } + +} diff --git a/x/storage/schemaless/projection/example_data.go b/x/storage/schemaless/projection/example_data.go new file mode 100644 index 00000000..1f064999 --- /dev/null +++ b/x/storage/schemaless/projection/example_data.go @@ -0,0 +1,18 @@ +package projection + +//go:generate go run ../../../../cmd/mkunion/main.go + +//go:tag serde:"json" +type Game struct { + SessionID string + Players []string + Winner string + IsDraw bool +} + +//go:tag serde:"json" +type SessionsStats struct { + Wins int + Draws int + Loose int +} diff --git a/x/storage/schemaless/projection/example_data_serde_gen.go b/x/storage/schemaless/projection/example_data_serde_gen.go new file mode 100644 index 00000000..53de1595 --- /dev/null +++ b/x/storage/schemaless/projection/example_data_serde_gen.go @@ -0,0 +1,243 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "encoding/json" + "fmt" +) + +var ( + _ json.Unmarshaler = (*Game)(nil) + _ json.Marshaler = (*Game)(nil) +) + +func (r *Game) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONGame(*r) +} +func (r *Game) _marshalJSONGame(x Game) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldSessionID []byte + fieldSessionID, err = r._marshalJSONstring(x.SessionID) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONGame: field name SessionID; %w", err) + } + partial["SessionID"] = fieldSessionID + var fieldPlayers []byte + fieldPlayers, err = r._marshalJSONSlicestring(x.Players) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONGame: field name Players; %w", err) + } + partial["Players"] = fieldPlayers + var fieldWinner []byte + fieldWinner, err = r._marshalJSONstring(x.Winner) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONGame: field name Winner; %w", err) + } + partial["Winner"] = fieldWinner + var fieldIsDraw []byte + fieldIsDraw, err = r._marshalJSONbool(x.IsDraw) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONGame: field name IsDraw; %w", err) + } + partial["IsDraw"] = fieldIsDraw + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONGame: struct; %w", err) + } + return result, nil +} +func (r *Game) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Game) _marshalJSONSlicestring(x []string) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONstring(v) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONSlicestring: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONSlicestring:; %w", err) + } + return result, nil +} +func (r *Game) _marshalJSONbool(x bool) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: Game._marshalJSONbool:; %w", err) + } + return result, nil +} +func (r *Game) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONGame(data) + if err != nil { + return fmt.Errorf("projection: Game.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Game) _unmarshalJSONGame(data []byte) (Game, error) { + result := Game{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONGame: native struct unwrap; %w", err) + } + if fieldSessionID, ok := partial["SessionID"]; ok { + result.SessionID, err = r._unmarshalJSONstring(fieldSessionID) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONGame: field SessionID; %w", err) + } + } + if fieldPlayers, ok := partial["Players"]; ok { + result.Players, err = r._unmarshalJSONSlicestring(fieldPlayers) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONGame: field Players; %w", err) + } + } + if fieldWinner, ok := partial["Winner"]; ok { + result.Winner, err = r._unmarshalJSONstring(fieldWinner) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONGame: field Winner; %w", err) + } + } + if fieldIsDraw, ok := partial["IsDraw"]; ok { + result.IsDraw, err = r._unmarshalJSONbool(fieldIsDraw) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONGame: field IsDraw; %w", err) + } + } + return result, nil +} +func (r *Game) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Game) _unmarshalJSONSlicestring(data []byte) ([]string, error) { + result := make([]string, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONSlicestring: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONstring(v) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONSlicestring: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *Game) _unmarshalJSONbool(data []byte) (bool, error) { + var result bool + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: Game._unmarshalJSONbool: native primitive unwrap; %w", err) + } + return result, nil +} + +var ( + _ json.Unmarshaler = (*SessionsStats)(nil) + _ json.Marshaler = (*SessionsStats)(nil) +) + +func (r *SessionsStats) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONSessionsStats(*r) +} +func (r *SessionsStats) _marshalJSONSessionsStats(x SessionsStats) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldWins []byte + fieldWins, err = r._marshalJSONint(x.Wins) + if err != nil { + return nil, fmt.Errorf("projection: SessionsStats._marshalJSONSessionsStats: field name Wins; %w", err) + } + partial["Wins"] = fieldWins + var fieldDraws []byte + fieldDraws, err = r._marshalJSONint(x.Draws) + if err != nil { + return nil, fmt.Errorf("projection: SessionsStats._marshalJSONSessionsStats: field name Draws; %w", err) + } + partial["Draws"] = fieldDraws + var fieldLoose []byte + fieldLoose, err = r._marshalJSONint(x.Loose) + if err != nil { + return nil, fmt.Errorf("projection: SessionsStats._marshalJSONSessionsStats: field name Loose; %w", err) + } + partial["Loose"] = fieldLoose + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: SessionsStats._marshalJSONSessionsStats: struct; %w", err) + } + return result, nil +} +func (r *SessionsStats) _marshalJSONint(x int) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: SessionsStats._marshalJSONint:; %w", err) + } + return result, nil +} +func (r *SessionsStats) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONSessionsStats(data) + if err != nil { + return fmt.Errorf("projection: SessionsStats.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *SessionsStats) _unmarshalJSONSessionsStats(data []byte) (SessionsStats, error) { + result := SessionsStats{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: SessionsStats._unmarshalJSONSessionsStats: native struct unwrap; %w", err) + } + if fieldWins, ok := partial["Wins"]; ok { + result.Wins, err = r._unmarshalJSONint(fieldWins) + if err != nil { + return result, fmt.Errorf("projection: SessionsStats._unmarshalJSONSessionsStats: field Wins; %w", err) + } + } + if fieldDraws, ok := partial["Draws"]; ok { + result.Draws, err = r._unmarshalJSONint(fieldDraws) + if err != nil { + return result, fmt.Errorf("projection: SessionsStats._unmarshalJSONSessionsStats: field Draws; %w", err) + } + } + if fieldLoose, ok := partial["Loose"]; ok { + result.Loose, err = r._unmarshalJSONint(fieldLoose) + if err != nil { + return result, fmt.Errorf("projection: SessionsStats._unmarshalJSONSessionsStats: field Loose; %w", err) + } + } + return result, nil +} +func (r *SessionsStats) _unmarshalJSONint(data []byte) (int, error) { + var result int + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: SessionsStats._unmarshalJSONint: native primitive unwrap; %w", err) + } + return result, nil +} diff --git a/x/storage/schemaless/projection/example_data_shape_gen.go b/x/storage/schemaless/projection/example_data_shape_gen.go new file mode 100644 index 00000000..1fea5e74 --- /dev/null +++ b/x/storage/schemaless/projection/example_data_shape_gen.go @@ -0,0 +1,85 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(GameShape()) + shape.Register(SessionsStatsShape()) +} + +//shape:shape +func GameShape() shape.Shape { + return &shape.StructLike{ + Name: "Game", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "SessionID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Players", + Type: &shape.ListLike{ + Element: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + { + Name: "Winner", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "IsDraw", + Type: &shape.PrimitiveLike{Kind: &shape.BooleanLike{}}, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func SessionsStatsShape() shape.Shape { + return &shape.StructLike{ + Name: "SessionsStats", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Wins", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + { + Name: "Draws", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + { + Name: "Loose", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} diff --git a/x/storage/schemaless/projection/handler_avg.go b/x/storage/schemaless/projection/handler_avg.go new file mode 100644 index 00000000..7db81e64 --- /dev/null +++ b/x/storage/schemaless/projection/handler_avg.go @@ -0,0 +1,21 @@ +package projection + +import "github.com/widmogrod/mkunion/x/schema" + +type AvgHandler struct { + avg float64 + count int +} + +func (h *AvgHandler) Process(msg Item, returning func(Item)) error { + h.avg = (h.avg*float64(h.count) + schema.AsDefault[float64](msg.Data, 0)) / (float64(h.count) + 1) + // avg = (avg * count + x) / (count + 1) + h.count += 1 + + newValue := schema.Number(h.avg) + + returning(Item{ + Data: &newValue, + }) + return nil +} diff --git a/x/storage/schemaless/projection/handler_avg_test.go b/x/storage/schemaless/projection/handler_avg_test.go new file mode 100644 index 00000000..75b8a346 --- /dev/null +++ b/x/storage/schemaless/projection/handler_avg_test.go @@ -0,0 +1,45 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestAvgHandler(t *testing.T) { + h := &AvgHandler{} + assert.Equal(t, float64(0), h.avg) + + l := ListAssert{t: t} + + err := h.Process(Item{ + Data: schema.MkInt(1), + }, l.Returning) + assert.NoError(t, err) + l.AssertAt(0, Item{ + Data: schema.MkFloat(1), + }) + assert.Equal(t, float64(1), h.avg) + assert.Equal(t, 1, h.count) + + err = h.Process(Item{ + Data: schema.MkInt(11), + }, l.Returning) + assert.NoError(t, err) + l.AssertAt(1, Item{ + Data: schema.MkFloat(6), + }) + assert.Equal(t, float64(6), h.avg) + assert.Equal(t, 2, h.count) + + err = h.Process(Item{ + Data: schema.MkInt(3), + }, l.Returning) + assert.NoError(t, err) + l.AssertAt(2, Item{ + Data: schema.MkFloat(5), + }) + assert.Equal(t, float64(5), h.avg) + assert.Equal(t, 3, h.count) + +} diff --git a/x/storage/schemaless/projection/handler_count.go b/x/storage/schemaless/projection/handler_count.go new file mode 100644 index 00000000..ae813641 --- /dev/null +++ b/x/storage/schemaless/projection/handler_count.go @@ -0,0 +1,15 @@ +package projection + +import "github.com/widmogrod/mkunion/x/schema" + +type CountHandler struct { + value int +} + +func (h *CountHandler) Process(msg Item, returning func(Item)) error { + h.value += schema.AsDefault[int](msg.Data, 0) + returning(Item{ + Data: schema.MkInt(int64(h.value)), + }) + return nil +} diff --git a/x/storage/schemaless/projection/handler_count_test.go b/x/storage/schemaless/projection/handler_count_test.go new file mode 100644 index 00000000..813fd790 --- /dev/null +++ b/x/storage/schemaless/projection/handler_count_test.go @@ -0,0 +1,32 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestCountHandler(t *testing.T) { + h := &CountHandler{} + assert.Equal(t, 0, h.value) + + l := &ListAssert{t: t} + err := h.Process(Item{ + Data: schema.MkInt(1), + }, l.Returning) + assert.NoError(t, err) + l.AssertAt(0, Item{ + Data: schema.MkInt(1), + }) + assert.Equal(t, 1, h.value) + + err = h.Process(Item{ + Data: schema.MkInt(2), + }, l.Returning) + assert.NoError(t, err) + l.AssertAt(1, Item{ + Data: schema.MkInt(3), + }) + assert.Equal(t, 3, h.value) + +} diff --git a/x/storage/schemaless/projection/handler_filter.go b/x/storage/schemaless/projection/handler_filter.go new file mode 100644 index 00000000..8091dcfa --- /dev/null +++ b/x/storage/schemaless/projection/handler_filter.go @@ -0,0 +1,26 @@ +package projection + +import ( + "github.com/widmogrod/mkunion/x/storage/predicate" +) + +var _ Handler = &FilterHandler{} + +type FilterHandler struct { + Where *predicate.WherePredicates +} + +func (f *FilterHandler) Process(x Item, returning func(Item)) error { + panic("not implemented") + //if f.Where.Evaluate(x.Data) { + // returning(x) + //} + + return nil +} + +func (f *FilterHandler) Retract(x Item, returning func(Item)) error { + panic("not implemented") + //return f.Process(x, returning) + return nil +} diff --git a/x/storage/schemaless/projection/handler_generate.go b/x/storage/schemaless/projection/handler_generate.go new file mode 100644 index 00000000..d8fa6ad7 --- /dev/null +++ b/x/storage/schemaless/projection/handler_generate.go @@ -0,0 +1,16 @@ +package projection + +var _ Handler = &GenerateHandler{} + +type GenerateHandler struct { + Load func(push func(message Item)) error +} + +func (h *GenerateHandler) Process(x Item, returning func(Item)) error { + return h.Load(returning) +} + +func (h *GenerateHandler) Retract(x Item, returning func(Item)) error { + //TODO implement me + panic("implement me") +} diff --git a/x/storage/schemaless/projection/handler_generate_test.go b/x/storage/schemaless/projection/handler_generate_test.go new file mode 100644 index 00000000..499370fb --- /dev/null +++ b/x/storage/schemaless/projection/handler_generate_test.go @@ -0,0 +1,51 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestGenerateHandler(t *testing.T) { + generate := []Item{ + { + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + Winner: "a", + }), + }, + { + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + Winner: "b", + }), + }, + { + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + IsDraw: true, + }), + }, + } + + h := &GenerateHandler{ + Load: func(returning func(message Item)) error { + for _, msg := range generate { + returning(msg) + } + return nil + }, + } + + l := &ListAssert{ + t: t, + } + err := h.Process(Item{}, l.Returning) + assert.NoError(t, err) + + l.AssertLen(3) + + for idx, msg := range generate { + l.AssertAt(idx, msg) + } +} diff --git a/x/storage/schemaless/projection/handler_join.go b/x/storage/schemaless/projection/handler_join.go new file mode 100644 index 00000000..8f9fd6ee --- /dev/null +++ b/x/storage/schemaless/projection/handler_join.go @@ -0,0 +1,60 @@ +package projection + +var _ Handler = &JoinHandler[any]{} + +type JoinHandler[T any] struct { + F func(a, b T, returning func(T)) error +} + +func (j *JoinHandler[T]) Process(x Item, returning func(Item)) error { + panic("not implemented") + //var result T + //var resultSet = false + //var first bool = true + //var err error + ////Each(x.Data, func(value schema.Schema) { + // var elem T + // if err != nil { + // return + // } + // + // elem, err = schema.ToGoG[T](value) + // if err != nil { + // return + // } + // + // if first { + // first = false + // result = elem + // return + // } + // + // err = j.F(result, elem, func(t T) { + // resultSet = true + // result = t + // }) + // if err != nil { + // return + // } + //}) + // + //if err != nil { + // d, err2 := schema.ToJSON(x.Data) + // return fmt.Errorf("mergeHandler:Process(%s, err=%s) err %s", string(d), err, err2) + //} + // + //if resultSet { + // returning(Item{ + // Key: x.Key, + // Data: schema.FromGo(result), + // }) + //} + + return nil +} + +func (j *JoinHandler[T]) Retract(x Item, returning func(Item)) error { + panic("not implemented") + //return j.Process(x, returning) + +} diff --git a/x/storage/schemaless/projection/handler_log.go b/x/storage/schemaless/projection/handler_log.go new file mode 100644 index 00000000..cc6e58f1 --- /dev/null +++ b/x/storage/schemaless/projection/handler_log.go @@ -0,0 +1,35 @@ +package projection + +import ( + log "github.com/sirupsen/logrus" +) + +func Log(prefix string) Handler { + return &LogHandler{ + prefix: prefix, + } +} + +type LogHandler struct { + prefix string +} + +func (l *LogHandler) Process(x Item, returning func(Item)) error { + log. + WithField("key", x.Key). + WithField("item", ToStrItem(&x)). + Infof("%s: Process \n", l.prefix) + + returning(x) + return nil +} + +func (l *LogHandler) Retract(x Item, returning func(Item)) error { + log. + WithField("key", x.Key). + WithField("item", ToStrItem(&x)). + Infof("%s: Retract \n", l.prefix) + + returning(x) + return nil +} diff --git a/x/storage/schemaless/projection/handler_map.go b/x/storage/schemaless/projection/handler_map.go new file mode 100644 index 00000000..8b3ccd02 --- /dev/null +++ b/x/storage/schemaless/projection/handler_map.go @@ -0,0 +1,30 @@ +package projection + +import "github.com/widmogrod/mkunion/x/schema" + +var _ Handler = &MapHandler[any, any]{} + +type MapHandler[A any, B any] struct { + F func(x A, returning func(key string, value B)) error +} + +func (h *MapHandler[A, B]) Process(x Item, returning func(Item)) error { + //panic("not implemented") + mapCombineReturning := func(key string, value B) { + returning(Item{ + Key: key, + Data: schema.FromGo(value), + }) + } + data, err := schema.ToGoG[A](x.Data) + if err != nil { + return err + } + + return h.F(data, mapCombineReturning) +} + +func (h *MapHandler[A, B]) Retract(x Item, returning func(Item)) error { + panic("not implemented") + //return h.Process(x, returning) +} diff --git a/x/storage/schemaless/projection/handler_map_test.go b/x/storage/schemaless/projection/handler_map_test.go new file mode 100644 index 00000000..16010dd5 --- /dev/null +++ b/x/storage/schemaless/projection/handler_map_test.go @@ -0,0 +1,40 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestMapHandler(t *testing.T) { + h := MapGameToStats() + l := &ListAssert{ + t: t, + } + + err := h.Process(Item{ + Key: "game:1", + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + Winner: "a", + }), + }, l.Returning) + assert.NoError(t, err) + l.AssertLen(2) + l.AssertAt(0, Item{ + Key: "session-stats-by-player:a", + Data: schema.FromGo(SessionsStats{ + Wins: 1, + Loose: 0, + Draws: 0, + }), + }) + l.AssertAt(1, Item{ + Key: "session-stats-by-player:b", + Data: schema.FromGo(SessionsStats{ + Wins: 0, + Loose: 1, + Draws: 0, + }), + }) +} diff --git a/x/storage/schemaless/projection/handler_merge.go b/x/storage/schemaless/projection/handler_merge.go new file mode 100644 index 00000000..e8546c62 --- /dev/null +++ b/x/storage/schemaless/projection/handler_merge.go @@ -0,0 +1,99 @@ +package projection + +import ( + "fmt" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/shared" +) + +var _ Handler = &MergeHandler[any]{} + +type MergeHandler[A any] struct { + Combine func(a, b A) (A, error) + DoRetract func(a, b A) (A, error) +} + +func (h *MergeHandler[A]) Process(x Item, returning func(Item)) error { + var result A + var first bool = true + var err error + Each(x.Data, func(value schema.Schema) { + var elem A + if err != nil { + return + } + + elem, err = schema.ToGoG[A](value) + if err != nil { + return + } + + if first { + first = false + result = elem + return + } + + result, err = h.Combine(result, elem) + if err != nil { + return + } + }) + + if err != nil { + //d, err2 := schema.ToJSON(x.Data) + d, err2 := shared.JSONMarshal[schema.Schema](x.Data) + return fmt.Errorf("mergeHandler:Process(%s, err=%s) err %s", string(d), err, err2) + } + + returning(Item{ + Key: x.Key, + Data: schema.FromGo(result), + EventTime: x.EventTime, + Window: x.Window, + }) + + return nil +} + +func (h *MergeHandler[A]) Retract(x Item, returning func(Item)) error { + var result A + var first bool = true + var err error + Each(x.Data, func(value schema.Schema) { + var elem A + if err != nil { + return + } + + elem, err = schema.ToGoG[A](value) + if err != nil { + return + } + + if first { + first = false + result = elem + return + } + + result, err = h.DoRetract(result, elem) + if err != nil { + return + } + }) + + if err != nil { + d, err2 := shared.JSONMarshal[schema.Schema](x.Data) + return fmt.Errorf("mergeHandler:Watermark(%s, err=%s) err %s", string(d), err, err2) + } + + returning(Item{ + Key: x.Key, + Data: schema.FromGo(result), + EventTime: x.EventTime, + Window: x.Window, + }) + + return nil +} diff --git a/x/storage/schemaless/projection/handler_merge_test.go b/x/storage/schemaless/projection/handler_merge_test.go new file mode 100644 index 00000000..f41ef9ce --- /dev/null +++ b/x/storage/schemaless/projection/handler_merge_test.go @@ -0,0 +1,35 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestMergeHandler(t *testing.T) { + h := MergeSessionStats() + + l := &ListAssert{t: t} + err := h.Process(Item{ + Key: "session-stats-by-player:a", + Data: schema.MkList( + schema.FromGo(SessionsStats{ + Wins: 1, + Draws: 2, + }), + schema.FromGo(SessionsStats{ + Wins: 3, + Draws: 4, + }), + ), + }, l.Returning) + + assert.NoError(t, err) + l.AssertAt(0, Item{ + Key: "session-stats-by-player:a", + Data: schema.FromGo(SessionsStats{ + Wins: 4, + Draws: 6, + }), + }) +} diff --git a/x/storage/schemaless/projection/handler_simple.go b/x/storage/schemaless/projection/handler_simple.go new file mode 100644 index 00000000..c3954d61 --- /dev/null +++ b/x/storage/schemaless/projection/handler_simple.go @@ -0,0 +1,37 @@ +package projection + +var _ Handler = (*SimpleProcessHandler)(nil) + +type SimpleProcessHandler struct { + P func(x Item, returning func(Item)) error + R func(x Item, returning func(Item)) error +} + +func (s *SimpleProcessHandler) Process(x Item, returning func(Item)) error { + return s.P(x, returning) +} + +func (s *SimpleProcessHandler) Retract(x Item, returning func(Item)) error { + //TODO implement me + panic("implement me") +} + +//var _ HandleAccumulate = (*SimpleAccumulateHandler)(nil) +// +//type SimpleAccumulateHandler struct { +// P func(current Item, previous *Item, returning func(Item)) error +//} +// +//func (s *SimpleAccumulateHandler) ProcessAccumulate(current Item, previous *Item, returning func(Item)) error { +// return s.P(current, previous, returning) +//} +// +//type SimpleAccumulateAndRetractHandler struct { +//} +// +//func (s *SimpleAccumulateAndRetractHandler) ProcessAccumulateAndRetract(current Item, retract *Item, returning func(Item)) error { +// //TODO implement me +// panic("implement me") +//} +// +//var _ HandleAccumulateAndRetract = (*SimpleAccumulateAndRetractHandler)(nil) diff --git a/x/storage/schemaless/projection/handler_time_or_size_buffer.go b/x/storage/schemaless/projection/handler_time_or_size_buffer.go new file mode 100644 index 00000000..7f7e458f --- /dev/null +++ b/x/storage/schemaless/projection/handler_time_or_size_buffer.go @@ -0,0 +1,51 @@ +package projection + +import "time" + +var _ Handler = &DebounceHandler{} + +type DebounceHandler struct { + MaxSize int + MaxTime time.Duration + + last *Item + lastTime *time.Time + lastSize int +} + +func (t *DebounceHandler) Process(x Item, returning func(Item)) error { + panic("TODO figure out how to implement timeouts, so that runtime can stimulate a handler to flush its buffer") + + //if t.last == nil { + // t.lastTime = new(time.Time) + // *t.lastTime = time.Now() + //} + // + //t.last = &x + //t.lastSize += 1 + // + //// flush because size limit was reached + //if t.lastSize >= t.MaxSize && t.MaxSize != 0 { + // returning(*t.last) + // t.last = nil + // t.lastSize = 0 + // t.lastTime = nil + // return nil + //} + // + //// flush because time limit was reached + //if t.lastTime != nil && time.Since(*t.lastTime) >= t.MaxTime { + // returning(*t.last) + // t.last = nil + // t.lastSize = 0 + // t.lastTime = nil + // return nil + //} + + return nil +} + +func (t *DebounceHandler) Retract(x Item, returning func(Item)) error { + //TODO implement me + panic("implement me") +} diff --git a/x/storage/schemaless/projection/interprete_in_memory_two.go b/x/storage/schemaless/projection/interprete_in_memory_two.go new file mode 100644 index 00000000..31181601 --- /dev/null +++ b/x/storage/schemaless/projection/interprete_in_memory_two.go @@ -0,0 +1,589 @@ +package projection + +import ( + "context" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/widmogrod/mkunion/x/schema" + "math" + "sync" + "time" +) + +func NewInMemoryTwoInterpreter() *InMemoryTwoInterpreter { + return &InMemoryTwoInterpreter{ + pubsub: NewPubSubMultiChan[Node](), + byKeys: make(map[Node]map[string]Item), + running: make(map[Node]struct{}), + stats: NewStatsCollector(), + bagItem: NewInMemoryBagOf[Item](), + bagWindowTrigger: NewInMemoryBagOf[*WindowTrigger](), + } +} + +type InMemoryTwoInterpreter struct { + lock sync.Mutex + pubsub PubSubForInterpreter[Node] + byKeys map[Node]map[string]Item + running map[Node]struct{} + status ExecutionStatus + // what differences between process time and event time + // should answers question + // - are there any events in the system, that a process should wait? + watermark int64 + stats StatsCollector + + bagItem BagOf[Item] + bagWindowTrigger BagOf[*WindowTrigger] + windowBuffers map[Node]*WindowBuffer +} + +func (i *InMemoryTwoInterpreter) Run(ctx context.Context, nodes []Node) error { + i.lock.Lock() + if i.status != ExecutionStatusNew { + i.lock.Unlock() + return fmt.Errorf("interpreter.Run state %d %w", i.status, ErrInterpreterNotInNewState) + } + i.status = ExecutionStatusRunning + i.lock.Unlock() + + ctx, cancel := context.WithCancel(ctx) + group := &ExecutionGroup{ + ctx: ctx, + cancel: cancel, + } + + // Registering new nodes makes sure that, in case of non-deterministic concurrency + // when goroutine want to subscribe to a node, it will be registered, even if it's not publishing yet + for _, node := range nodes { + err := i.pubsub.Register(node) + if err != nil { + i.lock.Lock() + i.status = ExecutionStatusError + i.lock.Unlock() + + return fmt.Errorf("interpreter.Run(1) %w", err) + } + } + + for _, node := range nodes { + func(node Node) { + group.Go(func() (err error) { + return i.run(ctx, node) + }) + }(node) + } + + if err := group.Wait(); err != nil { + i.lock.Lock() + i.status = ExecutionStatusError + i.lock.Unlock() + + return fmt.Errorf("interpreter.Run(2) %w", err) + } + + i.lock.Lock() + i.status = ExecutionStatusFinished + i.lock.Unlock() + + return nil +} + +//func (a *InMemoryTwoInterpreter) Process(x Item, returning func(Item)) error { +// return MustMatchWindowFlushMode( +// a.fm, +// func(y *Accumulate) error { +// key := ItemKeyWindow(x) +// previous, err := a.bagItem.Get(key) +// +// isError := err != nil && err != NotFound +// isFound := err == nil +// if isError { +// panic(err) +// } +// +// if isFound { +// x.P +// return a.mapf.Process(x, func(item Item) { +// z := Item{ +// Key: item.Key, +// Window: item.Window, +// Data: schema.MkList( +// previous.Data, +// item.Data, +// ), +// EventTime: item.EventTime, +// } +// +// err := a.mergef.Process(z, func(item Item) { +// err := a.bagItem.Set(key, item) +// if err != nil { +// panic(err) +// } +// +// returning(item) +// }) +// if err != nil { +// panic(err) +// } +// }) +// } +// +// return a.mapf.Process(x, func(item Item) { +// err := a.bagItem.Set(key, item) +// //printItem(item, "set") +// if err != nil { +// panic(err) +// } +// returning(item) +// }) +// }, +// func(y *Discard) error { +// return a.mapf.Process(x, returning) +// }, +// func(y *AccumulatingAndRetracting) error { +// key := ItemKeyWindow(x) +// previous, err := a.bagItem.Get(key) +// isError := err != nil && err != NotFound +// isFound := err == nil +// if isError { +// panic(err) +// } +// +// if isFound { +// return a.mapf.Process(x, func(item Item) { +// z := Item{ +// Key: item.Key, +// Window: item.Window, +// Data: schema.MkList( +// previous.Data, +// item.Data, +// ), +// EventTime: item.EventTime, +// } +// +// err := a.mergef.Process(z, func(newAggregate Item) { +// err := a.bagItem.Set(key, newAggregate) +// if err != nil { +// panic(err) +// } +// +// // operation is in one messages, as one or nothing principle +// // which will help in transactional systems. +// returning(Item{ +// Key: newAggregate.Key, +// Data: PackRetractAndAggregate( +// previous.Data, +// newAggregate.Data, +// ), +// EventTime: newAggregate.EventTime, +// Window: newAggregate.Window, +// Type: ItemRetractAndAggregate, +// }) +// }) +// if err != nil { +// panic(err) +// } +// }) +// } +// +// return a.mapf.Process(x, func(item Item) { +// err := a.bagItem.Set(key, item) +// if err != nil { +// panic(err) +// } +// returning(item) // emit aggregate +// }) +// }, +// ) +//} + +func (i *InMemoryTwoInterpreter) run(ctx context.Context, dag Node) error { + if dag == nil { + //panic("fix nodes that are nil! fix dag builder!") + return nil + } + + // TODO introduce parallelism for Item - key groups + // bounded to some number of goroutines, that can be configured + // and that can be used to limit memory usage + + // TODO introduce merge window triggers, and triggers in general so that + // - RepositorySink can be used with batches + // - LiveSelect in TicTacToe game, can show progress in game after reload, not through streaming updates, but by sending final state - debounce? + + /* + + parallelize.Window().DoWindow().Log() + Parallelize by key groups + - group by key + - for each key group, run in parallel + + i: (a, 1) (b, 2) (c, 3) (d, 4) (a, 5) (b, 6) (c, 7) (d, 8) + Window(i, +1) + o: (a, 2) (b, 3) (c, 4) (d, 5) (a, 6) (b, 7) (c, 8) (d, 9) + + (a, 1) (a, 5) + (b, 2) (b, 6) + (c, 3) (c, 7) + (d, 4) (d, 8) + + */ + + return MatchNodeR1( + dag, + func(x *DoWindow) error { + log.Debugln("DoWindow: Start ", i.str(x)) + var lastOffset int = 0 + + trigger := NewTriggerManager(x.Ctx.td) + + timeTickers := NewTimeTicker() + timeTickers.Register(x.Ctx.td, trigger) + defer timeTickers.Unregister(x.Ctx.td) + + wb := NewWindowBuffer(x.Ctx.wd, trigger) + returning := func(item Item) error { + key := KeyedWindowKey(ToKeyedWindowFromItem(&item)) + key = KeyWithNamespace(key, x.Ctx.Name()) + + return i.pubsub.Publish(ctx, x, Message{ + Key: item.Key, + Item: &item, + }) + } + + trigger.WhenTrigger(func(kw *KeyedWindow) { + wb.EachKeyedWindow(kw, func(group *ItemGroupedByWindow) { + err := returning(ToElement(group)) + if err != nil { + panic(err) + } + wb.RemoveItemGropedByWindow(group) + }) + }) + err := i.pubsub.Subscribe( + ctx, + x.Input, + lastOffset, + func(msg Message) error { + if msg.Item != nil { + log.Info("window buffer msg", msg) + z := *msg.Item + wb.Append(z) + } else if msg.Watermark != nil { + log.Info("window watermark", msg) + trigger.SignalWatermark(*msg.Watermark) + + // forward watermark + err := i.pubsub.Publish(ctx, x, Message{ + Key: msg.Key, + Watermark: msg.Watermark, + }) + if err != nil { + panic(err) + } + } else { + panic("unknown message type") + } + + return nil + }, + ) + if err != nil { + return fmt.Errorf("interpreter.Window(1) %w", err) + } + + log.Debugln("DoWindow: Finish", i.str(x)) + i.pubsub.Finish(ctx, x) + + return nil + }, + func(x *DoMap) error { + log.Debugln("DoMap: Start ", i.str(x)) + var lastOffset int = 0 + + err := i.pubsub.Subscribe( + ctx, + x.Input, + lastOffset, + func(msg Message) error { + if msg.Item != nil { + log.Info("window buffer msg", msg) + z := *msg.Item + + if z.Type == ItemRetractAndAggregate { + return x.OnMap.Retract(z, func(item Item) { + err := i.pubsub.Publish(ctx, x, Message{ + Key: item.Key, + Item: &item, + }) + if err != nil { + panic(err) + } + }) + } + + key := KeyedWindowKey(ToKeyedWindowFromItem(&z)) + key = KeyWithNamespace(key, x.Ctx.Name()) + + return MatchWindowFlushModeR1( + x.Ctx.fm, + func(y *Accumulate) error { + previous, err := i.bagItem.Get(key) + + isError := err != nil && err != NotFound + isFound := err == nil + if isError { + panic(err) + } + + var item2 Item + if isFound { + item2 = Item{ + Key: z.Key, + Window: z.Window, + Data: schema.MkMap( + schema.MkField("Previous", previous.Data), + schema.MkField("Current", z.Data), + ), + EventTime: z.EventTime, + } + } else { + item2 = Item{ + Key: z.Key, + Window: z.Window, + Data: schema.MkMap( + schema.MkField("Current", z.Data), + ), + EventTime: z.EventTime, + } + } + + return x.OnMap.Process(item2, func(item Item) { + err := i.bagItem.Set(key, item) + if err != nil { + panic(err) + } + + err = i.pubsub.Publish(ctx, x, Message{ + Key: item.Key, + Item: &item, + }) + if err != nil { + panic(err) + } + }) + }, + func(y *Discard) error { + return x.OnMap.Process(z, func(item Item) { + err := i.pubsub.Publish(ctx, x, Message{ + Key: item.Key, + Item: &item, + }) + if err != nil { + panic(err) + } + }) + }, + func(y *AccumulatingAndRetracting) error { + previous, err := i.bagItem.Get(key) + + isError := err != nil && err != NotFound + isFound := err == nil + if isError { + panic(err) + } + + log.Errorln("AccumulatingAndRetracting ", key) + log.Errorln("AccumulatingAndRetracting ", isError, isFound) + + var item2 Item + if isFound { + item2 = Item{ + Key: z.Key, + Window: z.Window, + Data: schema.MkMap( + schema.MkField("Previous", previous.Data), + schema.MkField("Current", z.Data), + ), + EventTime: z.EventTime, + } + } else { + item2 = Item{ + Key: z.Key, + Window: z.Window, + Data: schema.MkMap( + schema.MkField("Current", z.Data), + ), + EventTime: z.EventTime, + } + } + + if isFound { + return x.OnMap.Process(item2, func(newAggregate Item) { + err := i.bagItem.Set(key, newAggregate) + if err != nil { + panic(err) + } + + err = i.pubsub.Publish(ctx, x, Message{ + Key: newAggregate.Key, + Item: &Item{ + Key: newAggregate.Key, + Data: PackRetractAndAggregate( + previous.Data, + newAggregate.Data, + ), + EventTime: newAggregate.EventTime, + Window: newAggregate.Window, + Type: ItemRetractAndAggregate, + }, + }) + + if err != nil { + panic(err) + } + }) + } + + return x.OnMap.Process(item2, func(item Item) { + err := i.bagItem.Set(key, item) + if err != nil { + panic(err) + } + + err = i.pubsub.Publish(ctx, x, Message{ + Key: item.Key, + Item: &item, + }) + if err != nil { + panic(err) + } + }) + }, + ) + } else if msg.Watermark != nil { + log.Info("window watermark", msg) + + // forward watermark + err := i.pubsub.Publish(ctx, x, Message{ + Key: msg.Key, + Watermark: msg.Watermark, + }) + if err != nil { + panic(err) + } + } else { + panic("unknown message type") + } + + return nil + }, + ) + if err != nil { + return fmt.Errorf("interpreter.DoWindow(1) %w", err) + } + + log.Debugln("DoMap: Finish", i.str(x)) + i.pubsub.Finish(ctx, x) + + return nil + }, + func(x *DoLoad) error { + var err error + log.Debugln("DoLoad: Start", i.str(x)) + err = x.OnLoad.Process(Item{}, func(item Item) { + if err != nil { + return + } + + if item.EventTime == 0 { + item.EventTime = time.Now().UnixNano() + } + + //// calculate watermark + //if item.EventTime > i.watermark { + // i.watermark = item.EventTime + //} + + i.stats.Incr(fmt.Sprintf("load[%s].returning", x.Ctx.Name()), 1) + + err = i.pubsub.Publish(ctx, x, Message{ + Key: item.Key, + Item: &item, + }) + }) + + if err != nil { + return fmt.Errorf("interpreter.DoLoad(1) %w", err) + } + + var mi int64 = math.MaxInt64 + err = i.pubsub.Publish(ctx, x, Message{ + Key: "none", + Watermark: &mi, + }) + + log.Debugln("DoLoad: Finish", i.str(x)) + i.pubsub.Finish(ctx, x) + + return nil + }, + func(x *DoJoin) error { + lastOffset := make([]int, len(x.Input)) + for idx, _ := range x.Input { + lastOffset[idx] = 0 + } + + group := ExecutionGroup{ctx: ctx} + + for idx := range x.Input { + func(idx int) { + group.Go(func() error { + return i.pubsub.Subscribe( + ctx, + x.Input[idx], + lastOffset[idx], + func(msg Message) error { + lastOffset[idx] = msg.Offset + + i.stats.Incr(fmt.Sprintf("join[%s].returning", x.Ctx.Name()), 1) + + // join streams and publish + err := i.pubsub.Publish(ctx, x, Message{ + Key: msg.Key, + Item: msg.Item, + Watermark: msg.Watermark, + }) + + if err != nil { + return fmt.Errorf("interpreter.DoJoin(1) %w", err) + } + + return nil + }, + ) + }) + }(idx) + } + + if err := group.Wait(); err != nil { + return fmt.Errorf("interpreter.DoJoin(1) %w", err) + } + + log.Debugln("DoJoin: Finish", i.str(x)) + i.pubsub.Finish(ctx, x) + + return nil + }, + ) +} + +func (i *InMemoryTwoInterpreter) str(x Node) string { + return ToStr(x) +} + +func (i *InMemoryTwoInterpreter) StatsSnapshotAndReset() Stats { + return i.stats.Snapshot() +} diff --git a/x/storage/schemaless/projection/interprete_in_memory_two_test.go b/x/storage/schemaless/projection/interprete_in_memory_two_test.go new file mode 100644 index 00000000..35e9e277 --- /dev/null +++ b/x/storage/schemaless/projection/interprete_in_memory_two_test.go @@ -0,0 +1,84 @@ +package projection + +import ( + "context" + "fmt" + log "github.com/sirupsen/logrus" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/shared" + "testing" + "time" +) + +func TestDefaultInMemoryInterpreter2(t *testing.T) { + log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.TextFormatter{ + ForceColors: true, + TimestampFormat: "", + PadLevelText: true, + }) + + dag := NewDAGBuilder() + loaded := dag.Load(&GenerateHandler{ + Load: func(push func(message Item)) error { + for item := range GenerateItemsEvery(withTime(10, 0), 20, 10*time.Millisecond) { + push(item) + } + return nil + }, + }) + + mapped := loaded. + Window(WithTriggers(&AtPeriod{100 * time.Millisecond})). + Map(Log("window")) + + mapped. + Map(&SimpleProcessHandler{ + P: func(x Item, returning func(Item)) error { + d, _ := shared.JSONMarshal[schema.Schema](schema.FromGo(x)) + log.Errorln("merge=", string(d)) + //return MustMatchProcessItem( + // x, + // func(x *Item) error { + // panic("implement me") + // }, + // func(x *ItemAggregate) error { + // panic("implement me") + // }, + // func(x *ItemAggregateAndRetract) error { + // returning(Item{ + // Key: x.Key, + // Data: schema.FromGo(schema.Reduce(x.Aggregate, fmt.Sprintf("-1(%s)", schema.AsDefault[string](x.Retract, "-1")), func(x schema.Schema, agg string) string { + // return fmt.Sprintf("%d,%s", schema.AsDefault[int](x, 0), agg) + // })), + // EventTime: x.EventTime, + // Window: x.Window, + // }) + // return nil + // + // }, + //) + + previous := schema.AsDefault[string](schema.GetSchema(x.Data, "Previous"), "") + current := schema.GetSchema(x.Data, "Current") + + returning(Item{ + Key: x.Key, + Data: schema.FromGo(schema.Reduce(current, previous, func(x schema.Schema, agg string) string { + return fmt.Sprintf("%d,%s", schema.AsDefault[int](x, 0), agg) + })), + EventTime: x.EventTime, + Window: x.Window, + }) + log.Info("merge end") + return nil + }, + }, WithAccumulatingAndRetracting()). + Map(Log("log")) + + interpret := NewInMemoryTwoInterpreter() + err := interpret.Run(context.Background(), dag.Build()) + if err != nil { + t.Fatal(err) + } +} diff --git a/x/storage/schemaless/projection/interpreter_in_memory.go b/x/storage/schemaless/projection/interpreter_in_memory.go new file mode 100644 index 00000000..5a3e0c5d --- /dev/null +++ b/x/storage/schemaless/projection/interpreter_in_memory.go @@ -0,0 +1,539 @@ +package projection + +import ( + "context" + "fmt" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/shared" + "sync" +) + +// import ( +// +// "context" +// "fmt" +// log "github.com/sirupsen/logrus" +// "github.com/widmogrod/mkunion/x/schema" +// "sync" +// +// ) +// +// func DefaultInMemoryInterpreter() *InMemoryInterpreter { +// return &InMemoryInterpreter{ +// pubsub: NewPubSubMultiChan[Node](), +// //pubsub: NewPubSub[Node](), +// byKeys: make(map[Node]map[string]Item), +// running: make(map[Node]struct{}), +// stats: NewStatsCollector(), +// } +// } +type ExecutionStatus int + +const ( + ExecutionStatusNew ExecutionStatus = iota + ExecutionStatusRunning + ExecutionStatusError + ExecutionStatusFinished +) + +var ( + ErrInterpreterNotInNewState = fmt.Errorf("interpreter is not in new state") +) + +type PubSubForInterpreter[T comparable] interface { + Register(key T) error + Publish(ctx context.Context, key T, msg Message) error + Finish(ctx context.Context, key T) + Subscribe(ctx context.Context, node T, fromOffset int, f func(Message) error) error +} + +// type InMemoryInterpreter struct { +// lock sync.Mutex +// pubsub PubSubForInterpreter[Node] +// byKeys map[Node]map[string]Item +// running map[Node]struct{} +// status ExecutionStatus +// // what differences between process time and event time +// // should answers question +// // - are there any events in the system, that a process should wait? +// watermark int64 +// stats StatsCollector +// } +// +// func (i *InMemoryInterpreter) Run(ctx context.Context, nodes []Node) error { +// i.lock.Lock() +// if i.status != ExecutionStatusNew { +// i.lock.Unlock() +// return fmt.Errorf("interpreter.Run state %d %w", i.status, ErrInterpreterNotInNewState) +// } +// i.status = ExecutionStatusRunning +// i.lock.Unlock() +// +// ctx, cancel := context.WithCancel(ctx) +// group := &ExecutionGroup{ +// ctx: ctx, +// cancel: cancel, +// } +// +// // Registering new nodes makes sure that, in case of non-deterministic concurrency +// // when goroutine want to subscribe to a node, it will be registered, even if it's not publishing yet +// for _, node := range nodes { +// err := i.pubsub.Register(node) +// if err != nil { +// i.lock.Lock() +// i.status = ExecutionStatusError +// i.lock.Unlock() +// +// return fmt.Errorf("interpreter.Run(1) %w", err) +// } +// } +// +// for _, node := range nodes { +// func(node Node) { +// group.Go(func() (err error) { +// return i.run(ctx, node) +// }) +// }(node) +// } +// +// if err := group.Wait(); err != nil { +// i.lock.Lock() +// i.status = ExecutionStatusError +// i.lock.Unlock() +// +// return fmt.Errorf("interpreter.Run(2) %w", err) +// } +// +// i.lock.Lock() +// i.status = ExecutionStatusFinished +// i.lock.Unlock() +// +// return nil +// } +// +// func (i *InMemoryInterpreter) run(ctx context.Context, dag Node) error { +// if dag == nil { +// //panic("fix nodes that are nil! fix dag builder!") +// return nil +// } +// +// // TODO introduce parallelism for Item - key groups +// // bounded to some number of goroutines, that can be configured +// // and that can be used to limit memory usage +// +// // TODO introduce merge window triggers, and triggers in general so that +// // - RepositorySink can be used with batches +// // - LiveSelect in TicTacToe game, can show progress in game after reload, not through streaming updates, but by sending final state - debounce? +// +// /* +// +// parallelize.Window().DoWindow().Log() +// Parallelize by key groups +// - group by key +// - for each key group, run in parallel +// +// i: (a, 1) (b, 2) (c, 3) (d, 4) (a, 5) (b, 6) (c, 7) (d, 8) +// Window(i, +1) +// o: (a, 2) (b, 3) (c, 4) (d, 5) (a, 6) (b, 7) (c, 8) (d, 9) +// +// (a, 1) (a, 5) +// (b, 2) (b, 6) +// (c, 3) (c, 7) +// (d, 4) (d, 8) +// +// */ +// +// return MustMatchNode( +// dag, +// func(x *Window) error { +// log.Debugln("Window: Start ", i.str(x)) +// var lastOffset int = 0 +// +// err := i.pubsub.Subscribe( +// ctx, +// x.Input, +// lastOffset, +// func(msg Message) error { +// lastOffset = msg.Offset +// log.Debugln("Window: ", i.str(x), msg.Item != nil, msg.Watermark != nil) +// log.Debugf("✉️: %+v %s\n", msg, i.str(x)) +// switch true { +// case msg.Item != nil && msg.Watermark == nil, +// msg.Item != nil && msg.Watermark != nil && !x.Ctx.ShouldRetract(): +// +// err := x.OnMap.Process(*msg.Item, func(item Item) { +// i.stats.Incr(fmt.Sprintf("map[%s].returning.aggregate", x.Ctx.Name()), 1) +// +// err := i.pubsub.Publish(ctx, x, Message{ +// Key: item.Key, +// Item: &item, +// }) +// if err != nil { +// panic(err) +// } +// }) +// if err != nil { +// panic(err) +// } +// +// case msg.Item != nil && msg.Watermark != nil && x.Ctx.ShouldRetract(): +// buff := NewDual() +// err := x.OnMap.Process(*msg.Item, buff.ReturningAggregate) +// if err != nil { +// panic(err) +// } +// err = x.OnMap.Retract(*msg.Watermark, buff.ReturningRetract) +// if err != nil { +// panic(err) +// } +// +// if !buff.IsValid() { +// panic("Window(1); asymmetry " + i.str(x)) +// } +// +// for _, msg := range buff.List() { +// i.stats.Incr(fmt.Sprintf("map[%s].returning.aggregate", x.Ctx.Name()), 1) +// i.stats.Incr(fmt.Sprintf("map[%s].returning.retract", x.Ctx.Name()), 1) +// +// err := i.pubsub.Publish(ctx, x, *msg) +// if err != nil { +// panic(err) +// } +// } +// +// case msg.Item == nil && msg.Watermark != nil && x.Ctx.ShouldRetract(): +// err := x.OnMap.Retract(*msg.Watermark, func(item Item) { +// +// i.stats.Incr(fmt.Sprintf("map[%s].returning.aggregate", x.Ctx.Name()), 1) +// +// err := i.pubsub.Publish(ctx, x, Message{ +// Key: item.Key, +// Watermark: &item, +// }) +// if err != nil { +// panic(err) +// } +// }) +// if err != nil { +// panic(err) +// } +// +// case msg.Item == nil && msg.Watermark != nil && !x.Ctx.ShouldRetract(): +// log.Debugln("ignored retraction", i.str(x)) +// +// default: +// panic("not implemented Window(3); " + i.str(x) + " " + ToStrMessage(msg)) +// } +// +// log.Debugln("√", i.str(x)) +// +// return nil +// }, +// ) +// if err != nil { +// return fmt.Errorf("interpreter.Window(1) %w", err) +// } +// +// log.Debugln("Window: Finish", i.str(x)) +// i.pubsub.Finish(ctx, x) +// +// return nil +// }, +// func(x *DoWindow) error { +// var lastOffset int = 0 +// prev := make(map[string]*Item) +// +// err := i.pubsub.Subscribe( +// ctx, +// x.Input, +// lastOffset, +// func(msg Message) error { +// lastOffset = msg.Offset +// +// if msg.Watermark == nil && msg.Item == nil { +// panic("message has not Aggretate nor Watermark. not implemented (1)") +// } +// +// log.Debugln("DoWindow 👯: ", i.str(x), msg.Item != nil, msg.Watermark != nil) +// +// if _, ok := prev[msg.Key]; ok { +// base := prev[msg.Key] +// +// // TODO: retraction and aggregatoin don't happen in transactional way, even if message has both operations +// // this is a problem, because if retraction fails, then aggregation will be lost +// if msg.Watermark != nil && x.Ctx.ShouldRetract() { +// log.Debugln("❌retracting in merge", i.str(x)) +// retract := Item{ +// Key: msg.Key, +// Data: schema.MkList(base.Data, msg.Watermark.Data), +// } +// +// if err := x.OnMap.Retract(retract, func(item Item) { +// +// i.stats.Incr(fmt.Sprintf("merge[%s].returning.retract", x.Ctx.Name()), 1) +// +// base = &item +// err := i.pubsub.Publish(ctx, x, Message{ +// Key: msg.Key, +// Watermark: &item, +// }) +// if err != nil { +// panic(err) +// } +// }); err != nil { +// panic(err) +// } +// } +// +// if msg.Item != nil { +// log.Debugln("✅aggregate in merge", i.str(x)) +// merge := Item{ +// Key: msg.Key, +// Data: schema.MkList(base.Data, msg.Item.Data), +// } +// err := x.OnMap.Process(merge, func(item Item) { +// i.stats.Incr(fmt.Sprintf("merge[%s].returning.aggregate", x.Ctx.Name()), 1) +// +// p := base +// base = &item +// // TODO: In feature, we should make better decision whenever send retractions or not. +// // For now, we always send retractions, they don't have to be treated as retraction by the receiver. +// // But, this has penalty related to throughput, and latency, and for some applications, it is not acceptable. +// err := i.pubsub.Publish(ctx, x, Message{ +// Key: msg.Key, +// Item: &item, +// Watermark: p, +// }) +// if err != nil { +// panic(err) +// } +// }) +// if err != nil { +// panic(err) +// } +// } +// +// prev[msg.Key] = base +// +// } else { +// if msg.Watermark != nil { +// panic("no previous state, and requesing retracting. not implemented (2)" + ToStrMessage(msg)) +// } +// +// i.stats.Incr(fmt.Sprintf("merge[%s].returning.aggregate", x.Ctx.Name()), 1) +// +// prev[msg.Key] = msg.Item +// err := i.pubsub.Publish(ctx, x, Message{ +// Key: msg.Key, +// Item: msg.Item, +// }) +// if err != nil { +// return fmt.Errorf("interpreter.DoWindow(1) %w", err) +// } +// } +// +// return nil +// }, +// ) +// if err != nil { +// return fmt.Errorf("interpreter.DoWindow(1) %w", err) +// } +// +// //for _, item := range prev { +// // err := i.pubsub.Publish(ctx, x, Message{ +// // Key: item.Key, +// // Item: item, +// // }) +// // if err != nil { +// // return fmt.Errorf("interpreter.DoWindow(2) %w", err) +// // } +// //} +// +// log.Debugln("DoWindow: Finish", i.str(x)) +// i.pubsub.Finish(ctx, x) +// +// return nil +// }, +// func(x *DoLoad) error { +// var err error +// log.Debugln("DoLoad: Start", i.str(x)) +// err = x.OnLoad.Process(Item{}, func(item Item) { +// if err != nil { +// return +// } +// +// //if item.EventTime == 0 { +// // item.EventTime = time.Now().UnixNano() +// //} +// // +// //// calculate watermark +// //if item.EventTime > i.watermark { +// // i.watermark = item.EventTime +// //} +// +// i.stats.Incr(fmt.Sprintf("load[%s].returning", x.Ctx.Name()), 1) +// +// err = i.pubsub.Publish(ctx, x, Message{ +// Key: item.Key, +// Item: &item, +// Watermark: nil, +// }) +// }) +// +// if err != nil { +// return fmt.Errorf("interpreter.DoLoad(1) %w", err) +// } +// +// log.Debugln("DoLoad: Finish", i.str(x)) +// i.pubsub.Finish(ctx, x) +// +// return nil +// }, +// func(x *DoJoin) error { +// lastOffset := make([]int, len(x.Input)) +// for idx, _ := range x.Input { +// lastOffset[idx] = 0 +// } +// +// group := ExecutionGroup{ctx: ctx} +// +// for idx := range x.Input { +// func(idx int) { +// group.Go(func() error { +// return i.pubsub.Subscribe( +// ctx, +// x.Input[idx], +// lastOffset[idx], +// func(msg Message) error { +// lastOffset[idx] = msg.Offset +// +// i.stats.Incr(fmt.Sprintf("join[%s].returning", x.Ctx.Name()), 1) +// +// // join streams and publish +// err := i.pubsub.Publish(ctx, x, Message{ +// Key: msg.Key, +// Item: msg.Item, +// Watermark: msg.Watermark, +// }) +// +// if err != nil { +// return fmt.Errorf("interpreter.DoJoin(1) %w", err) +// } +// +// return nil +// }, +// ) +// }) +// }(idx) +// } +// +// if err := group.Wait(); err != nil { +// return fmt.Errorf("interpreter.DoJoin(1) %w", err) +// } +// +// log.Debugln("DoJoin: Finish", i.str(x)) +// i.pubsub.Finish(ctx, x) +// +// return nil +// }, +// ) +// } +//func (i *InMemoryInterpreter) str(x Node) string { +// return ToStr(x) +//} +// +//func (i *InMemoryInterpreter) StatsSnapshotAndReset() Stats { +// return i.stats.Snapshot() +//} + +//func ToStrMessage(msg Message) string { +// return fmt.Sprintf("Message{Key: %s, Watermark: %s, Item: %s}", +// msg.Key, +// //ToStrItem(msg.Watermark), +// ToStrItem(msg.Item)) +//} + +func ToStrItem(item *Item) string { + if item == nil { + return "nil" + } + bytes, err := shared.JSONMarshal[schema.Schema](item.Data) + + if err != nil { + panic(err) + } + return fmt.Sprintf("Item{Key: %s, Data: %s}", + item.Key, string(bytes)) +} + +func ToStr(x Node) string { + return MatchNodeR1( + x, + func(x *DoWindow) string { + return fmt.Sprintf("map(%sv)", x.Ctx.Name()) + }, + func(x *DoMap) string { + return fmt.Sprintf("merge(%sv)", x.Ctx.Name()) + }, + func(x *DoLoad) string { + return fmt.Sprintf("DoLoad(%s)", x.Ctx.Name()) + }, + func(x *DoJoin) string { + return fmt.Sprintf("join(%s)", x.Ctx.Name()) + }, + ) +} + +type ExecutionGroup struct { + ctx context.Context + cancel func() + wg sync.WaitGroup + err error + once sync.Once +} + +func (g *ExecutionGroup) Go(f func() error) { + g.wg.Add(1) + + started := make(chan struct{}) + go func() { + defer g.wg.Done() + + select { + case <-g.ctx.Done(): + // signal that goroutine has started + close(started) + if err := g.ctx.Err(); err != nil { + g.once.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel() + } + }) + } + + default: + // signal that goroutine has started + close(started) + err := f() + if err != nil { + g.once.Do(func() { + g.err = err + if g.cancel != nil { + g.cancel() + } + }) + } + } + }() + + <-started +} + +func (g *ExecutionGroup) Wait() error { + g.wg.Wait() + if g.cancel != nil { + g.cancel() + } + return nil +} diff --git a/x/storage/schemaless/projection/interpreter_in_memory_test.go b/x/storage/schemaless/projection/interpreter_in_memory_test.go new file mode 100644 index 00000000..061c2598 --- /dev/null +++ b/x/storage/schemaless/projection/interpreter_in_memory_test.go @@ -0,0 +1,72 @@ +package projection + +// +//func TestDefaultInMemoryInterpreter(t *testing.T) { +// log.SetLevel(log.DebugLevel) +// log.SetFormatter(&log.TextFormatter{ +// ForceColors: true, +// TimestampFormat: "", +// PadLevelText: true, +// }) +// +// dag := NewDAGBuilder() +// _ = dag. +// DoLoad(&GenerateHandler{DoLoad: func(push func(message Item)) error { +// push(Item{Key: "1", Data: schema.FromGo(1)}) +// return nil +// }}). +// Window(&MapHandler[int, int]{ +// F: func(x int, returning func(key string, value int)) error { +// returning("x", x+1) +// return nil +// }, +// }, WithName("DoSomething")) +// +// t.Run("normal run, finishes", func(t *testing.T) { +// interpreter := DefaultInMemoryInterpreter() +// assert.NotNil(t, interpreter) +// +// err := interpreter.Run(context.Background(), dag.Build()) +// assert.NoError(t, err) +// //DEBUG [0000] Window: map(DoSomething, r=false) true false +// //DEBUG [0000] ✉️: {Offset:0 Key:1 Item:0x14000178d20 Watermark: finished:false} map(DoSomething, r=false) +// //DEBUG [0000] √ map(DoSomething, r=false) +// //DEBUG [0000] DoLoad: Finish DoLoad(root.Load0, r=false) +// //DEBUG [0000] Window: Finish map(DoSomething, r=false) +// stats := interpreter.StatsSnapshotAndReset() +// assert.Equal(t, 1, stats["load[root.Load0].returning"]) +// assert.Equal(t, 1, stats["map[DoSomething].returning.aggregate"]) +// +// // second time should return zero +// stats = interpreter.StatsSnapshotAndReset() +// assert.Equal(t, 0, stats["load[root.Load0].returning"]) +// assert.Equal(t, 0, stats["map[DoSomething].returning.aggregate"]) +// }) +// +// // should be able to run again the same DAG +// t.Run("run on closed context should not execute, end return error", func(t *testing.T) { +// // should not execute when context is cancelled +// ctx, cancel := context.WithCancel(context.Background()) +// cancel() +// +// interpreter := DefaultInMemoryInterpreter() +// // TODO fix this, to proper error handling +// err := interpreter.Run(ctx, dag.Build()) +// assert.NoError(t, err) +// +// stats := interpreter.StatsSnapshotAndReset() +// assert.Equal(t, 0, stats["load[root.Load0].returning"]) +// assert.Equal(t, 0, stats["map[DoSomething].returning.aggregate"]) +// }) +// +// t.Run("executing the same DAG twice should not execute twice", func(t *testing.T) { +// interpreter := DefaultInMemoryInterpreter() +// assert.NotNil(t, interpreter) +// +// err := interpreter.Run(context.Background(), dag.Build()) +// assert.NoError(t, err) +// +// err = interpreter.Run(context.Background(), dag.Build()) +// assert.ErrorIs(t, err, ErrInterpreterNotInNewState) +// }) +//} diff --git a/x/storage/schemaless/projection/projection.go b/x/storage/schemaless/projection/projection.go new file mode 100644 index 00000000..aca08ce1 --- /dev/null +++ b/x/storage/schemaless/projection/projection.go @@ -0,0 +1,222 @@ +package projection + +import ( + "errors" + "github.com/widmogrod/mkunion/x/schema" + "math" + "time" +) + +var ErrNotFound = errors.New("node not found") + +//go:generate go run ../../../../cmd/mkunion/main.go + +//go:tag mkunion:"Node" +type ( + DoWindow struct { + Ctx *DefaultContext + Input Node + } + // DoMap implicitly means, merge by key + DoMap struct { + Ctx *DefaultContext + OnMap Handler + Input Node + } + DoLoad struct { + Ctx *DefaultContext + OnLoad Handler + } + DoJoin struct { + Ctx *DefaultContext + Input []Node + } +) + +func GetCtx(node Node) *DefaultContext { + return MatchNodeR1( + node, + func(node *DoWindow) *DefaultContext { return node.Ctx }, + func(node *DoMap) *DefaultContext { return node.Ctx }, + func(node *DoLoad) *DefaultContext { return node.Ctx }, + func(node *DoJoin) *DefaultContext { return node.Ctx }, + ) +} + +func NodeToString(node Node) string { + return MatchNodeR1( + node, + func(node *DoWindow) string { return "Window" }, + func(node *DoMap) string { return "DoWindow" }, + func(node *DoLoad) string { return "DoLoad" }, + func(node *DoJoin) string { return "DoJoin" }, + ) +} + +type EventTime = int64 + +type Window struct { + Start int64 + End int64 +} + +type ItemType uint8 + +const ( + ItemAggregation ItemType = iota + ItemRetractAndAggregate +) + +//go:tag serde:"json" +type Item struct { + Key string + Data schema.Schema + EventTime EventTime + Window *Window + Type ItemType +} + +//go:tag serde:"json" +type ItemGroupedByKey struct { + Key string + Data []Item +} + +//go:tag serde:"json" +type ItemGroupedByWindow struct { + Key string + Data *schema.List + Window *Window +} + +func PackRetractAndAggregate(x, y schema.Schema) *schema.Map { + return schema.MkMap( + schema.MkField("Retract", x), + schema.MkField("Aggregate", y), + ) +} + +//func UnpackRetractAndAggregate(x *schema.Map) (retract schema.Schema, aggregate schema.Schema) { +// return schema.Get[schema.Schema](x, "Retract"), schema.Get[schema.Schema](x, "Aggregate") +//} + +type Handler interface { + Process(x Item, returning func(Item)) error + Retract(x Item, returning func(Item)) error +} + +//type HandleAccumulate interface { +// ProcessAccumulate(current Item, previous *Item, returning func(Item)) error +//} +// +//type HandleAccumulateAndRetract interface { +// ProcessAccumulateAndRetract(current Item, retract *Item, returning func(Item)) error +//} + +type Builder interface { + Load(f Handler, opts ...ContextOptionFunc) Builder + Window(opts ...ContextOptionFunc) Builder + Map(f Handler, opts ...ContextOptionFunc) Builder + Join(a, b Builder, opts ...ContextOptionFunc) Builder + Build() []Node +} + +type ContextOptionFunc func(c *DefaultContext) + +func NewContextBuilder(builders ...func(config *DefaultContext)) *DefaultContext { + config := &DefaultContext{ + wd: &FixedWindow{ + Width: math.MaxInt64, + }, + td: &AtWatermark{}, + fm: &Discard{}, + } + for _, builder := range builders { + builder(config) + } + + return config +} + +func WithWindowDescription(wd WindowDescription) ContextOptionFunc { + return func(config *DefaultContext) { + config.wd = wd + } +} + +func WithFixedWindow(width time.Duration) ContextOptionFunc { + return WithWindowDescription(&FixedWindow{ + Width: width, + }) +} +func WithSlidingWindow(width time.Duration, period time.Duration) ContextOptionFunc { + return WithWindowDescription(&SlidingWindow{ + Width: width, + Period: period, + }) +} +func WithSessionWindow(gap time.Duration) ContextOptionFunc { + return WithWindowDescription(&SessionWindow{ + GapDuration: gap, + }) +} + +func WithTriggers(and ...TriggerDescription) ContextOptionFunc { + return func(config *DefaultContext) { + config.td = &AllOf{ + Triggers: and, + } + } +} + +func WithWindowFlushMode(fm WindowFlushMode) ContextOptionFunc { + return func(config *DefaultContext) { + config.fm = fm + } +} + +func WithDiscard() ContextOptionFunc { + return WithWindowFlushMode(&Discard{}) +} +func WithAccumulate() ContextOptionFunc { + return WithWindowFlushMode(&Accumulate{}) +} +func WithAccumulatingAndRetracting() ContextOptionFunc { + return WithWindowFlushMode(&AccumulatingAndRetracting{}) +} + +func WithName(name string) ContextOptionFunc { + return func(c *DefaultContext) { + c.name = name + } +} + +type DefaultContext struct { + name string + contextName string + //retracting *bool + + wd WindowDescription + td TriggerDescription + fm WindowFlushMode +} + +func (c *DefaultContext) Scope(name string) *DefaultContext { + return NewContextBuilder(WithName(c.name + "." + name)) +} + +func (c *DefaultContext) Name() string { + return c.name +} + +type Message struct { + Offset int + // at some point of time i may need to pass type reference + Key string + Item *Item + Watermark *int64 + + finished bool +} + +type Stats = map[string]int diff --git a/x/storage/schemaless/projection/projection_serde_gen.go b/x/storage/schemaless/projection/projection_serde_gen.go new file mode 100644 index 00000000..eeb4fc45 --- /dev/null +++ b/x/storage/schemaless/projection/projection_serde_gen.go @@ -0,0 +1,480 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "encoding/json" + "fmt" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/shared" +) + +var ( + _ json.Unmarshaler = (*Item)(nil) + _ json.Marshaler = (*Item)(nil) +) + +func (r *Item) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONItem(*r) +} +func (r *Item) _marshalJSONItem(x Item) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldKey []byte + fieldKey, err = r._marshalJSONstring(x.Key) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItem: field name Key; %w", err) + } + partial["Key"] = fieldKey + var fieldData []byte + fieldData, err = r._marshalJSONschema_Schema(x.Data) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItem: field name Data; %w", err) + } + partial["Data"] = fieldData + var fieldEventTime []byte + fieldEventTime, err = r._marshalJSONEventTime(x.EventTime) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItem: field name EventTime; %w", err) + } + partial["EventTime"] = fieldEventTime + var fieldWindow []byte + fieldWindow, err = r._marshalJSONPtrWindow(x.Window) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItem: field name Window; %w", err) + } + if fieldWindow != nil { + partial["Window"] = fieldWindow + } + var fieldType []byte + fieldType, err = r._marshalJSONItemType(x.Type) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItem: field name Type; %w", err) + } + partial["Type"] = fieldType + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItem: struct; %w", err) + } + return result, nil +} +func (r *Item) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Item) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *Item) _marshalJSONEventTime(x EventTime) ([]byte, error) { + result, err := shared.JSONMarshal[EventTime](x) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONEventTime:; %w", err) + } + return result, nil +} +func (r *Item) _marshalJSONPtrWindow(x *Window) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONWindow(*x) +} +func (r *Item) _marshalJSONWindow(x Window) ([]byte, error) { + result, err := shared.JSONMarshal[Window](x) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONWindow:; %w", err) + } + return result, nil +} +func (r *Item) _marshalJSONItemType(x ItemType) ([]byte, error) { + result, err := shared.JSONMarshal[ItemType](x) + if err != nil { + return nil, fmt.Errorf("projection: Item._marshalJSONItemType:; %w", err) + } + return result, nil +} +func (r *Item) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONItem(data) + if err != nil { + return fmt.Errorf("projection: Item.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Item) _unmarshalJSONItem(data []byte) (Item, error) { + result := Item{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItem: native struct unwrap; %w", err) + } + if fieldKey, ok := partial["Key"]; ok { + result.Key, err = r._unmarshalJSONstring(fieldKey) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItem: field Key; %w", err) + } + } + if fieldData, ok := partial["Data"]; ok { + result.Data, err = r._unmarshalJSONschema_Schema(fieldData) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItem: field Data; %w", err) + } + } + if fieldEventTime, ok := partial["EventTime"]; ok { + result.EventTime, err = r._unmarshalJSONEventTime(fieldEventTime) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItem: field EventTime; %w", err) + } + } + if fieldWindow, ok := partial["Window"]; ok { + result.Window, err = r._unmarshalJSONPtrWindow(fieldWindow) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItem: field Window; %w", err) + } + } + if fieldType, ok := partial["Type"]; ok { + result.Type, err = r._unmarshalJSONItemType(fieldType) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItem: field Type; %w", err) + } + } + return result, nil +} +func (r *Item) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Item) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Item) _unmarshalJSONEventTime(data []byte) (EventTime, error) { + result, err := shared.JSONUnmarshal[EventTime](data) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONEventTime: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Item) _unmarshalJSONPtrWindow(data []byte) (*Window, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONWindow(data) + if err != nil { + return nil, fmt.Errorf("projection: Item._unmarshalJSONPtrWindow: pointer; %w", err) + } + return &result, nil +} +func (r *Item) _unmarshalJSONWindow(data []byte) (Window, error) { + result, err := shared.JSONUnmarshal[Window](data) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONWindow: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Item) _unmarshalJSONItemType(data []byte) (ItemType, error) { + result, err := shared.JSONUnmarshal[ItemType](data) + if err != nil { + return result, fmt.Errorf("projection: Item._unmarshalJSONItemType: native ref unwrap; %w", err) + } + return result, nil +} + +var ( + _ json.Unmarshaler = (*ItemGroupedByKey)(nil) + _ json.Marshaler = (*ItemGroupedByKey)(nil) +) + +func (r *ItemGroupedByKey) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONItemGroupedByKey(*r) +} +func (r *ItemGroupedByKey) _marshalJSONItemGroupedByKey(x ItemGroupedByKey) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldKey []byte + fieldKey, err = r._marshalJSONstring(x.Key) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONItemGroupedByKey: field name Key; %w", err) + } + partial["Key"] = fieldKey + var fieldData []byte + fieldData, err = r._marshalJSONSliceItem(x.Data) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONItemGroupedByKey: field name Data; %w", err) + } + partial["Data"] = fieldData + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONItemGroupedByKey: struct; %w", err) + } + return result, nil +} +func (r *ItemGroupedByKey) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *ItemGroupedByKey) _marshalJSONSliceItem(x []Item) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONItem(v) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONSliceItem: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONSliceItem:; %w", err) + } + return result, nil +} +func (r *ItemGroupedByKey) _marshalJSONItem(x Item) ([]byte, error) { + result, err := shared.JSONMarshal[Item](x) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByKey._marshalJSONItem:; %w", err) + } + return result, nil +} +func (r *ItemGroupedByKey) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONItemGroupedByKey(data) + if err != nil { + return fmt.Errorf("projection: ItemGroupedByKey.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *ItemGroupedByKey) _unmarshalJSONItemGroupedByKey(data []byte) (ItemGroupedByKey, error) { + result := ItemGroupedByKey{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONItemGroupedByKey: native struct unwrap; %w", err) + } + if fieldKey, ok := partial["Key"]; ok { + result.Key, err = r._unmarshalJSONstring(fieldKey) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONItemGroupedByKey: field Key; %w", err) + } + } + if fieldData, ok := partial["Data"]; ok { + result.Data, err = r._unmarshalJSONSliceItem(fieldData) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONItemGroupedByKey: field Data; %w", err) + } + } + return result, nil +} +func (r *ItemGroupedByKey) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *ItemGroupedByKey) _unmarshalJSONSliceItem(data []byte) ([]Item, error) { + result := make([]Item, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONSliceItem: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONItem(v) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONSliceItem: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *ItemGroupedByKey) _unmarshalJSONItem(data []byte) (Item, error) { + result, err := shared.JSONUnmarshal[Item](data) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByKey._unmarshalJSONItem: native ref unwrap; %w", err) + } + return result, nil +} + +var ( + _ json.Unmarshaler = (*ItemGroupedByWindow)(nil) + _ json.Marshaler = (*ItemGroupedByWindow)(nil) +) + +func (r *ItemGroupedByWindow) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONItemGroupedByWindow(*r) +} +func (r *ItemGroupedByWindow) _marshalJSONItemGroupedByWindow(x ItemGroupedByWindow) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldKey []byte + fieldKey, err = r._marshalJSONstring(x.Key) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONItemGroupedByWindow: field name Key; %w", err) + } + partial["Key"] = fieldKey + var fieldData []byte + fieldData, err = r._marshalJSONPtrschema_List(x.Data) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONItemGroupedByWindow: field name Data; %w", err) + } + if fieldData != nil { + partial["Data"] = fieldData + } + var fieldWindow []byte + fieldWindow, err = r._marshalJSONPtrWindow(x.Window) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONItemGroupedByWindow: field name Window; %w", err) + } + if fieldWindow != nil { + partial["Window"] = fieldWindow + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONItemGroupedByWindow: struct; %w", err) + } + return result, nil +} +func (r *ItemGroupedByWindow) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *ItemGroupedByWindow) _marshalJSONPtrschema_List(x *schema.List) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONschema_List(*x) +} +func (r *ItemGroupedByWindow) _marshalJSONschema_List(x schema.List) ([]byte, error) { + result, err := shared.JSONMarshal[schema.List](x) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONschema_List:; %w", err) + } + return result, nil +} +func (r *ItemGroupedByWindow) _marshalJSONPtrWindow(x *Window) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONWindow(*x) +} +func (r *ItemGroupedByWindow) _marshalJSONWindow(x Window) ([]byte, error) { + result, err := shared.JSONMarshal[Window](x) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._marshalJSONWindow:; %w", err) + } + return result, nil +} +func (r *ItemGroupedByWindow) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONItemGroupedByWindow(data) + if err != nil { + return fmt.Errorf("projection: ItemGroupedByWindow.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *ItemGroupedByWindow) _unmarshalJSONItemGroupedByWindow(data []byte) (ItemGroupedByWindow, error) { + result := ItemGroupedByWindow{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONItemGroupedByWindow: native struct unwrap; %w", err) + } + if fieldKey, ok := partial["Key"]; ok { + result.Key, err = r._unmarshalJSONstring(fieldKey) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONItemGroupedByWindow: field Key; %w", err) + } + } + if fieldData, ok := partial["Data"]; ok { + result.Data, err = r._unmarshalJSONPtrschema_List(fieldData) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONItemGroupedByWindow: field Data; %w", err) + } + } + if fieldWindow, ok := partial["Window"]; ok { + result.Window, err = r._unmarshalJSONPtrWindow(fieldWindow) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONItemGroupedByWindow: field Window; %w", err) + } + } + return result, nil +} +func (r *ItemGroupedByWindow) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *ItemGroupedByWindow) _unmarshalJSONPtrschema_List(data []byte) (*schema.List, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONschema_List(data) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONPtrschema_List: pointer; %w", err) + } + return &result, nil +} +func (r *ItemGroupedByWindow) _unmarshalJSONschema_List(data []byte) (schema.List, error) { + result, err := shared.JSONUnmarshal[schema.List](data) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONschema_List: native ref unwrap; %w", err) + } + return result, nil +} +func (r *ItemGroupedByWindow) _unmarshalJSONPtrWindow(data []byte) (*Window, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONWindow(data) + if err != nil { + return nil, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONPtrWindow: pointer; %w", err) + } + return &result, nil +} +func (r *ItemGroupedByWindow) _unmarshalJSONWindow(data []byte) (Window, error) { + result, err := shared.JSONUnmarshal[Window](data) + if err != nil { + return result, fmt.Errorf("projection: ItemGroupedByWindow._unmarshalJSONWindow: native ref unwrap; %w", err) + } + return result, nil +} diff --git a/x/storage/schemaless/projection/projection_shape_gen.go b/x/storage/schemaless/projection/projection_shape_gen.go new file mode 100644 index 00000000..d3d131de --- /dev/null +++ b/x/storage/schemaless/projection/projection_shape_gen.go @@ -0,0 +1,411 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(DefaultContextShape()) + shape.Register(DoJoinShape()) + shape.Register(DoLoadShape()) + shape.Register(DoMapShape()) + shape.Register(DoWindowShape()) + shape.Register(EventTimeShape()) + shape.Register(ItemGroupedByKeyShape()) + shape.Register(ItemGroupedByWindowShape()) + shape.Register(ItemShape()) + shape.Register(ItemTypeShape()) + shape.Register(MessageShape()) + shape.Register(NodeShape()) + shape.Register(StatsShape()) + shape.Register(WindowShape()) +} + +//shape:shape + +func NodeShape() shape.Shape { + return &shape.UnionLike{ + Name: "Node", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Variant: []shape.Shape{ + DoWindowShape(), + DoMapShape(), + DoLoadShape(), + DoJoinShape(), + }, + } +} + +func DoWindowShape() shape.Shape { + return &shape.StructLike{ + Name: "DoWindow", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Ctx", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "DefaultContext", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + { + Name: "Input", + Type: &shape.RefName{ + Name: "Node", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + } +} + +func DoMapShape() shape.Shape { + return &shape.StructLike{ + Name: "DoMap", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Ctx", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "DefaultContext", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + { + Name: "OnMap", + Type: &shape.RefName{ + Name: "Handler", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + { + Name: "Input", + Type: &shape.RefName{ + Name: "Node", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + } +} + +func DoLoadShape() shape.Shape { + return &shape.StructLike{ + Name: "DoLoad", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Ctx", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "DefaultContext", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + { + Name: "OnLoad", + Type: &shape.RefName{ + Name: "Handler", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + } +} + +func DoJoinShape() shape.Shape { + return &shape.StructLike{ + Name: "DoJoin", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Ctx", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "DefaultContext", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + { + Name: "Input", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Node", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + }, + } +} + +//shape:shape +func DefaultContextShape() shape.Shape { + return &shape.StructLike{ + Name: "DefaultContext", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +//shape:shape +func EventTimeShape() shape.Shape { + return &shape.AliasLike{ + Name: "EventTime", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + IsAlias: true, + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + } +} + +//shape:shape +func ItemShape() shape.Shape { + return &shape.StructLike{ + Name: "Item", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Key", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Data", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + { + Name: "EventTime", + Type: &shape.RefName{ + Name: "EventTime", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + { + Name: "Window", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "Window", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + { + Name: "Type", + Type: &shape.RefName{ + Name: "ItemType", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func WindowShape() shape.Shape { + return &shape.StructLike{ + Name: "Window", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Start", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "End", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + }, + } +} + +//shape:shape +func ItemTypeShape() shape.Shape { + return &shape.AliasLike{ + Name: "ItemType", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.UInt8{}, + }, + }, + } +} + +//shape:shape +func ItemGroupedByKeyShape() shape.Shape { + return &shape.StructLike{ + Name: "ItemGroupedByKey", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Key", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Data", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Item", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func ItemGroupedByWindowShape() shape.Shape { + return &shape.StructLike{ + Name: "ItemGroupedByWindow", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Key", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Data", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "List", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + { + Name: "Window", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "Window", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func MessageShape() shape.Shape { + return &shape.StructLike{ + Name: "Message", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Offset", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + { + Name: "Key", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Item", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "Item", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + { + Name: "Watermark", + Type: &shape.PointerLike{ + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + }, + }, + } +} + +//shape:shape +func StatsShape() shape.Shape { + return &shape.AliasLike{ + Name: "Stats", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + IsAlias: true, + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + } +} diff --git a/x/storage/schemaless/projection/projection_stats_collector.go b/x/storage/schemaless/projection/projection_stats_collector.go new file mode 100644 index 00000000..af2b0fe7 --- /dev/null +++ b/x/storage/schemaless/projection/projection_stats_collector.go @@ -0,0 +1,38 @@ +package projection + +import "sync" + +type StatsCollector interface { + Snapshot() Stats + Incr(key string, increment int) +} + +func NewStatsCollector() *statsCollector { + return &statsCollector{ + stats: Stats{}, + } +} + +var _ StatsCollector = (*statsCollector)(nil) + +type statsCollector struct { + lock sync.Mutex + stats Stats +} + +func (s *statsCollector) Snapshot() Stats { + s.lock.Lock() + defer s.lock.Unlock() + + result := s.stats + s.stats = Stats{} + + return result +} + +func (s *statsCollector) Incr(key string, increment int) { + s.lock.Lock() + defer s.lock.Unlock() + + s.stats[key] += increment +} diff --git a/x/storage/schemaless/projection/projection_test.go b/x/storage/schemaless/projection/projection_test.go new file mode 100644 index 00000000..0a4fa4e3 --- /dev/null +++ b/x/storage/schemaless/projection/projection_test.go @@ -0,0 +1,459 @@ +package projection + +import ( + log "github.com/sirupsen/logrus" + "github.com/widmogrod/mkunion/x/schema" +) + +var generateData []Item + +func init() { + generateData = []Item{ + Item{ + Key: "game:1", + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + Winner: "a", + }), + }, + Item{ + Key: "game:2", + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + Winner: "b", + }), + }, + Item{ + Key: "game:3", + Data: schema.FromGo(Game{ + Players: []string{"a", "b"}, + IsDraw: true, + }), + }, + } +} + +func GenerateData() *GenerateHandler { + return &GenerateHandler{ + Load: func(returning func(message Item)) error { + for _, msg := range generateData { + returning(msg) + } + return nil + }, + } +} + +func MapGameToStats() *MapHandler[Game, SessionsStats] { + return &MapHandler[Game, SessionsStats]{ + F: func(x Game, returning func(key string, value SessionsStats)) error { + for _, player := range x.Players { + wins := 0 + draws := 0 + loose := 0 + + if x.IsDraw { + draws = 1 + } else if x.Winner == player { + wins = 1 + } else { + loose = 1 + } + + returning("session-stats-by-player:"+player, SessionsStats{ + Wins: wins, + Draws: draws, + Loose: loose, + }) + } + + return nil + }, + } +} + +func MergeSessionStats() *MergeHandler[SessionsStats] { + return &MergeHandler[SessionsStats]{ + Combine: func(base, x SessionsStats) (SessionsStats, error) { + return SessionsStats{ + Wins: base.Wins + x.Wins, + Draws: base.Draws + x.Draws, + Loose: base.Loose + x.Loose, + }, nil + }, + DoRetract: func(base, x SessionsStats) (SessionsStats, error) { + panic("retraction on SessionStats should not happen") + }, + } +} + +func CountTotalSessionsStats(b Builder) Builder { + return b. + Map(&MergeHandler[int]{ + Combine: func(base, x int) (int, error) { + log.Debugln("counting(+)", base+x, base, x) + return base + x, nil + }, + DoRetract: func(base int, x int) (int, error) { + log.Debugln("counting(-)", base+x, base, x) + return base - x, nil + }, + }, WithName("CountTotalSessionsStats:Count")) +} + +//func TestProjection(t *testing.T) { +// log.SetLevel(log.DebugLevel) +// log.SetFormatter(&log.TextFormatter{ +// ForceColors: true, +// TimestampFormat: "", +// PadLevelText: true, +// }) +// store := schemaless.NewInMemoryRepository() +// sessionStatsRepo := typedful.NewTypedRepository[SessionsStats](store) +// totalRepo := typedful.NewTypedRepository[int](store) +// +// dag := NewDAGBuilder() +// games := dag. +// DoLoad(GenerateData(), WithName("GenerateData")) +// gameStats := games. +// Window(MapGameToStats(), WithName("MapGameToStats")) +// gameStatsBySession := gameStats. +// DoWindow(MergeSessionStats(), WithName("MergeSessionStats")) +// +// _ = CountTotalSessionsStats(gameStatsBySession). +// Window(NewRepositorySink("total", store), WithName("Sink ⚽️TotalCount")) +// +// _ = gameStatsBySession. +// Window(NewRepositorySink("session", store), WithName("NewRepositorySink")) +// +// interpretation := DefaultInMemoryInterpreter() +// err := interpretation.Run(context.Background(), dag.Build()) +// assert.NoError(t, err) +// +// result, err := sessionStatsRepo.FindingRecords(schemaless.FindingRecords[schemaless.Record[SessionsStats]]{ +// RecordType: "session", +// }) +// assert.NoError(t, err) +// assert.Len(t, result.Items, 2) +// for _, x := range result.Items { +// v, err := schema.ToJSON(schema.FromGo(x.Data)) +// assert.NoError(t, err) +// fmt.Printf("item: id=%s type-%s %s\n", x.ID, x.Type, string(v)) +// } +// +// stats, err := sessionStatsRepo.Get("session-stats-by-player:a", "session") +// assert.NoError(t, err) +// assert.Equal(t, SessionsStats{ +// Wins: 1, +// Loose: 1, +// Draws: 1, +// }, stats.Data) +// +// stats, err = sessionStatsRepo.Get("session-stats-by-player:b", "session") +// assert.NoError(t, err) +// assert.Equal(t, SessionsStats{ +// Wins: 1, +// Loose: 1, +// Draws: 1, +// }, stats.Data) +// +// total, err := totalRepo.Get("total", "total") +// assert.NoError(t, err) +// assert.Equal(t, 2, total.Data) +//} + +//func TestLiveSelect(t *testing.T) { +// log.SetLevel(log.DebugLevel) +// log.SetFormatter(&log.TextFormatter{ +// ForceColors: true, +// TimestampFormat: "", +// PadLevelText: true, +// }) +// +// // setup type registry +// schema.RegisterRules([]schema.RuleMatcher{ +// schema.WhenPath(nil, schema.UseStruct(&schemaless.Record[Game]{})), +// // mkunion should be able to deduce this type +// // todo add this feature! +// schema.WhenPath([]string{"Data"}, schema.UseStruct(Game{})), +// }) +// +// // This is example that is aiming to explore concept of live select. +// // Example use case in context of tic-tac-toe game: +// // - As a player I want to see my stats in session in real time +// // - As a player I want to see tic-tac-toe game updates in real time +// // (I wonder how live select would compete vs current implementation on websockets) +// // - (some other) As a player I want to see achivements, in-game messages, in real time +// // +// // LIVE SELECT +// // sessionID, +// // COUNT_BY_VALUE(winner, WHERE winnerID NOT NULL) as wins, // {"a": 1, "b": 2} +// // COUNT(WHERE isDraw = TRUE) as draws, +// // COUNT() as total +// // GROUP BY sessionID as group +// // WHERE sessionID = :sessionID +// // AND gameState = "GameFinished" +// // +// // Solving live select model with DAG, can solve also MATERIALIZED VIEW problem with ease. +// // +// // At some point it would be nice to have benchmarks that show where is breaking point of +// // doing ad hock live selects vs precalculating materialized view. +// // --- +// // This example works, and there are few things to solve +// // - detect when there is no updates [v] +// // - let's data producer send a signal that it finished, and no frther updates will sent [v] +// // - add watermarking, to detect, what are latest events in system [TODO when there will be windowing] +// // - closing live select, when connection is closed [TODO add context] +// //------------------------------------ +// // - DAG compilation, like loading data from stream, +// // - if steam is Kinesis, there is limit of consumers that can be attached to stream. +// // this means, that when there can be few milion of live select, there will be need to have some other way to DoLoad data to DAG +// // - one way is to have part of DAG to recognise this limitation, and act within limit of kinesis, an have only few consumers +// // that push data to a solution, that can handle millions of lightweight consumers, +// // - RabbitMQ, it's all about topology of messages, few thousen of consumers should be fine +// // - Redis? +// // - In memeory, since DAG for live select is already in memeory, to could be able to route messaged to at lewast few thousend of consumers +// // - if DAG would push message to API Gateway Websocket, then state on one node is not concerned, +// // but what is, is that each node may have some data, and then it will need to re route them to other nodeDAGBuilders to create final aggregate +// // which means that each node needs to have knowladge which node process process which kays ranges +// // +// // - DoLoad node1 +// // - Select repository (Optimise and cache) +// // - Take events related to a filter from stream (steam reads from a partition, so it has olny potion of data) +// // - Window & DoWindow +// // - Push to web socket +// // +// // since every above optimisation would require some kind of cluster, and mitigates some limitations, +// // but since live select is always from a point of time, and later is interested in having only latest data pushes, maybe it make sense +// // to have only data for that window in memory. Then all steam data whenever live select request for it or now, would be computer for recently change data +// // that way, cluster only works for time horizon. Time horizon is smaller than all data, +// // it still could be horizontly scaled, each node would have it's own range of keys +// // +// // Framing problem of live select as select on record with only one element that exists in database (no joins) +// // when connected with RepositoryWithAggregate, solves live select by only working with stream and waiting for updates, no need to past data, only updates +// // that way, select to DynamoDB won't be needed, and thise other otimisations (like caching DAX or Reads from OpenSearch) won't be needed +// // +// // +// // +// // +// //--------------------------------- +// // - optimiastion of DAGs, few edges in line, withotu forks, can be executed in memory, without need of streams between them +// // - what if different partitions needs to merge? like count total, +// // data from different counting nodeDAGBuilders, should be send to one selected node +// // - How to sove such partitioning? would RabbitMQ help or make things harder? +// // - DynamoDB loader, can have information on how many RUs to use, like 5% percent +// // - when system is on production, and there will be more live select DAGs, +// // - loading subset of records from db, may be fine for live select +// // - but what if there will be a lot of new DAGs, that need to process all data fron whole db? +// // my initial assumption, was that DAGs can be lightwaight, so that I can add new forks on runtime, +// // but fork on "joined" will be from zero oldest offset, and may not have data from DB, so it's point in time +// // maybe this means that instead of having easy way of forking, just DAGs can be deployed with full DoLoad from DB +// // since such situation can happen multiple times, that would mean that database needs to be optimised for massive parallel reads +// // +// // Premature optimisation: In context of DDB, this will consume a lot of RCUs, +// // so that could be solved by creating a data (delta) lake on object storage like S3, +// // Where there is DAG that use DDB and stream to keep S3 data up to date, and always with the latest representation +// // +// // Thinking in a way that each DAG is separate deployment, that tracks it's process +// // Means that change is separates, deployments can be separate, scaling needs can be separate, blast radius and ownership as well +// // More teams can work in parallel, and with uniform language of describing DAGs, means that domain concepts can be included as library +// // +// // From that few interesing patterns can happed, (some described in Data Architecture at Scale) +// // - Read-only Data Stores. Sharing read RDS, each team can gen a database that other team has, +// // deployed to their account, and keep up to date by data system (layer) +// // which means, each system, can do reads as much as they can with once proximity to data (different account can be in different geo regions) +// // which means, each system, can share libraries that perform domain specific queries, and those libraries can use RDS in their account +// // which means, that those libraries, can have also catching, and catch layer can be deployed on reader account, +// // +// // How live select architecture can be decomposed? +// // - Fast message and reliable message delivery platform +// // - Fast change detection +// // +// dag := NewDAGBuilder() +// // Only latest records from database that match live select criteria are used +// lastState := dag. +// DoLoad(&GenerateHandler{ +// DoLoad: func(push func(message Item)) error { +// push(Item{ +// Key: "game-1", +// Data: schema.FromGo(schemaless.Record[Game]{ +// ID: "game-1", +// Version: 3, +// Data: Game{ +// SessionID: "session-1", +// Players: []string{"a", "b"}, +// Winner: "a", +// }, +// }), +// }) +// push(Item{ +// Key: "game-2", +// Data: schema.FromGo(schemaless.Record[Game]{ +// ID: "game-2", +// Version: 3, +// Data: Game{ +// SessionID: "session-2", +// Players: []string{"a", "b"}, +// Winner: "a", +// }, +// }), +// }) +// +// return nil +// }, +// }, WithName("DynamoDB LastState Filtered")) +// // Only streamed records that match live select criteria are used +// streamState := dag. +// DoLoad(&GenerateHandler{ +// DoLoad: func(push func(message Item)) error { +// // This is where we would get data from stream +// push(Item{ +// Key: "game-1", +// Data: schema.FromGo(schemaless.Record[Game]{ +// ID: "game-1", +// Version: 2, +// Data: Game{ +// SessionID: "session-1", +// Players: []string{"a", "b"}, +// Winner: "a", +// }, +// }), +// }) +// return nil +// }, +// }, WithName("DynamoDB Filtered Stream")) +// // Joining make sure that newest version is published +// +// joined := dag. +// // DoJoin by key, so if db and stream has the same key, then it will be joined. +// DoJoin(lastState, streamState, WithName("DoJoin")). +// Window(&FilterHandler{ +// Where: predicate.MustWhere( +// "Data.SessionID = :sessionID", +// predicate.ParamBinds{ +// ":sessionID": schema.MkString("session-1"), +// }), +// }). +// // Joining by key and producing a new key is like merging! +// DoWindow(&JoinHandler[schemaless.Record[Game]]{ +// F: func(a, b schemaless.Record[Game], returning func(schemaless.Record[Game])) error { +// if a.Version < b.Version { +// returning(b) +// } +// return nil +// }, +// }) +// +// gameStats := joined. +// Window(Log("gameStats"), WithName("MapGameToStats")). +// Window(&MapHandler[schemaless.Record[Game], SessionsStats]{ +// F: func(x schemaless.Record[Game], returning func(key string, value SessionsStats)) error { +// y := x.Data +// for _, player := range y.Players { +// wins := 0 +// draws := 0 +// loose := 0 +// +// if y.IsDraw { +// draws = 1 +// } else if y.Winner == player { +// wins = 1 +// } else { +// loose = 1 +// } +// +// returning("session-stats-by-player:"+player, SessionsStats{ +// Wins: wins, +// Draws: draws, +// Loose: loose, +// }) +// } +// +// return nil +// }, +// }) +// +// gameStatsBySession := gameStats. +// DoWindow(MergeSessionStats(), WithName("MergeSessionStats")) +// +// //// Storing in database those updates is like creating materialized view +// //// For live select this can be skipped. +// //store := schemaless.NewInMemoryRepository() +// //gameStatsBySession. +// // WithName("Store in database"). +// // Window(NewRepositorySink("session", store), IgnoreRetractions()) +// +// gameStatsBySession. +// Window(Log("publish-web-socket"), WithName("Publish to websocket")) +// //Window(NewWebsocketSink()) +// +// interpretation := DefaultInMemoryInterpreter() +// err := interpretation.Run(context.Background(), dag.Build()) +// assert.NoError(t, err) +//} + +//func TestMergeDifferentInputsTypes(t *testing.T) { +// log.SetLevel(log.DebugLevel) +// log.SetFormatter(&log.TextFormatter{ +// ForceColors: true, +// TimestampFormat: "", +// PadLevelText: true, +// }) +// +// dag := NewDAGBuilder() +// +// ints := dag.DoLoad(&GenerateHandler{ +// DoLoad: func(push func(message Item)) error { +// push(Item{ +// Key: "int-1", +// Data: schema.FromGo(1), +// }) +// return nil +// }, +// }) +// +// strings := dag.DoLoad(&GenerateHandler{ +// DoLoad: func(push func(message Item)) error { +// push(Item{ +// Key: "string-1", +// Data: schema.FromGo("string-1"), +// }) +// return nil +// }, +// }) +// +// _ = dag. +// // Push to the same channel different keys +// DoJoin(ints, strings). +// // Window, don't look at keys, so it can squash them into one +// Window(&MapHandler[any, any]{ +// F: func(x any, returning func(key string, value any)) error { +// switch y := x.(type) { +// case int: +// returning("key", strconv.Itoa(y)) +// case float64: +// returning("key", strconv.FormatFloat(y, 'f', -1, 64)) +// case string: +// returning("key", y) +// default: +// return fmt.Errorf("unknown type %T", x) +// } +// return nil +// }, +// }). +// // DoWindow is always MergeByKey, and since we have only one key, it will merge all incoming data +// DoWindow(&MergeHandler[string]{ +// Combine: func(a, b string) (string, error) { +// return a + b, nil +// }, +// }). +// //Window(&DebounceHandler{ +// // MaxSize: 10, +// // MaxTime: 10 * time.Millisecond, +// //}). +// Window(Log("merged")) +// +// interpretation := DefaultInMemoryInterpreter() +// err := interpretation.Run(context.Background(), dag.Build()) +// assert.NoError(t, err) +//} diff --git a/x/storage/schemaless/projection/projection_union_gen.go b/x/storage/schemaless/projection/projection_union_gen.go new file mode 100644 index 00000000..5766ccba --- /dev/null +++ b/x/storage/schemaless/projection/projection_union_gen.go @@ -0,0 +1,779 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "encoding/json" + "fmt" + "github.com/widmogrod/mkunion/x/shared" +) + +type NodeVisitor interface { + VisitDoWindow(v *DoWindow) any + VisitDoMap(v *DoMap) any + VisitDoLoad(v *DoLoad) any + VisitDoJoin(v *DoJoin) any +} + +type Node interface { + AcceptNode(g NodeVisitor) any +} + +var ( + _ Node = (*DoWindow)(nil) + _ Node = (*DoMap)(nil) + _ Node = (*DoLoad)(nil) + _ Node = (*DoJoin)(nil) +) + +func (r *DoWindow) AcceptNode(v NodeVisitor) any { return v.VisitDoWindow(r) } +func (r *DoMap) AcceptNode(v NodeVisitor) any { return v.VisitDoMap(r) } +func (r *DoLoad) AcceptNode(v NodeVisitor) any { return v.VisitDoLoad(r) } +func (r *DoJoin) AcceptNode(v NodeVisitor) any { return v.VisitDoJoin(r) } + +func MatchNodeR3[T0, T1, T2 any]( + x Node, + f1 func(x *DoWindow) (T0, T1, T2), + f2 func(x *DoMap) (T0, T1, T2), + f3 func(x *DoLoad) (T0, T1, T2), + f4 func(x *DoJoin) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *DoWindow: + return f1(v) + case *DoMap: + return f2(v) + case *DoLoad: + return f3(v) + case *DoJoin: + return f4(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchNodeR2[T0, T1 any]( + x Node, + f1 func(x *DoWindow) (T0, T1), + f2 func(x *DoMap) (T0, T1), + f3 func(x *DoLoad) (T0, T1), + f4 func(x *DoJoin) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *DoWindow: + return f1(v) + case *DoMap: + return f2(v) + case *DoLoad: + return f3(v) + case *DoJoin: + return f4(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchNodeR1[T0 any]( + x Node, + f1 func(x *DoWindow) T0, + f2 func(x *DoMap) T0, + f3 func(x *DoLoad) T0, + f4 func(x *DoJoin) T0, +) T0 { + switch v := x.(type) { + case *DoWindow: + return f1(v) + case *DoMap: + return f2(v) + case *DoLoad: + return f3(v) + case *DoJoin: + return f4(v) + } + var result1 T0 + return result1 +} + +func MatchNodeR0( + x Node, + f1 func(x *DoWindow), + f2 func(x *DoMap), + f3 func(x *DoLoad), + f4 func(x *DoJoin), +) { + switch v := x.(type) { + case *DoWindow: + f1(v) + case *DoMap: + f2(v) + case *DoLoad: + f3(v) + case *DoJoin: + f4(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.Node", NodeFromJSON, NodeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.DoWindow", DoWindowFromJSON, DoWindowToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.DoMap", DoMapFromJSON, DoMapToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.DoLoad", DoLoadFromJSON, DoLoadToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.DoJoin", DoJoinFromJSON, DoJoinToJSON) +} + +type NodeUnionJSON struct { + Type string `json:"$type,omitempty"` + DoWindow json.RawMessage `json:"projection.DoWindow,omitempty"` + DoMap json.RawMessage `json:"projection.DoMap,omitempty"` + DoLoad json.RawMessage `json:"projection.DoLoad,omitempty"` + DoJoin json.RawMessage `json:"projection.DoJoin,omitempty"` +} + +func NodeFromJSON(x []byte) (Node, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data NodeUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "projection.DoWindow": + return DoWindowFromJSON(data.DoWindow) + case "projection.DoMap": + return DoMapFromJSON(data.DoMap) + case "projection.DoLoad": + return DoLoadFromJSON(data.DoLoad) + case "projection.DoJoin": + return DoJoinFromJSON(data.DoJoin) + } + + if data.DoWindow != nil { + return DoWindowFromJSON(data.DoWindow) + } else if data.DoMap != nil { + return DoMapFromJSON(data.DoMap) + } else if data.DoLoad != nil { + return DoLoadFromJSON(data.DoLoad) + } else if data.DoJoin != nil { + return DoJoinFromJSON(data.DoJoin) + } + + return nil, fmt.Errorf("projection.Node: unknown type %s", data.Type) +} + +func NodeToJSON(x Node) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchNodeR2( + x, + func(x *DoWindow) ([]byte, error) { + body, err := DoWindowToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NodeUnionJSON{ + Type: "projection.DoWindow", + DoWindow: body, + }) + }, + func(x *DoMap) ([]byte, error) { + body, err := DoMapToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NodeUnionJSON{ + Type: "projection.DoMap", + DoMap: body, + }) + }, + func(x *DoLoad) ([]byte, error) { + body, err := DoLoadToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NodeUnionJSON{ + Type: "projection.DoLoad", + DoLoad: body, + }) + }, + func(x *DoJoin) ([]byte, error) { + body, err := DoJoinToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(NodeUnionJSON{ + Type: "projection.DoJoin", + DoJoin: body, + }) + }, + ) +} + +func DoWindowFromJSON(x []byte) (*DoWindow, error) { + result := new(DoWindow) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DoWindowToJSON(x *DoWindow) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*DoWindow)(nil) + _ json.Marshaler = (*DoWindow)(nil) +) + +func (r *DoWindow) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDoWindow(*r) +} +func (r *DoWindow) _marshalJSONDoWindow(x DoWindow) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCtx []byte + fieldCtx, err = r._marshalJSONPtrDefaultContext(x.Ctx) + if err != nil { + return nil, fmt.Errorf("projection: DoWindow._marshalJSONDoWindow: field name Ctx; %w", err) + } + if fieldCtx != nil { + partial["Ctx"] = fieldCtx + } + var fieldInput []byte + fieldInput, err = r._marshalJSONNode(x.Input) + if err != nil { + return nil, fmt.Errorf("projection: DoWindow._marshalJSONDoWindow: field name Input; %w", err) + } + partial["Input"] = fieldInput + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: DoWindow._marshalJSONDoWindow: struct; %w", err) + } + return result, nil +} +func (r *DoWindow) _marshalJSONPtrDefaultContext(x *DefaultContext) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONDefaultContext(*x) +} +func (r *DoWindow) _marshalJSONDefaultContext(x DefaultContext) ([]byte, error) { + result, err := shared.JSONMarshal[DefaultContext](x) + if err != nil { + return nil, fmt.Errorf("projection: DoWindow._marshalJSONDefaultContext:; %w", err) + } + return result, nil +} +func (r *DoWindow) _marshalJSONNode(x Node) ([]byte, error) { + result, err := shared.JSONMarshal[Node](x) + if err != nil { + return nil, fmt.Errorf("projection: DoWindow._marshalJSONNode:; %w", err) + } + return result, nil +} +func (r *DoWindow) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDoWindow(data) + if err != nil { + return fmt.Errorf("projection: DoWindow.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *DoWindow) _unmarshalJSONDoWindow(data []byte) (DoWindow, error) { + result := DoWindow{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: DoWindow._unmarshalJSONDoWindow: native struct unwrap; %w", err) + } + if fieldCtx, ok := partial["Ctx"]; ok { + result.Ctx, err = r._unmarshalJSONPtrDefaultContext(fieldCtx) + if err != nil { + return result, fmt.Errorf("projection: DoWindow._unmarshalJSONDoWindow: field Ctx; %w", err) + } + } + if fieldInput, ok := partial["Input"]; ok { + result.Input, err = r._unmarshalJSONNode(fieldInput) + if err != nil { + return result, fmt.Errorf("projection: DoWindow._unmarshalJSONDoWindow: field Input; %w", err) + } + } + return result, nil +} +func (r *DoWindow) _unmarshalJSONPtrDefaultContext(data []byte) (*DefaultContext, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONDefaultContext(data) + if err != nil { + return nil, fmt.Errorf("projection: DoWindow._unmarshalJSONPtrDefaultContext: pointer; %w", err) + } + return &result, nil +} +func (r *DoWindow) _unmarshalJSONDefaultContext(data []byte) (DefaultContext, error) { + result, err := shared.JSONUnmarshal[DefaultContext](data) + if err != nil { + return result, fmt.Errorf("projection: DoWindow._unmarshalJSONDefaultContext: native ref unwrap; %w", err) + } + return result, nil +} +func (r *DoWindow) _unmarshalJSONNode(data []byte) (Node, error) { + result, err := shared.JSONUnmarshal[Node](data) + if err != nil { + return result, fmt.Errorf("projection: DoWindow._unmarshalJSONNode: native ref unwrap; %w", err) + } + return result, nil +} + +func DoMapFromJSON(x []byte) (*DoMap, error) { + result := new(DoMap) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DoMapToJSON(x *DoMap) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*DoMap)(nil) + _ json.Marshaler = (*DoMap)(nil) +) + +func (r *DoMap) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDoMap(*r) +} +func (r *DoMap) _marshalJSONDoMap(x DoMap) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCtx []byte + fieldCtx, err = r._marshalJSONPtrDefaultContext(x.Ctx) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONDoMap: field name Ctx; %w", err) + } + if fieldCtx != nil { + partial["Ctx"] = fieldCtx + } + var fieldOnMap []byte + fieldOnMap, err = r._marshalJSONHandler(x.OnMap) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONDoMap: field name OnMap; %w", err) + } + partial["OnMap"] = fieldOnMap + var fieldInput []byte + fieldInput, err = r._marshalJSONNode(x.Input) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONDoMap: field name Input; %w", err) + } + partial["Input"] = fieldInput + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONDoMap: struct; %w", err) + } + return result, nil +} +func (r *DoMap) _marshalJSONPtrDefaultContext(x *DefaultContext) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONDefaultContext(*x) +} +func (r *DoMap) _marshalJSONDefaultContext(x DefaultContext) ([]byte, error) { + result, err := shared.JSONMarshal[DefaultContext](x) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONDefaultContext:; %w", err) + } + return result, nil +} +func (r *DoMap) _marshalJSONHandler(x Handler) ([]byte, error) { + result, err := shared.JSONMarshal[Handler](x) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONHandler:; %w", err) + } + return result, nil +} +func (r *DoMap) _marshalJSONNode(x Node) ([]byte, error) { + result, err := shared.JSONMarshal[Node](x) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._marshalJSONNode:; %w", err) + } + return result, nil +} +func (r *DoMap) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDoMap(data) + if err != nil { + return fmt.Errorf("projection: DoMap.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *DoMap) _unmarshalJSONDoMap(data []byte) (DoMap, error) { + result := DoMap{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONDoMap: native struct unwrap; %w", err) + } + if fieldCtx, ok := partial["Ctx"]; ok { + result.Ctx, err = r._unmarshalJSONPtrDefaultContext(fieldCtx) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONDoMap: field Ctx; %w", err) + } + } + if fieldOnMap, ok := partial["OnMap"]; ok { + result.OnMap, err = r._unmarshalJSONHandler(fieldOnMap) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONDoMap: field OnMap; %w", err) + } + } + if fieldInput, ok := partial["Input"]; ok { + result.Input, err = r._unmarshalJSONNode(fieldInput) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONDoMap: field Input; %w", err) + } + } + return result, nil +} +func (r *DoMap) _unmarshalJSONPtrDefaultContext(data []byte) (*DefaultContext, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONDefaultContext(data) + if err != nil { + return nil, fmt.Errorf("projection: DoMap._unmarshalJSONPtrDefaultContext: pointer; %w", err) + } + return &result, nil +} +func (r *DoMap) _unmarshalJSONDefaultContext(data []byte) (DefaultContext, error) { + result, err := shared.JSONUnmarshal[DefaultContext](data) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONDefaultContext: native ref unwrap; %w", err) + } + return result, nil +} +func (r *DoMap) _unmarshalJSONHandler(data []byte) (Handler, error) { + result, err := shared.JSONUnmarshal[Handler](data) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONHandler: native ref unwrap; %w", err) + } + return result, nil +} +func (r *DoMap) _unmarshalJSONNode(data []byte) (Node, error) { + result, err := shared.JSONUnmarshal[Node](data) + if err != nil { + return result, fmt.Errorf("projection: DoMap._unmarshalJSONNode: native ref unwrap; %w", err) + } + return result, nil +} + +func DoLoadFromJSON(x []byte) (*DoLoad, error) { + result := new(DoLoad) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DoLoadToJSON(x *DoLoad) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*DoLoad)(nil) + _ json.Marshaler = (*DoLoad)(nil) +) + +func (r *DoLoad) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDoLoad(*r) +} +func (r *DoLoad) _marshalJSONDoLoad(x DoLoad) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCtx []byte + fieldCtx, err = r._marshalJSONPtrDefaultContext(x.Ctx) + if err != nil { + return nil, fmt.Errorf("projection: DoLoad._marshalJSONDoLoad: field name Ctx; %w", err) + } + if fieldCtx != nil { + partial["Ctx"] = fieldCtx + } + var fieldOnLoad []byte + fieldOnLoad, err = r._marshalJSONHandler(x.OnLoad) + if err != nil { + return nil, fmt.Errorf("projection: DoLoad._marshalJSONDoLoad: field name OnLoad; %w", err) + } + partial["OnLoad"] = fieldOnLoad + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: DoLoad._marshalJSONDoLoad: struct; %w", err) + } + return result, nil +} +func (r *DoLoad) _marshalJSONPtrDefaultContext(x *DefaultContext) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONDefaultContext(*x) +} +func (r *DoLoad) _marshalJSONDefaultContext(x DefaultContext) ([]byte, error) { + result, err := shared.JSONMarshal[DefaultContext](x) + if err != nil { + return nil, fmt.Errorf("projection: DoLoad._marshalJSONDefaultContext:; %w", err) + } + return result, nil +} +func (r *DoLoad) _marshalJSONHandler(x Handler) ([]byte, error) { + result, err := shared.JSONMarshal[Handler](x) + if err != nil { + return nil, fmt.Errorf("projection: DoLoad._marshalJSONHandler:; %w", err) + } + return result, nil +} +func (r *DoLoad) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDoLoad(data) + if err != nil { + return fmt.Errorf("projection: DoLoad.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *DoLoad) _unmarshalJSONDoLoad(data []byte) (DoLoad, error) { + result := DoLoad{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: DoLoad._unmarshalJSONDoLoad: native struct unwrap; %w", err) + } + if fieldCtx, ok := partial["Ctx"]; ok { + result.Ctx, err = r._unmarshalJSONPtrDefaultContext(fieldCtx) + if err != nil { + return result, fmt.Errorf("projection: DoLoad._unmarshalJSONDoLoad: field Ctx; %w", err) + } + } + if fieldOnLoad, ok := partial["OnLoad"]; ok { + result.OnLoad, err = r._unmarshalJSONHandler(fieldOnLoad) + if err != nil { + return result, fmt.Errorf("projection: DoLoad._unmarshalJSONDoLoad: field OnLoad; %w", err) + } + } + return result, nil +} +func (r *DoLoad) _unmarshalJSONPtrDefaultContext(data []byte) (*DefaultContext, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONDefaultContext(data) + if err != nil { + return nil, fmt.Errorf("projection: DoLoad._unmarshalJSONPtrDefaultContext: pointer; %w", err) + } + return &result, nil +} +func (r *DoLoad) _unmarshalJSONDefaultContext(data []byte) (DefaultContext, error) { + result, err := shared.JSONUnmarshal[DefaultContext](data) + if err != nil { + return result, fmt.Errorf("projection: DoLoad._unmarshalJSONDefaultContext: native ref unwrap; %w", err) + } + return result, nil +} +func (r *DoLoad) _unmarshalJSONHandler(data []byte) (Handler, error) { + result, err := shared.JSONUnmarshal[Handler](data) + if err != nil { + return result, fmt.Errorf("projection: DoLoad._unmarshalJSONHandler: native ref unwrap; %w", err) + } + return result, nil +} + +func DoJoinFromJSON(x []byte) (*DoJoin, error) { + result := new(DoJoin) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DoJoinToJSON(x *DoJoin) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*DoJoin)(nil) + _ json.Marshaler = (*DoJoin)(nil) +) + +func (r *DoJoin) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDoJoin(*r) +} +func (r *DoJoin) _marshalJSONDoJoin(x DoJoin) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCtx []byte + fieldCtx, err = r._marshalJSONPtrDefaultContext(x.Ctx) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONDoJoin: field name Ctx; %w", err) + } + if fieldCtx != nil { + partial["Ctx"] = fieldCtx + } + var fieldInput []byte + fieldInput, err = r._marshalJSONSliceNode(x.Input) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONDoJoin: field name Input; %w", err) + } + partial["Input"] = fieldInput + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONDoJoin: struct; %w", err) + } + return result, nil +} +func (r *DoJoin) _marshalJSONPtrDefaultContext(x *DefaultContext) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONDefaultContext(*x) +} +func (r *DoJoin) _marshalJSONDefaultContext(x DefaultContext) ([]byte, error) { + result, err := shared.JSONMarshal[DefaultContext](x) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONDefaultContext:; %w", err) + } + return result, nil +} +func (r *DoJoin) _marshalJSONSliceNode(x []Node) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONNode(v) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONSliceNode: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONSliceNode:; %w", err) + } + return result, nil +} +func (r *DoJoin) _marshalJSONNode(x Node) ([]byte, error) { + result, err := shared.JSONMarshal[Node](x) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._marshalJSONNode:; %w", err) + } + return result, nil +} +func (r *DoJoin) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDoJoin(data) + if err != nil { + return fmt.Errorf("projection: DoJoin.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *DoJoin) _unmarshalJSONDoJoin(data []byte) (DoJoin, error) { + result := DoJoin{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONDoJoin: native struct unwrap; %w", err) + } + if fieldCtx, ok := partial["Ctx"]; ok { + result.Ctx, err = r._unmarshalJSONPtrDefaultContext(fieldCtx) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONDoJoin: field Ctx; %w", err) + } + } + if fieldInput, ok := partial["Input"]; ok { + result.Input, err = r._unmarshalJSONSliceNode(fieldInput) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONDoJoin: field Input; %w", err) + } + } + return result, nil +} +func (r *DoJoin) _unmarshalJSONPtrDefaultContext(data []byte) (*DefaultContext, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONDefaultContext(data) + if err != nil { + return nil, fmt.Errorf("projection: DoJoin._unmarshalJSONPtrDefaultContext: pointer; %w", err) + } + return &result, nil +} +func (r *DoJoin) _unmarshalJSONDefaultContext(data []byte) (DefaultContext, error) { + result, err := shared.JSONUnmarshal[DefaultContext](data) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONDefaultContext: native ref unwrap; %w", err) + } + return result, nil +} +func (r *DoJoin) _unmarshalJSONSliceNode(data []byte) ([]Node, error) { + result := make([]Node, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONSliceNode: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONNode(v) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONSliceNode: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *DoJoin) _unmarshalJSONNode(data []byte) (Node, error) { + result, err := shared.JSONUnmarshal[Node](data) + if err != nil { + return result, fmt.Errorf("projection: DoJoin._unmarshalJSONNode: native ref unwrap; %w", err) + } + return result, nil +} diff --git a/x/storage/schemaless/projection/pub_sub.go b/x/storage/schemaless/projection/pub_sub.go new file mode 100644 index 00000000..a7fbe298 --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub.go @@ -0,0 +1,182 @@ +package projection + +import ( + "container/list" + "context" + "errors" + "fmt" + "sync" +) + +func NewPubSub[T comparable]() *PubSub[T] { + lock := sync.RWMutex{} + return &PubSub[T]{ + lock: &lock, + cond: sync.NewCond(lock.RLocker()), + publisher: make(map[T]*list.List), + } +} + +var _ PubSubForInterpreter[any] = (*PubSub[any])(nil) + +type PubSub[T comparable] struct { + lock *sync.RWMutex + cond *sync.Cond + publisher map[T]*list.List +} + +var ( + ErrNoPublisher = errors.New("no appendLog") + ErrFinished = errors.New("appendLog is finished") + ErrContextDone = errors.New("context is done") + ErrHandlerReturnErr = errors.New("handler returned error") + ErrPublishWithOffset = errors.New("cannot publish message with offset") +) + +func (p *PubSub[T]) Register(key T) error { + //log.Errorf("pubsub.registerRec(%s)\n", GetCtx(any(key).(Node)).name) + p.lock.Lock() + defer p.lock.Unlock() + //if _, ok := p.finished[key]; ok { + // return fmt.Errorf("pubsub.registerRec: key=%#v %w", key, ErrFinished) + //} + + if _, ok := p.publisher[key]; !ok { + p.publisher[key] = list.New() + } else { + //log.Errorf("pubsub.registerRec(%s) ALREADY\n", GetCtx(any(key).(Node)).name) + } + + if last := p.publisher[key].Back(); last != nil { + if last.Value.(Message).finished { + return fmt.Errorf("pubsub.registerRec: key=%#v %w", key, ErrFinished) + } + } + + p.cond.Broadcast() + + return nil +} + +// Publish should return error, and not throw panic +// this is a temporary solution, for prototyping +func (p *PubSub[T]) Publish(ctx context.Context, key T, msg Message) error { + select { + case <-ctx.Done(): + return fmt.Errorf("pubsub.Publish: key=%#v ctx=%s %w", key, ctx.Err(), ErrContextDone) + default: + // continue + } + + //log.Errorf("pubsub.Publish(%s)\n", GetCtx(any(key).(Node)).name) + if msg.Offset != 0 { + return fmt.Errorf("pubsub.Publish: key=%#v %w", key, ErrPublishWithOffset) + } + + p.lock.Lock() + defer p.lock.Unlock() + //if _, ok := p.finished[key]; ok { + // return fmt.Errorf("pubsub.Publish: key=%#v %w", key, ErrFinished) + //} + + if _, ok := p.publisher[key]; !ok { + p.publisher[key] = list.New() + } + + if last := p.publisher[key].Back(); last != nil { + if last.Value.(Message).finished { + return fmt.Errorf("pubsub.Publish: key=%#v %w", key, ErrFinished) + } + } + + msg.Offset = p.publisher[key].Len() + p.publisher[key].PushBack(msg) + p.cond.Broadcast() + return nil +} + +// Finish is called when a node won't publish any more messages +func (p *PubSub[T]) Finish(ctx context.Context, key T) { + err := p.Publish(ctx, key, Message{ + finished: true, + }) + if err != nil { + panic(err) + } + //log.Errorf("pubsub.Finish(%s)\n", GetCtx(any(key).(Node)).name) + //p.lock.Lock() + //p.finished[key] = true + //p.lock.Unlock() + // + //p.cond.Broadcast() +} + +//TODO: refactor PubSub and Kinesis to share as much as they can! + +func (p *PubSub[T]) Subscribe(ctx context.Context, node T, fromOffset int, f func(Message) error) error { + p.lock.RLock() + appendLog, ok := p.publisher[node] + if !ok { + p.lock.RUnlock() + return ErrNoPublisher + } + p.lock.RUnlock() + + var prev *list.Element = nil + + // Until, there is no messages, wait + p.cond.L.Lock() + for appendLog.Len() == 0 { + p.cond.Wait() + } + + // Select the offset to start reading messages from + switch fromOffset { + case 0: + prev = appendLog.Front() + case -1: + prev = appendLog.Back() + default: + for e := appendLog.Front(); e != nil; e = e.Next() { + prev = e + if e.Value.(Message).Offset == fromOffset { + break + } + } + + if prev == appendLog.Back() { + p.cond.L.Unlock() + return errors.New("offset not found") + } + } + p.cond.L.Unlock() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("pubsub.Subscribe %s %w", ctx.Err(), ErrContextDone) + + default: + msg := prev.Value.(Message) + if msg.finished { + //log.Errorf("pubsub.Subscribe END(%s)\n", GetCtx(any(node).(Node)).name) + return nil + } + + //log.Errorf("pubsub.Subscribe CALL (%s)\n", GetCtx(any(node).(Node)).name) + err := f(msg) + if err != nil { + return fmt.Errorf("pubsub.Subscribe %s %w", err, ErrHandlerReturnErr) + } + + // Wait for new changes to be available + p.cond.L.Lock() + for prev.Next() == nil { + p.cond.Wait() + } + + prev = prev.Next() + p.cond.L.Unlock() + } + } +} diff --git a/x/storage/schemaless/projection/pub_sub_chan.go b/x/storage/schemaless/projection/pub_sub_chan.go new file mode 100644 index 00000000..d0d7a825 --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_chan.go @@ -0,0 +1,169 @@ +package projection + +import ( + "fmt" + log "github.com/sirupsen/logrus" + "github.com/widmogrod/mkunion/x/shared" + "sync" + "sync/atomic" +) + +type subscriber[T any] struct { + inputs chan T + f func(T) error + done chan error + once sync.Once + processOnce sync.Once + finished chan struct{} +} + +func (s *subscriber[T]) Close() { + s.CloseWithErr(nil) +} + +func (s *subscriber[T]) CloseWithErr(err error) { + s.once.Do(func() { + // close inputs channel to signal that no more messages will be sent + close(s.inputs) + + // wait for all background invocations to finish + <-s.finished + close(s.finished) + + // send potential error to done channel + s.done <- err + close(s.done) + }) +} + +func (s *subscriber[T]) Process() { + s.processOnce.Do(func() { + for msg := range s.inputs { + if s.Invoke(msg) { + break + } + } + + s.finished <- struct{}{} + }) +} + +func (s *subscriber[T]) Invoke(msg T) bool { + err := s.f(msg) + if err != nil { + s.CloseWithErr(err) + return true + } + return false +} + +func NewPubSubChan[T any]() *PubSubChan[T] { + return &PubSubChan[T]{ + lock: &sync.RWMutex{}, + channel: make(chan T, 1000), + subscribers: nil, + + closed: make(chan struct{}), + } +} + +type PubSubChan[T any] struct { + lock *sync.RWMutex + channel chan T + subscribers []*subscriber[T] + isClosed atomic.Bool + once sync.Once + + closed chan struct{} +} + +func (s *PubSubChan[T]) Publish(msg T) error { + if msg2, ok := any(msg).(Message); ok { + if msg2.finished { + s.Close() + return nil + } + } + + if s.isClosed.Load() { + return fmt.Errorf("PubSubChan.Publish: channel is closed %w", ErrFinished) + } + s.channel <- msg + return nil +} + +func (s *PubSubChan[T]) Process() { + var length int + + defer func() { + s.lock.RLock() + for _, sub := range s.subscribers { + sub.Close() + } + s.lock.RUnlock() + + s.closed <- struct{}{} + }() + + for msg := range s.channel { + s.lock.RLock() + + length = len(s.subscribers) + switch length { + case 0: + data, _ := shared.JSONMarshal[any](msg) + log.Warn("PubSubChan.Process: no subscribers but get message: ", + length, ",", string(data)) + + // optimisation, when there is only one subscriber, we can invoke it directly + case 1: + s.subscribers[0].Invoke(msg) + default: + for _, sub := range s.subscribers { + sub.inputs <- msg + } + } + s.lock.RUnlock() + } +} + +func (s *PubSubChan[T]) Subscribe(f func(T) error) error { + if s.isClosed.Load() { + return fmt.Errorf("PubSubChan.Subscribe: channel is closed %w", ErrFinished) + } + + sub := &subscriber[T]{ + f: f, + done: make(chan error), + inputs: make(chan T, 1000), + finished: make(chan struct{}), + } + + go sub.Process() + + s.lock.Lock() + s.subscribers = append(s.subscribers, sub) + s.lock.Unlock() + + err := <-sub.done + + s.lock.Lock() + newSubscribers := make([]*subscriber[T], 0, len(s.subscribers)-1) + for _, su := range s.subscribers { + if su != sub { + newSubscribers = append(newSubscribers, sub) + } + } + s.subscribers = newSubscribers + s.lock.Unlock() + + return err +} + +func (s *PubSubChan[T]) Close() { + s.once.Do(func() { + s.isClosed.Store(true) + close(s.channel) + <-s.closed + }) +} diff --git a/x/storage/schemaless/projection/pub_sub_chan_test.go b/x/storage/schemaless/projection/pub_sub_chan_test.go new file mode 100644 index 00000000..7411c2c8 --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_chan_test.go @@ -0,0 +1,34 @@ +package projection + +import ( + "errors" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestPubSubChan(t *testing.T) { + psc := NewPubSubChan[string]() + go psc.Process() + + var err = errors.New("foo") + + done := make(chan struct{}) + + started := make(chan struct{}) + go func() { + defer close(done) + started <- struct{}{} + defer close(started) + err2 := psc.Subscribe(func(msg string) error { + assert.Equal(t, "foo", msg) + return err + }) + assert.Error(t, err2, err) + }() + <-started + + err3 := psc.Publish("foo") + assert.NoError(t, err3) + + <-done +} diff --git a/x/storage/schemaless/projection/pub_sub_key_partitioned.go b/x/storage/schemaless/projection/pub_sub_key_partitioned.go new file mode 100644 index 00000000..f1ffccad --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_key_partitioned.go @@ -0,0 +1,3 @@ +package projection + +// To enable diff --git a/x/storage/schemaless/projection/pub_sub_key_partitioned_test.go b/x/storage/schemaless/projection/pub_sub_key_partitioned_test.go new file mode 100644 index 00000000..aae89b07 --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_key_partitioned_test.go @@ -0,0 +1,87 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestChan(t *testing.T) { + x := make(chan int, 10) + x <- 1 + x <- 2 + x <- 3 + close(x) + + counter := 0 + for range x { + counter++ + } + + assert.Equal(t, 3, counter) +} + +//func TestPartitionedPubSub(t *testing.T) { +// queue := NewPartitionedQueue() +// +// for i := 0; i < 100; i++ { +// queue.Publish(Item{ +// Key: fmt.Sprintf("key-%d", i%10), +// Data: schema.MkInt(i), +// EventTime: 0, +// Window: 0, +// finished: false, +// }) +// } +// +// // operations on queue should result in Window or DoWindow operations per key group +// // Window and DoWindow should be executed in parallel +// +// mappedQueue := NewPartitionedQueue() +// +// var mapWorkers = 3 +// var mapped = make(chan *Item) +// queue.Subscribe(func(i *Item) { +// mapped <- i +// }) +// +// for i := 0; i < mapWorkers; i++ { +// go TryMap(mapped, mappedQueue) +// } +// +// var groups = make(map[string]chan Item) +// var newGroups = make(chan string) +// queue.Subscribe(func(i *Item) { +// if _, ok := groups[i.Key]; !ok { +// groups[i.Key] = make(chan Item) +// newGroups <- i.Key +// } +// +// groups[i.Key] <- *i +// }) +// +// // when subscription is closed, all groups should be closed +// // and all groups should be merged +// +// for group := range newGroups { +// go func(group string) { +// TryMerge(groups[group]) +// }(group) +// } +// +//} +// +//func TryMerge(items chan Item) { +// for { +// v1, ok1 := <-items +// v2, ok2 := <-items +// +// if !ok1 || !ok2 { +// if ok1 { +// fmt.Printf("v1: %v \n", v1) +// } else if ok2 { +// fmt.Printf("v2: %v \n", v2) +// } +// break +// } +// } +//} diff --git a/x/storage/schemaless/projection/pub_sub_multi.go b/x/storage/schemaless/projection/pub_sub_multi.go new file mode 100644 index 00000000..5f44e776 --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_multi.go @@ -0,0 +1,120 @@ +package projection + +import ( + "context" + "fmt" + log "github.com/sirupsen/logrus" + "sync" +) + +func NewPubSubMultiChan[T comparable]() *PubSubMulti[T] { + return &PubSubMulti[T]{ + multi: make(map[T]PubSubSingler[Message]), + onces: make(map[T]*sync.Once), + lock: &sync.RWMutex{}, + new: func() PubSubSingler[Message] { + return NewPubSubChan[Message]() + }, + finished: make(map[T]bool), + } +} + +type PubSubSingler[T comparable] interface { + Publish(msg T) error + Process() + Subscribe(f func(T) error) error + Close() +} + +var _ PubSubForInterpreter[any] = (*PubSubMulti[any])(nil) + +type PubSubMulti[T comparable] struct { + multi map[T]PubSubSingler[Message] + onces map[T]*sync.Once + lock *sync.RWMutex + new func() PubSubSingler[Message] + finished map[T]bool +} + +func (p *PubSubMulti[T]) Register(key T) error { + p.lock.Lock() + defer p.lock.Unlock() + + if _, ok := p.multi[key]; ok { + return nil + //return fmt.Errorf("PubSubMulti.registerRec: key %s already registered", key) + } + + p.multi[key] = p.new() + //go p.multi[key].Process() + p.onces[key] = &sync.Once{} + + return nil +} + +func (p *PubSubMulti[T]) Publish(ctx context.Context, key T, msg Message) error { + log.Debugf("PublishMulti: key=%v msg=%v", key, msg) + select { + case <-ctx.Done(): + return fmt.Errorf("PubSubMulti.Publish: key=%#v ctx=%s %w", key, ctx.Err(), ErrContextDone) + default: + // continue + } + + if msg.Offset != 0 { + return fmt.Errorf("PubSubMulti.Publish: key=%#v %w", key, ErrPublishWithOffset) + } + + p.lock.RLock() + if _, ok := p.finished[key]; ok { + p.lock.RUnlock() + return fmt.Errorf("PubSubMulti.Publish: key=%#v %w", key, ErrFinished) + } + p.lock.RUnlock() + + if _, ok := p.multi[key]; !ok { + return fmt.Errorf("PubSubMulti.Publish: key=%#v not registered", key) + } + + p.onces[key].Do(func() { + go p.multi[key].Process() + }) + + return p.multi[key].Publish(msg) +} + +func (p *PubSubMulti[T]) Finish(ctx context.Context, key T) { + err := p.Publish(ctx, key, Message{finished: true}) + if err != nil { + panic(err) + } + p.lock.Lock() + p.finished[key] = true + p.lock.Unlock() + + //p.multi[key].Close() +} + +func (p *PubSubMulti[T]) Subscribe(ctx context.Context, key T, fromOffset int, f func(Message) error) error { + select { + case <-ctx.Done(): + return fmt.Errorf("PubSubMulti.Subscribe %s %w", ctx.Err(), ErrContextDone) + default: + } + + p.lock.RLock() + if _, ok := p.finished[key]; ok { + p.lock.RUnlock() + return fmt.Errorf("PubSubMulti.Subscribe: key=%#v %w", key, ErrFinished) + } + p.lock.RUnlock() + + p.lock.RLock() + if _, ok := p.multi[key]; !ok { + p.lock.RUnlock() + return fmt.Errorf("PubSubMulti.Subscribe: key %T not registered", key) + } + p.lock.RUnlock() + + return p.multi[key].Subscribe(f) +} diff --git a/x/storage/schemaless/projection/pub_sub_single.go b/x/storage/schemaless/projection/pub_sub_single.go new file mode 100644 index 00000000..bde84d1a --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_single.go @@ -0,0 +1,122 @@ +package projection + +import ( + "container/list" + "context" + "errors" + "fmt" + "sync" +) + +func NewPubSubSingle() *PubSubSingle { + lock := sync.RWMutex{} + return &PubSubSingle{ + lock: &lock, + cond: sync.NewCond(lock.RLocker()), + appendLog: list.New(), + finished: false, + } +} + +type PubSubSingle struct { + lock *sync.RWMutex + cond *sync.Cond + appendLog *list.List + finished bool +} + +func (p *PubSubSingle) Publish(ctx context.Context, msg Message) error { + select { + case <-ctx.Done(): + return fmt.Errorf("pubsubsingle.Publish: ctx=%s %w", ctx.Err(), ErrContextDone) + default: + // continue + } + + if msg.Offset != 0 { + return fmt.Errorf("pubsubsingle.Publish: %w", ErrPublishWithOffset) + } + + p.lock.Lock() + defer p.lock.Unlock() + if p.finished { + return fmt.Errorf("pubsubsingle.Publish: %w", ErrFinished) + } + + msg.Offset = p.appendLog.Len() + p.appendLog.PushBack(msg) + p.cond.Broadcast() + return nil +} + +// Finish is called when a node won't publish any more messages +func (p *PubSubSingle) Finish() { + p.lock.Lock() + p.finished = true + p.lock.Unlock() + + p.cond.Broadcast() +} + +func (p *PubSubSingle) Subscribe(ctx context.Context, fromOffset int, f func(Message) error) error { + var prev *list.Element = nil + + // Until, there is no messages, wait + p.cond.L.Lock() + for p.appendLog.Len() == 0 && !p.finished { + p.cond.Wait() + } + if p.appendLog.Len() == 0 && p.finished { + p.cond.L.Unlock() + return nil + } + + // Select the offset to start reading messages from + switch fromOffset { + case 0: + prev = p.appendLog.Front() + case -1: + prev = p.appendLog.Back() + default: + for e := p.appendLog.Front(); e != nil; e = e.Next() { + prev = e + if e.Value.(Message).Offset == fromOffset { + break + } + } + + if prev == p.appendLog.Back() { + p.cond.L.Unlock() + return errors.New("offset not found") + } + } + p.cond.L.Unlock() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("pubsubsingle.Subscribe %s %w", ctx.Err(), ErrContextDone) + + default: + msg := prev.Value.(Message) + + err := f(msg) + if err != nil { + return fmt.Errorf("pubsubsingle.Subscribe %s %w", err, ErrHandlerReturnErr) + } + + // Wait for new changes to be available + p.cond.L.Lock() + for prev.Next() == nil && !p.finished { + p.cond.Wait() + } + if prev.Next() == nil && p.finished { + p.cond.L.Unlock() + return nil + } + + prev = prev.Next() + p.cond.L.Unlock() + } + } +} diff --git a/x/storage/schemaless/projection/pub_sub_single_test.go b/x/storage/schemaless/projection/pub_sub_single_test.go new file mode 100644 index 00000000..7261615c --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_single_test.go @@ -0,0 +1,30 @@ +package projection + +import ( + "context" + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestPusSubSingle(t *testing.T) { + pss := NewPubSubSingle() + err := pss.Publish(context.Background(), Message{ + Key: "foo", + Item: &Item{ + Key: "foo", + Data: schema.FromGo("foo"), + EventTime: 0, + }, + }) + assert.NoError(t, err) + + pss.Finish() + + err = pss.Subscribe(context.Background(), 0, func(msg Message) error { + assert.Equal(t, "foo", msg.Key) + return nil + }) + assert.NoError(t, err) + +} diff --git a/x/storage/schemaless/projection/pub_sub_test.go b/x/storage/schemaless/projection/pub_sub_test.go new file mode 100644 index 00000000..2e887b6c --- /dev/null +++ b/x/storage/schemaless/projection/pub_sub_test.go @@ -0,0 +1,85 @@ +package projection + +import ( + "context" + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "testing" +) + +func TestPubSubTest_Subscribe(t *testing.T) { + ctx := context.TODO() + + n := &DoLoad{} + msg := Message{ + Offset: 0, + Key: "123", + Item: &Item{ + Key: "321", + Data: schema.FromGo(1), + }, + Watermark: nil, + } + msg2 := Message{ + Offset: 0, + Key: "312", + Item: &Item{ + Key: "sdadfad", + Data: schema.FromGo(2), + }, + Watermark: nil, + } + + pubsub := NewPubSub[Node]() + err := pubsub.Publish(ctx, n, Message{ + Offset: 123, + }) + assert.ErrorIs(t, err, ErrPublishWithOffset) + + err = pubsub.Publish(ctx, n, msg) + assert.NoError(t, err) + err = pubsub.Publish(ctx, n, msg2) + assert.NoError(t, err) + + assertCalled := func() func(result Message) error { + order := 0 + + asserts := []Message{msg, msg2} + + return func(result Message) error { + defer func() { order++ }() + + if order >= len(asserts) { + assert.Fail(t, "should not receive message", result) + } else { + assert.Equal(t, asserts[order].Item, result.Item) + assert.Equal(t, asserts[order].Watermark, result.Watermark) + } + + return nil + } + } + + // when producing is not marked as finished, Subcribe3 will wait for messages + // we need to run it in a goroutine + done := make(chan struct{}) + go func() { + err := pubsub.Subscribe(context.Background(), n, 0, assertCalled()) + assert.NoError(t, err) + done <- struct{}{} + }() + + // but when we mark it as finished, it should return + pubsub.Finish(context.Background(), n) + err = pubsub.Publish(ctx, n, msg) + assert.Error(t, err, ErrFinished) + err = pubsub.Register(n) + assert.Error(t, err, ErrFinished) + + // Consuming from finished producer must be possible + err = pubsub.Subscribe(ctx, n, 0, assertCalled()) + assert.NoError(t, err) + + <-done + close(done) +} diff --git a/x/storage/schemaless/projection/registry_funcion.go b/x/storage/schemaless/projection/registry_funcion.go new file mode 100644 index 00000000..2b0dfadb --- /dev/null +++ b/x/storage/schemaless/projection/registry_funcion.go @@ -0,0 +1,53 @@ +package projection + +//type FunctionID string +// +//var ( +// ErrFunctionNotFound = fmt.Errorf("function not found") +// ErrFunctionExists = fmt.Errorf("function already exists") +//) +// +//type ( +// FunctionRegistry struct { +// function map[FunctionID]Handler +// } +//) +// +//func (r *FunctionRegistry) Get(id FunctionID) (Handler, error) { +// if h, ok := r.function[id]; ok { +// return h, nil +// } +// return nil, fmt.Errorf("%w id=%s", ErrFunctionNotFound, id) +//} +// +//var defaultFunctionRegistry = &FunctionRegistry{ +// function: map[FunctionID]Handler{}, +//} +// +//func DefaultFunctionRegistry() *FunctionRegistry { +// return defaultFunctionRegistry +//} +// +//func WithFunction(id FunctionID, handler Handler) (FunctionID, error) { +// if _, ok := defaultFunctionRegistry.function[id]; ok { +// return "", fmt.Errorf("%w id=%s", ErrFunctionExists, id) +// } +// defaultFunctionRegistry.function[id] = handler +// return id, nil +//} +// +//func MustFunction(id FunctionID, handler Handler) FunctionID { +// res, err := WithFunction(id, handler) +// if err != nil { +// panic(err) +// } +// return res +//} +// +//func MustRetrieveFunction(id FunctionID) Handler { +// res, err := defaultFunctionRegistry.Get(id) +// if err != nil { +// panic(err) +// } +// return res +//} diff --git a/x/storage/schemaless/projection/sink_repository.go b/x/storage/schemaless/projection/sink_repository.go new file mode 100644 index 00000000..efc20160 --- /dev/null +++ b/x/storage/schemaless/projection/sink_repository.go @@ -0,0 +1,114 @@ +package projection + +import ( + log "github.com/sirupsen/logrus" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/storage/schemaless" + "sync" + "time" +) + +func NewRepositorySink(recordType string, store schemaless.Repository[schema.Schema]) *RepositorySink { + sink := &RepositorySink{ + flushWhenBatchSize: 0, + flushWhenDuration: 1 * time.Second, + + store: store, + recordType: recordType, + + bufferSaving: map[string]schemaless.Record[schema.Schema]{}, + bufferDeleting: map[string]schemaless.Record[schema.Schema]{}, + } + + // TODO consider to move it outside, for explicit managment + // or make hooks on records, that will wait for flush + sink.FlushOnTime() + + return sink +} + +type RepositorySink struct { + lock sync.Mutex + + flushWhenBatchSize int + flushWhenDuration time.Duration + + bufferSaving map[string]schemaless.Record[schema.Schema] + bufferDeleting map[string]schemaless.Record[schema.Schema] + + store schemaless.Repository[schema.Schema] + recordType string +} + +func (s *RepositorySink) FlushOnTime() { + go func() { + ticker := time.NewTicker(s.flushWhenDuration) + for range ticker.C { + s.flush() + } + }() +} + +func (s *RepositorySink) Process(x Item, returning func(Item)) error { + s.lock.Lock() + s.bufferSaving[x.Key] = schemaless.Record[schema.Schema]{ + ID: x.Key, + Type: s.recordType, + Data: x.Data, + Version: 0, + } + s.lock.Unlock() + if len(s.bufferSaving)+len(s.bufferDeleting) >= s.flushWhenBatchSize { + return s.flush() + } + + return nil +} + +func (s *RepositorySink) Retract(x Item, returning func(Item)) error { + s.lock.Lock() + s.bufferDeleting[x.Key] = schemaless.Record[schema.Schema]{ + ID: x.Key, + Type: s.recordType, + Data: x.Data, + Version: 0, + } + s.lock.Unlock() + + if len(s.bufferSaving)+len(s.bufferDeleting) >= s.flushWhenBatchSize { + return s.flush() + } + + return nil +} + +func (s *RepositorySink) flush() error { + s.lock.Lock() + defer s.lock.Unlock() + + if len(s.bufferSaving)+len(s.bufferDeleting) == 0 { + log.Debugln("nothing to flush") + return nil + } + + err := s.store.UpdateRecords(schemaless.UpdateRecords[schemaless.Record[schema.Schema]]{ + UpdatingPolicy: schemaless.PolicyOverwriteServerChanges, + Saving: s.bufferSaving, + Deleting: s.bufferDeleting, + }) + if err != nil { + return err + } + log.Debugln("flushed:") + for id, record := range s.bufferSaving { + log.Debugln("- saved", id, record) + } + for id, record := range s.bufferDeleting { + log.Debugln("- deleted", id, record) + } + + s.bufferSaving = map[string]schemaless.Record[schema.Schema]{} + s.bufferDeleting = map[string]schemaless.Record[schema.Schema]{} + + return nil +} diff --git a/x/storage/schemaless/projection/triggering.go b/x/storage/schemaless/projection/triggering.go new file mode 100644 index 00000000..792a749d --- /dev/null +++ b/x/storage/schemaless/projection/triggering.go @@ -0,0 +1,473 @@ +package projection + +import ( + "errors" + "fmt" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/shared" + "sync" + "time" +) + +//go:generate go run ../../../../cmd/mkunion/main.go + +// go:generate mkunion -name=TriggerType -variants=AtPeriod,AtWindowItemSize,AtWatermark +// +//go:tag mkunion:"TriggerType" +type ( + AtPeriod1 = AtPeriod + AtWindowItemSize1 = AtWindowItemSize + AtWatermark1 = AtWatermark +) + +//go:tag mkunion:"TriggerDescription" +type ( + AtPeriod struct { + Duration time.Duration + } + AtWindowItemSize struct { + Number int + } + AtWatermark struct { + Timestamp int64 + } + AnyOf struct { + Triggers []TriggerDescription + } + AllOf struct { + Triggers []TriggerDescription + } +) + +//go:tag mkunion:"WindowFlushMode" +type ( + Accumulate struct { + AllowLateArrival time.Duration + } + Discard struct{} + AccumulatingAndRetracting struct { + AllowLateArrival time.Duration + } +) + +type TriggerHandler struct { + //wd WindowDescription + td TriggerDescription + + wb *WindowBuffer + + wts BagOf[*WindowTrigger] + + lock sync.Mutex +} + +var _ Handler = (*TriggerHandler)(nil) + +func printTrigger(triggerType TriggerType) { + MatchTriggerTypeR0( + triggerType, + func(x *AtPeriod) { + fmt.Printf("AtPeriod(%v)", x.Duration) + + }, + func(x *AtWindowItemSize) { + fmt.Printf("AtWindowItemSize(%v)", x.Number) + }, + func(x *AtWatermark) { + fmt.Printf("AtWatermark()") + }) +} + +func (tm *TriggerHandler) Triggered(trigger TriggerType, returning func(Item)) error { + tm.lock.Lock() + defer tm.lock.Unlock() + + tm.wb.EachItemGroupedByWindow(func(group *ItemGroupedByWindow) { + wt, err := tm.wts.Get(WindowKey(group.Window)) + isError := err != nil && err != NotFound + isFound := err == nil + + if isError { + panic(err) + } + + if !isFound { + wt = NewWindowTrigger(group.Window, tm.td) + err = tm.wts.Set(WindowKey(group.Window), wt) + if err != nil { + panic(err) + } + } + + wt.ReceiveEvent(trigger) + wt.ReceiveEvent(&AtWindowItemSize{Number: len(*group.Data)}) + + if wt.ShouldTrigger() { + returning(ToElement(group)) + tm.wb.RemoveItemGropedByWindow(group) + wt.Reset() + } + }) + + return nil +} + +func (tm *TriggerHandler) Process(x Item, returning func(Item)) error { + tm.lock.Lock() + tm.wb.Append(x) + tm.lock.Unlock() + return tm.Triggered(&AtWindowItemSize{Number: -1}, returning) +} + +func (tm *TriggerHandler) Retract(x Item, returning func(Item)) error { + panic("implement me") +} + +var NotFound = errors.New("not found") + +type BagOf[A any] interface { + Set(key string, value A) error + Get(key string) (A, error) + Del(key string) error + Range(f func(key string, item A)) +} + +var _ BagOf[any] = (*InMemoryBagOf[any])(nil) + +type InMemoryBagOf[A any] struct { + m map[string]A +} + +func NewInMemoryBagOf[A any]() *InMemoryBagOf[A] { + return &InMemoryBagOf[A]{ + m: make(map[string]A), + } +} + +func (b *InMemoryBagOf[A]) Set(key string, value A) error { + b.m[key] = value + return nil +} + +func (b *InMemoryBagOf[A]) Get(key string) (A, error) { + if value, ok := b.m[key]; ok { + return value, nil + } + + var a A + return a, NotFound +} + +func (b *InMemoryBagOf[A]) Del(key string) error { + delete(b.m, key) + return nil +} + +func (b *InMemoryBagOf[A]) Range(f func(key string, item A)) { + for k, v := range b.m { + f(k, v) + } +} + +type AccumulateDiscardRetractHandler struct { + fm WindowFlushMode + mapf Handler + mergef Handler + + bag BagOf[Item] +} + +var _ Handler = (*AccumulateDiscardRetractHandler)(nil) + +func printItem(x Item, sx ...string) { + data, _ := shared.JSONMarshal[schema.Schema](x.Data) + fmt.Println(fmt.Sprintf("Item(%v)", sx), x.Key, x.Window, string(data), x.EventTime) +} + +func (a *AccumulateDiscardRetractHandler) Process(x Item, returning func(Item)) error { + return MatchWindowFlushModeR1( + a.fm, + func(y *Accumulate) error { + key := KeyedWindowKey(ToKeyedWindowFromItem(&x)) + previous, err := a.bag.Get(key) + + isError := err != nil && err != NotFound + isFound := err == nil + if isError { + panic(err) + } + + if isFound { + return a.mapf.Process(x, func(item Item) { + z := Item{ + Key: item.Key, + Window: item.Window, + Data: schema.MkList( + previous.Data, + item.Data, + ), + EventTime: item.EventTime, + } + + err := a.mergef.Process(z, func(item Item) { + err := a.bag.Set(key, item) + if err != nil { + panic(err) + } + + returning(item) + }) + if err != nil { + panic(err) + } + }) + } + + return a.mapf.Process(x, func(item Item) { + err := a.bag.Set(key, item) + if err != nil { + panic(err) + } + returning(item) + }) + }, + func(y *Discard) error { + return a.mapf.Process(x, returning) + }, + func(y *AccumulatingAndRetracting) error { + key := KeyedWindowKey(ToKeyedWindowFromItem(&x)) + previous, err := a.bag.Get(key) + isError := err != nil && err != NotFound + isFound := err == nil + if isError { + panic(err) + } + + if isFound { + return a.mapf.Process(x, func(item Item) { + z := Item{ + Key: item.Key, + Window: item.Window, + Data: schema.MkList( + previous.Data, + item.Data, + ), + EventTime: item.EventTime, + } + + err := a.mergef.Process(z, func(newAggregate Item) { + err := a.bag.Set(key, newAggregate) + if err != nil { + panic(err) + } + + // operation is in one messages, as one or nothing principle + // which will help in transactional systems. + returning(Item{ + Key: newAggregate.Key, + Data: PackRetractAndAggregate( + previous.Data, + newAggregate.Data, + ), + EventTime: newAggregate.EventTime, + Window: newAggregate.Window, + Type: ItemRetractAndAggregate, + }) + }) + if err != nil { + panic(err) + } + }) + } + + return a.mapf.Process(x, func(item Item) { + err := a.bag.Set(key, item) + if err != nil { + panic(err) + } + returning(item) // emit aggregate + }) + }, + ) +} + +func (a *AccumulateDiscardRetractHandler) Retract(x Item, returning func(Item)) error { + //TODO implement me + panic("implement me") +} + +type ( + WindowBufferSignaler interface { + SignalWindowCreated(kw *KeyedWindow) + SignalWindowDeleted(kw *KeyedWindow) + SignalWindowSizeReached(kw *KeyedWindow, size int) + } + + WatermarkSignaler interface { + SignalWatermark(timestamp int64) + } + + TimeSignaler interface { + SignalDuration(duration time.Duration) + } +) + +func NewTriggerManager(td TriggerDescription) *TriggerManager { + tm := &TriggerManager{ + td: td, + windowTriggers: NewInMemoryBagOf[*WindowTrigger](), + keyedWindows: NewInMemoryBagOf[*KeyedWindow](), + } + + return tm +} + +type TriggerManager struct { + td TriggerDescription + + windowTriggers BagOf[*WindowTrigger] + keyedWindows BagOf[*KeyedWindow] + + triggerWindow func(w *KeyedWindow) +} + +var _ WindowBufferSignaler = (*TriggerManager)(nil) +var _ WatermarkSignaler = (*TriggerManager)(nil) +var _ TimeSignaler = (*TriggerManager)(nil) + +func (tm *TriggerManager) SignalWindowCreated(kw *KeyedWindow) { + err := tm.windowTriggers.Set(KeyedWindowKey(kw), NewWindowTrigger(kw.Window, tm.td)) + if err != nil { + panic(err) + } + err = tm.keyedWindows.Set(KeyedWindowKey(kw), kw) + if err != nil { + panic(err) + } +} + +func (tm *TriggerManager) SignalWindowDeleted(kw *KeyedWindow) { + err := tm.windowTriggers.Del(KeyedWindowKey(kw)) + if err != nil { + panic(err) + } + err = tm.keyedWindows.Del(KeyedWindowKey(kw)) + if err != nil { + panic(err) + } +} + +func (tm *TriggerManager) SignalWindowSizeReached(kw *KeyedWindow, size int) { + wt, err := tm.windowTriggers.Get(KeyedWindowKey(kw)) + if err != nil { + panic(err) + } + + wt.ReceiveEvent(&AtWindowItemSize{ + Number: size, + }) + if wt.ShouldTrigger() { + tm.triggerWindow(kw) + wt.Reset() + } +} + +func (tm *TriggerManager) WhenTrigger(f func(w *KeyedWindow)) { + if tm.triggerWindow != nil { + panic("trigger window already set") + } + + tm.triggerWindow = f +} + +func (tm *TriggerManager) SignalDuration(duration time.Duration) { + tm.windowTriggers.Range(func(key string, wt *WindowTrigger) { + wt.ReceiveEvent(&AtPeriod{ + Duration: duration, + }) + if wt.ShouldTrigger() { + kw, err := tm.keyedWindows.Get(key) + if err != nil { + panic(err) + } + tm.triggerWindow(kw) + wt.Reset() + } + }) +} + +func (tm *TriggerManager) SignalWatermark(timestamp int64) { + tm.windowTriggers.Range(func(key string, wt *WindowTrigger) { + wt.ReceiveEvent(&AtWatermark{ + Timestamp: timestamp, + }) + if wt.ShouldTrigger() { + kw, err := tm.keyedWindows.Get(key) + if err != nil { + panic(err) + } + tm.triggerWindow(kw) + wt.Reset() + } + }) +} + +func NewTimeTicker() *Tickers { + return &Tickers{ + tickers: map[TriggerDescription]*time.Ticker{}, + } +} + +type Tickers struct { + tickers map[TriggerDescription]*time.Ticker +} + +func (t *Tickers) Register(td TriggerDescription, ts TimeSignaler) { + MatchTriggerDescriptionR0( + td, + func(x *AtPeriod) { + go func() { + t.tickers[td] = time.NewTicker(x.Duration) + for range t.tickers[td].C { + ts.SignalDuration(x.Duration) + } + }() + }, + func(x *AtWindowItemSize) {}, + func(x *AtWatermark) {}, + func(x *AnyOf) { + for _, td := range x.Triggers { + t.Register(td, ts) + } + }, + func(x *AllOf) { + for _, td := range x.Triggers { + t.Register(td, ts) + } + }, + ) +} + +func (t *Tickers) Unregister(td TriggerDescription) { + MatchTriggerDescriptionR0( + td, + func(x *AtPeriod) { + if ticker, ok := t.tickers[td]; ok { + ticker.Stop() + delete(t.tickers, td) + } + }, + func(x *AtWindowItemSize) {}, + func(x *AtWatermark) {}, + func(x *AnyOf) { + for _, td := range x.Triggers { + t.Unregister(td) + } + }, + func(x *AllOf) { + for _, td := range x.Triggers { + t.Unregister(td) + } + }, + ) +} diff --git a/x/storage/schemaless/projection/triggering_shape_gen.go b/x/storage/schemaless/projection/triggering_shape_gen.go new file mode 100644 index 00000000..c902a0f6 --- /dev/null +++ b/x/storage/schemaless/projection/triggering_shape_gen.go @@ -0,0 +1,306 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(AccumulateDiscardRetractHandlerShape()) + shape.Register(AccumulateShape()) + shape.Register(AccumulatingAndRetractingShape()) + shape.Register(AllOfShape()) + shape.Register(AnyOfShape()) + shape.Register(AtPeriod1Shape()) + shape.Register(AtPeriodShape()) + shape.Register(AtWatermark1Shape()) + shape.Register(AtWatermarkShape()) + shape.Register(AtWindowItemSize1Shape()) + shape.Register(AtWindowItemSizeShape()) + shape.Register(DiscardShape()) + shape.Register(InMemoryBagOfShape()) + shape.Register(TickersShape()) + shape.Register(TriggerDescriptionShape()) + shape.Register(TriggerHandlerShape()) + shape.Register(TriggerManagerShape()) + shape.Register(TriggerTypeShape()) + shape.Register(WindowFlushModeShape()) +} + +//shape:shape + +func TriggerDescriptionShape() shape.Shape { + return &shape.UnionLike{ + Name: "TriggerDescription", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Variant: []shape.Shape{ + AtPeriodShape(), + AtWindowItemSizeShape(), + AtWatermarkShape(), + AnyOfShape(), + AllOfShape(), + }, + } +} + +func AtPeriodShape() shape.Shape { + return &shape.StructLike{ + Name: "AtPeriod", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Duration", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + }, + } +} + +func AtWindowItemSizeShape() shape.Shape { + return &shape.StructLike{ + Name: "AtWindowItemSize", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Number", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + }, + } +} + +func AtWatermarkShape() shape.Shape { + return &shape.StructLike{ + Name: "AtWatermark", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Timestamp", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + }, + } +} + +func AnyOfShape() shape.Shape { + return &shape.StructLike{ + Name: "AnyOf", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Triggers", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "TriggerDescription", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + }, + } +} + +func AllOfShape() shape.Shape { + return &shape.StructLike{ + Name: "AllOf", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Triggers", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "TriggerDescription", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + }, + } +} + +//shape:shape + +func TriggerTypeShape() shape.Shape { + return &shape.UnionLike{ + Name: "TriggerType", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Variant: []shape.Shape{ + AtPeriod1Shape(), + AtWindowItemSize1Shape(), + AtWatermark1Shape(), + }, + } +} + +func AtPeriod1Shape() shape.Shape { + return &shape.AliasLike{ + Name: "AtPeriod1", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + IsAlias: true, + Type: &shape.RefName{ + Name: "AtPeriod", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + } +} + +func AtWindowItemSize1Shape() shape.Shape { + return &shape.AliasLike{ + Name: "AtWindowItemSize1", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + IsAlias: true, + Type: &shape.RefName{ + Name: "AtWindowItemSize", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + } +} + +func AtWatermark1Shape() shape.Shape { + return &shape.AliasLike{ + Name: "AtWatermark1", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + IsAlias: true, + Type: &shape.RefName{ + Name: "AtWatermark", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + } +} + +//shape:shape + +func WindowFlushModeShape() shape.Shape { + return &shape.UnionLike{ + Name: "WindowFlushMode", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Variant: []shape.Shape{ + AccumulateShape(), + DiscardShape(), + AccumulatingAndRetractingShape(), + }, + } +} + +func AccumulateShape() shape.Shape { + return &shape.StructLike{ + Name: "Accumulate", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "AllowLateArrival", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + }, + } +} + +func DiscardShape() shape.Shape { + return &shape.StructLike{ + Name: "Discard", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +func AccumulatingAndRetractingShape() shape.Shape { + return &shape.StructLike{ + Name: "AccumulatingAndRetracting", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "AllowLateArrival", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + }, + } +} + +//shape:shape +func AccumulateDiscardRetractHandlerShape() shape.Shape { + return &shape.StructLike{ + Name: "AccumulateDiscardRetractHandler", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +//shape:shape +func InMemoryBagOfShape() shape.Shape { + return &shape.StructLike{ + Name: "InMemoryBagOf", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + } +} + +//shape:shape +func TickersShape() shape.Shape { + return &shape.StructLike{ + Name: "Tickers", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +//shape:shape +func TriggerHandlerShape() shape.Shape { + return &shape.StructLike{ + Name: "TriggerHandler", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +//shape:shape +func TriggerManagerShape() shape.Shape { + return &shape.StructLike{ + Name: "TriggerManager", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} diff --git a/x/storage/schemaless/projection/triggering_test.go b/x/storage/schemaless/projection/triggering_test.go new file mode 100644 index 00000000..7fc441a7 --- /dev/null +++ b/x/storage/schemaless/projection/triggering_test.go @@ -0,0 +1,362 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "math" + "os" + "testing" + "time" +) + +func TestTriggers(t *testing.T) { + if os.Getenv("RUN_EXPERIMENTAL_TEST") == "false" { + t.Skip(`Skipping test because: +- RUN_EXPERIMENTAL_TEST=false is set. +`) + } + + useCases := map[string]struct { + td TriggerDescription + wd WindowDescription + fm WindowFlushMode + expected []Item + }{ + "should trigger window emitting once at period 100ms, and 10 items arrives as 1 item": { + td: &AllOf{ + Triggers: []TriggerDescription{ + &AtPeriod{ + Duration: 100 * time.Millisecond, + }, + &AtWatermark{}, + }, + }, + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + fm: &Discard{}, + expected: []Item{ + { + Key: "key", + Data: schema.MkList( + schema.MkInt(0), schema.MkInt(1), schema.MkInt(2), schema.MkInt(3), schema.MkInt(4), + schema.MkInt(5), schema.MkInt(6), schema.MkInt(7), schema.MkInt(8), schema.MkInt(9), + ), + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + { + Key: "key", + Data: schema.MkList( + schema.MkInt(10), schema.MkInt(11), schema.MkInt(12), schema.MkInt(13), schema.MkInt(14), + schema.MkInt(15), schema.MkInt(16), schema.MkInt(17), schema.MkInt(18), + // it should fit in 100ms window, but due timeouts being part of process time, not event time, + // it's not guaranteed that when system will receive event at 10.1s, it will be processed at 10.2s + schema.MkInt(19), + ), + EventTime: withTime(10, 0) + (200 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0) + (100 * int64(time.Millisecond)), + End: withTime(10, 0) + (200 * int64(time.Millisecond)), + }, + }, + }, + }, + "should trigger window emitting when window size reach 2 item": { + td: &AtWindowItemSize{ + Number: 2, + }, + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + fm: &Discard{}, + expected: []Item{ + { + Key: "key", + Data: schema.MkList( + schema.MkInt(0), schema.MkInt(1), + ), + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + { + Key: "key", + Data: schema.MkList( + schema.MkInt(2), schema.MkInt(3), + ), + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + { + Key: "key", + Data: schema.MkList( + schema.MkInt(4), schema.MkInt(5), + ), + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + }, + }, + "should trigger window flush at watermark": { + td: &AtWatermark{}, + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + fm: &Discard{}, + expected: []Item{ + { + Key: "key", + Data: schema.MkList( + schema.MkInt(0), schema.MkInt(1), schema.MkInt(2), schema.MkInt(3), schema.MkInt(4), + schema.MkInt(5), schema.MkInt(6), schema.MkInt(7), schema.MkInt(8), schema.MkInt(9), + ), + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + }, + }, + } + for name, uc := range useCases { + t.Run(name, func(t *testing.T) { + returning := &ListAssert{t: t} + + trigger := NewTriggerManager(uc.td) + + timeTickers := NewTimeTicker() + timeTickers.Register(uc.td, trigger) + defer timeTickers.Unregister(uc.td) + + wb := NewWindowBuffer(uc.wd, trigger) + + trigger.WhenTrigger(func(kw *KeyedWindow) { + wb.EachKeyedWindow(kw, func(group *ItemGroupedByWindow) { + returning.Returning(ToElement(group)) + wb.RemoveItemGropedByWindow(group) + }) + }) + + for item := range GenerateItemsEvery(withTime(10, 0), 20, 10*time.Millisecond) { + wb.Append(item) + } + + // trigger watermark that there won't be any more events + trigger.SignalWatermark(math.MaxInt64) + + time.Sleep(100 * time.Millisecond) + for i, expected := range uc.expected { + returning.AssertAt(i, expected) + } + }) + } +} + +func TestAggregate(t *testing.T) { + if os.Getenv("RUN_EXPERIMENTAL_TEST") == "false" { + t.Skip(`Skipping test because: +- RUN_EXPERIMENTAL_TEST=false is set. +`) + } + + // arithmetic sum of series 0..9, 10..19, 0 .. 19 + // 45, 145, 190 + useCases := map[string]struct { + td TriggerDescription + wd WindowDescription + fm WindowFlushMode + expected []Item + }{ + "should trigger window emitting evey period 100ms, and 10 items arrives as 1 item, late arrivals are new aggregations": { + td: &AtPeriod{ + Duration: 100 * time.Millisecond, + }, + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + fm: &Discard{}, + expected: []Item{ + { + Key: "key", + Data: schema.MkInt(45), // arithmetic sum fo series 0..9 + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + { + Key: "key", + Data: schema.MkInt(126), + EventTime: withTime(10, 0) + (200 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0) + (100 * int64(time.Millisecond)), + End: withTime(10, 0) + (200 * int64(time.Millisecond)), + }, + }, + }, + }, + "should trigger window emitting evey period 100ms, and 10 items arrives as 1 item, late arrivals use past aggregation as base": { + td: &AtPeriod{ + Duration: 100 * time.Millisecond, + }, + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + fm: &Accumulate{}, + expected: []Item{ + { + Key: "key", + Data: schema.MkInt(45), // arithmetic sum fo series 0..9 + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + }, + // this window is incomplete, and will be remitted + { + Key: "key", + Data: schema.MkInt(126), + EventTime: withTime(10, 0) + (200 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0) + (100 * int64(time.Millisecond)), + End: withTime(10, 0) + (200 * int64(time.Millisecond)), + }, + }, + // here is complete aggregation in effect. + { + Key: "key", + Data: schema.MkInt(145), // arithmetic sum of series 10..19 + EventTime: withTime(10, 0) + (200 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0) + (100 * int64(time.Millisecond)), + End: withTime(10, 0) + (200 * int64(time.Millisecond)), + }, + }, + }, + }, + "should trigger window emitting every period 100ms, and 10 items arrives as 1 item, late arrivals use past aggregation as base, and retract last change": { + td: &AtPeriod{ + Duration: 100 * time.Millisecond, + }, + wd: &FixedWindow{ + Width: 100 * time.Millisecond, + }, + fm: &AccumulatingAndRetracting{}, + expected: []Item{ + { + Key: "key", + Data: schema.MkInt(45), // arithmetic sum fo series 0..9 + EventTime: withTime(10, 0) + (100 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 0) + (100 * int64(time.Millisecond)), + }, + Type: ItemAggregation, + }, + // this window is incomplete, and will be remitted + { + Key: "key", + Data: schema.MkInt(126), + EventTime: withTime(10, 0) + (200 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0) + (100 * int64(time.Millisecond)), + End: withTime(10, 0) + (200 * int64(time.Millisecond)), + }, + Type: ItemAggregation, + }, + // here is retracting and aggregate in effect. + { + Key: "key", + Data: PackRetractAndAggregate( + schema.MkInt(126), // retract previous + schema.MkInt(145), // aggregate new + ), + EventTime: withTime(10, 0) + (200 * int64(time.Millisecond)), + Window: &Window{ + Start: withTime(10, 0) + (100 * int64(time.Millisecond)), + End: withTime(10, 0) + (200 * int64(time.Millisecond)), + }, + Type: ItemRetractAndAggregate, + }, + }, + }, + } + for name, uc := range useCases { + t.Run(name, func(t *testing.T) { + returning := &ListAssert{t: t} + + trigger := NewTriggerManager(uc.td) + + timeTickers := NewTimeTicker() + timeTickers.Register(uc.td, trigger) + defer timeTickers.Unregister(uc.td) + + wb := NewWindowBuffer(uc.wd, trigger) + + handler2 := &AccumulateDiscardRetractHandler{ + fm: uc.fm, + mapf: &SimpleProcessHandler{ + P: func(item Item, returning func(Item)) error { + returning(Item{ + Key: item.Key, + Data: schema.MkInt(schema.Reduce[int64]( + item.Data, + 0, + func(s schema.Schema, i int64) int64 { + x, err := schema.ToGoG[float64](s) + if err != nil { + panic(err) + } + return int64(x) + i + }, + )), + EventTime: item.EventTime, + Window: item.Window, + }) + return nil + }}, + mergef: &MergeHandler[int]{ + Combine: func(a, b int) (int, error) { + return a + b, nil + }, + }, + bag: NewInMemoryBagOf[Item](), + } + + trigger.WhenTrigger(func(kw *KeyedWindow) { + wb.EachKeyedWindow(kw, func(group *ItemGroupedByWindow) { + err := handler2.Process(ToElement(group), returning.Returning) + assert.NoError(t, err) + wb.RemoveItemGropedByWindow(group) + }) + }) + + for item := range GenerateItemsEvery(withTime(10, 0), 20, 10*time.Millisecond) { + wb.Append(item) + } + + // trigger watermark that there won't be any more events + trigger.SignalWatermark(math.MaxInt64) + + time.Sleep(100 * time.Millisecond) + for i, expected := range uc.expected { + returning.AssertAt(i, expected) + } + }) + } +} diff --git a/x/storage/schemaless/projection/triggering_union_gen.go b/x/storage/schemaless/projection/triggering_union_gen.go new file mode 100644 index 00000000..276c7dc0 --- /dev/null +++ b/x/storage/schemaless/projection/triggering_union_gen.go @@ -0,0 +1,1348 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "encoding/json" + "fmt" + "github.com/widmogrod/mkunion/x/shared" + "time" +) + +type TriggerDescriptionVisitor interface { + VisitAtPeriod(v *AtPeriod) any + VisitAtWindowItemSize(v *AtWindowItemSize) any + VisitAtWatermark(v *AtWatermark) any + VisitAnyOf(v *AnyOf) any + VisitAllOf(v *AllOf) any +} + +type TriggerDescription interface { + AcceptTriggerDescription(g TriggerDescriptionVisitor) any +} + +var ( + _ TriggerDescription = (*AtPeriod)(nil) + _ TriggerDescription = (*AtWindowItemSize)(nil) + _ TriggerDescription = (*AtWatermark)(nil) + _ TriggerDescription = (*AnyOf)(nil) + _ TriggerDescription = (*AllOf)(nil) +) + +func (r *AtPeriod) AcceptTriggerDescription(v TriggerDescriptionVisitor) any { + return v.VisitAtPeriod(r) +} +func (r *AtWindowItemSize) AcceptTriggerDescription(v TriggerDescriptionVisitor) any { + return v.VisitAtWindowItemSize(r) +} +func (r *AtWatermark) AcceptTriggerDescription(v TriggerDescriptionVisitor) any { + return v.VisitAtWatermark(r) +} +func (r *AnyOf) AcceptTriggerDescription(v TriggerDescriptionVisitor) any { return v.VisitAnyOf(r) } +func (r *AllOf) AcceptTriggerDescription(v TriggerDescriptionVisitor) any { return v.VisitAllOf(r) } + +func MatchTriggerDescriptionR3[T0, T1, T2 any]( + x TriggerDescription, + f1 func(x *AtPeriod) (T0, T1, T2), + f2 func(x *AtWindowItemSize) (T0, T1, T2), + f3 func(x *AtWatermark) (T0, T1, T2), + f4 func(x *AnyOf) (T0, T1, T2), + f5 func(x *AllOf) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *AtPeriod: + return f1(v) + case *AtWindowItemSize: + return f2(v) + case *AtWatermark: + return f3(v) + case *AnyOf: + return f4(v) + case *AllOf: + return f5(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchTriggerDescriptionR2[T0, T1 any]( + x TriggerDescription, + f1 func(x *AtPeriod) (T0, T1), + f2 func(x *AtWindowItemSize) (T0, T1), + f3 func(x *AtWatermark) (T0, T1), + f4 func(x *AnyOf) (T0, T1), + f5 func(x *AllOf) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *AtPeriod: + return f1(v) + case *AtWindowItemSize: + return f2(v) + case *AtWatermark: + return f3(v) + case *AnyOf: + return f4(v) + case *AllOf: + return f5(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchTriggerDescriptionR1[T0 any]( + x TriggerDescription, + f1 func(x *AtPeriod) T0, + f2 func(x *AtWindowItemSize) T0, + f3 func(x *AtWatermark) T0, + f4 func(x *AnyOf) T0, + f5 func(x *AllOf) T0, +) T0 { + switch v := x.(type) { + case *AtPeriod: + return f1(v) + case *AtWindowItemSize: + return f2(v) + case *AtWatermark: + return f3(v) + case *AnyOf: + return f4(v) + case *AllOf: + return f5(v) + } + var result1 T0 + return result1 +} + +func MatchTriggerDescriptionR0( + x TriggerDescription, + f1 func(x *AtPeriod), + f2 func(x *AtWindowItemSize), + f3 func(x *AtWatermark), + f4 func(x *AnyOf), + f5 func(x *AllOf), +) { + switch v := x.(type) { + case *AtPeriod: + f1(v) + case *AtWindowItemSize: + f2(v) + case *AtWatermark: + f3(v) + case *AnyOf: + f4(v) + case *AllOf: + f5(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.TriggerDescription", TriggerDescriptionFromJSON, TriggerDescriptionToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AtPeriod", AtPeriodFromJSON, AtPeriodToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AtWindowItemSize", AtWindowItemSizeFromJSON, AtWindowItemSizeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AtWatermark", AtWatermarkFromJSON, AtWatermarkToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AnyOf", AnyOfFromJSON, AnyOfToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AllOf", AllOfFromJSON, AllOfToJSON) +} + +type TriggerDescriptionUnionJSON struct { + Type string `json:"$type,omitempty"` + AtPeriod json.RawMessage `json:"projection.AtPeriod,omitempty"` + AtWindowItemSize json.RawMessage `json:"projection.AtWindowItemSize,omitempty"` + AtWatermark json.RawMessage `json:"projection.AtWatermark,omitempty"` + AnyOf json.RawMessage `json:"projection.AnyOf,omitempty"` + AllOf json.RawMessage `json:"projection.AllOf,omitempty"` +} + +func TriggerDescriptionFromJSON(x []byte) (TriggerDescription, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data TriggerDescriptionUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "projection.AtPeriod": + return AtPeriodFromJSON(data.AtPeriod) + case "projection.AtWindowItemSize": + return AtWindowItemSizeFromJSON(data.AtWindowItemSize) + case "projection.AtWatermark": + return AtWatermarkFromJSON(data.AtWatermark) + case "projection.AnyOf": + return AnyOfFromJSON(data.AnyOf) + case "projection.AllOf": + return AllOfFromJSON(data.AllOf) + } + + if data.AtPeriod != nil { + return AtPeriodFromJSON(data.AtPeriod) + } else if data.AtWindowItemSize != nil { + return AtWindowItemSizeFromJSON(data.AtWindowItemSize) + } else if data.AtWatermark != nil { + return AtWatermarkFromJSON(data.AtWatermark) + } else if data.AnyOf != nil { + return AnyOfFromJSON(data.AnyOf) + } else if data.AllOf != nil { + return AllOfFromJSON(data.AllOf) + } + + return nil, fmt.Errorf("projection.TriggerDescription: unknown type %s", data.Type) +} + +func TriggerDescriptionToJSON(x TriggerDescription) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchTriggerDescriptionR2( + x, + func(x *AtPeriod) ([]byte, error) { + body, err := AtPeriodToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerDescriptionUnionJSON{ + Type: "projection.AtPeriod", + AtPeriod: body, + }) + }, + func(x *AtWindowItemSize) ([]byte, error) { + body, err := AtWindowItemSizeToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerDescriptionUnionJSON{ + Type: "projection.AtWindowItemSize", + AtWindowItemSize: body, + }) + }, + func(x *AtWatermark) ([]byte, error) { + body, err := AtWatermarkToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerDescriptionUnionJSON{ + Type: "projection.AtWatermark", + AtWatermark: body, + }) + }, + func(x *AnyOf) ([]byte, error) { + body, err := AnyOfToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerDescriptionUnionJSON{ + Type: "projection.AnyOf", + AnyOf: body, + }) + }, + func(x *AllOf) ([]byte, error) { + body, err := AllOfToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerDescriptionUnionJSON{ + Type: "projection.AllOf", + AllOf: body, + }) + }, + ) +} + +func AtPeriodFromJSON(x []byte) (*AtPeriod, error) { + result := new(AtPeriod) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AtPeriodToJSON(x *AtPeriod) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AtPeriod)(nil) + _ json.Marshaler = (*AtPeriod)(nil) +) + +func (r *AtPeriod) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAtPeriod(*r) +} +func (r *AtPeriod) _marshalJSONAtPeriod(x AtPeriod) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldDuration []byte + fieldDuration, err = r._marshalJSONtime_Duration(x.Duration) + if err != nil { + return nil, fmt.Errorf("projection: AtPeriod._marshalJSONAtPeriod: field name Duration; %w", err) + } + partial["Duration"] = fieldDuration + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AtPeriod._marshalJSONAtPeriod: struct; %w", err) + } + return result, nil +} +func (r *AtPeriod) _marshalJSONtime_Duration(x time.Duration) ([]byte, error) { + result, err := shared.JSONMarshal[time.Duration](x) + if err != nil { + return nil, fmt.Errorf("projection: AtPeriod._marshalJSONtime_Duration:; %w", err) + } + return result, nil +} +func (r *AtPeriod) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAtPeriod(data) + if err != nil { + return fmt.Errorf("projection: AtPeriod.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AtPeriod) _unmarshalJSONAtPeriod(data []byte) (AtPeriod, error) { + result := AtPeriod{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AtPeriod._unmarshalJSONAtPeriod: native struct unwrap; %w", err) + } + if fieldDuration, ok := partial["Duration"]; ok { + result.Duration, err = r._unmarshalJSONtime_Duration(fieldDuration) + if err != nil { + return result, fmt.Errorf("projection: AtPeriod._unmarshalJSONAtPeriod: field Duration; %w", err) + } + } + return result, nil +} +func (r *AtPeriod) _unmarshalJSONtime_Duration(data []byte) (time.Duration, error) { + result, err := shared.JSONUnmarshal[time.Duration](data) + if err != nil { + return result, fmt.Errorf("projection: AtPeriod._unmarshalJSONtime_Duration: native ref unwrap; %w", err) + } + return result, nil +} + +func AtWindowItemSizeFromJSON(x []byte) (*AtWindowItemSize, error) { + result := new(AtWindowItemSize) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AtWindowItemSizeToJSON(x *AtWindowItemSize) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AtWindowItemSize)(nil) + _ json.Marshaler = (*AtWindowItemSize)(nil) +) + +func (r *AtWindowItemSize) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAtWindowItemSize(*r) +} +func (r *AtWindowItemSize) _marshalJSONAtWindowItemSize(x AtWindowItemSize) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldNumber []byte + fieldNumber, err = r._marshalJSONint(x.Number) + if err != nil { + return nil, fmt.Errorf("projection: AtWindowItemSize._marshalJSONAtWindowItemSize: field name Number; %w", err) + } + partial["Number"] = fieldNumber + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AtWindowItemSize._marshalJSONAtWindowItemSize: struct; %w", err) + } + return result, nil +} +func (r *AtWindowItemSize) _marshalJSONint(x int) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: AtWindowItemSize._marshalJSONint:; %w", err) + } + return result, nil +} +func (r *AtWindowItemSize) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAtWindowItemSize(data) + if err != nil { + return fmt.Errorf("projection: AtWindowItemSize.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AtWindowItemSize) _unmarshalJSONAtWindowItemSize(data []byte) (AtWindowItemSize, error) { + result := AtWindowItemSize{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AtWindowItemSize._unmarshalJSONAtWindowItemSize: native struct unwrap; %w", err) + } + if fieldNumber, ok := partial["Number"]; ok { + result.Number, err = r._unmarshalJSONint(fieldNumber) + if err != nil { + return result, fmt.Errorf("projection: AtWindowItemSize._unmarshalJSONAtWindowItemSize: field Number; %w", err) + } + } + return result, nil +} +func (r *AtWindowItemSize) _unmarshalJSONint(data []byte) (int, error) { + var result int + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: AtWindowItemSize._unmarshalJSONint: native primitive unwrap; %w", err) + } + return result, nil +} + +func AtWatermarkFromJSON(x []byte) (*AtWatermark, error) { + result := new(AtWatermark) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AtWatermarkToJSON(x *AtWatermark) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AtWatermark)(nil) + _ json.Marshaler = (*AtWatermark)(nil) +) + +func (r *AtWatermark) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAtWatermark(*r) +} +func (r *AtWatermark) _marshalJSONAtWatermark(x AtWatermark) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldTimestamp []byte + fieldTimestamp, err = r._marshalJSONint64(x.Timestamp) + if err != nil { + return nil, fmt.Errorf("projection: AtWatermark._marshalJSONAtWatermark: field name Timestamp; %w", err) + } + partial["Timestamp"] = fieldTimestamp + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AtWatermark._marshalJSONAtWatermark: struct; %w", err) + } + return result, nil +} +func (r *AtWatermark) _marshalJSONint64(x int64) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("projection: AtWatermark._marshalJSONint64:; %w", err) + } + return result, nil +} +func (r *AtWatermark) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAtWatermark(data) + if err != nil { + return fmt.Errorf("projection: AtWatermark.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AtWatermark) _unmarshalJSONAtWatermark(data []byte) (AtWatermark, error) { + result := AtWatermark{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AtWatermark._unmarshalJSONAtWatermark: native struct unwrap; %w", err) + } + if fieldTimestamp, ok := partial["Timestamp"]; ok { + result.Timestamp, err = r._unmarshalJSONint64(fieldTimestamp) + if err != nil { + return result, fmt.Errorf("projection: AtWatermark._unmarshalJSONAtWatermark: field Timestamp; %w", err) + } + } + return result, nil +} +func (r *AtWatermark) _unmarshalJSONint64(data []byte) (int64, error) { + var result int64 + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("projection: AtWatermark._unmarshalJSONint64: native primitive unwrap; %w", err) + } + return result, nil +} + +func AnyOfFromJSON(x []byte) (*AnyOf, error) { + result := new(AnyOf) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AnyOfToJSON(x *AnyOf) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AnyOf)(nil) + _ json.Marshaler = (*AnyOf)(nil) +) + +func (r *AnyOf) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAnyOf(*r) +} +func (r *AnyOf) _marshalJSONAnyOf(x AnyOf) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldTriggers []byte + fieldTriggers, err = r._marshalJSONSliceTriggerDescription(x.Triggers) + if err != nil { + return nil, fmt.Errorf("projection: AnyOf._marshalJSONAnyOf: field name Triggers; %w", err) + } + partial["Triggers"] = fieldTriggers + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AnyOf._marshalJSONAnyOf: struct; %w", err) + } + return result, nil +} +func (r *AnyOf) _marshalJSONSliceTriggerDescription(x []TriggerDescription) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONTriggerDescription(v) + if err != nil { + return nil, fmt.Errorf("projection: AnyOf._marshalJSONSliceTriggerDescription: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AnyOf._marshalJSONSliceTriggerDescription:; %w", err) + } + return result, nil +} +func (r *AnyOf) _marshalJSONTriggerDescription(x TriggerDescription) ([]byte, error) { + result, err := shared.JSONMarshal[TriggerDescription](x) + if err != nil { + return nil, fmt.Errorf("projection: AnyOf._marshalJSONTriggerDescription:; %w", err) + } + return result, nil +} +func (r *AnyOf) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAnyOf(data) + if err != nil { + return fmt.Errorf("projection: AnyOf.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AnyOf) _unmarshalJSONAnyOf(data []byte) (AnyOf, error) { + result := AnyOf{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AnyOf._unmarshalJSONAnyOf: native struct unwrap; %w", err) + } + if fieldTriggers, ok := partial["Triggers"]; ok { + result.Triggers, err = r._unmarshalJSONSliceTriggerDescription(fieldTriggers) + if err != nil { + return result, fmt.Errorf("projection: AnyOf._unmarshalJSONAnyOf: field Triggers; %w", err) + } + } + return result, nil +} +func (r *AnyOf) _unmarshalJSONSliceTriggerDescription(data []byte) ([]TriggerDescription, error) { + result := make([]TriggerDescription, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AnyOf._unmarshalJSONSliceTriggerDescription: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONTriggerDescription(v) + if err != nil { + return result, fmt.Errorf("projection: AnyOf._unmarshalJSONSliceTriggerDescription: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *AnyOf) _unmarshalJSONTriggerDescription(data []byte) (TriggerDescription, error) { + result, err := shared.JSONUnmarshal[TriggerDescription](data) + if err != nil { + return result, fmt.Errorf("projection: AnyOf._unmarshalJSONTriggerDescription: native ref unwrap; %w", err) + } + return result, nil +} + +func AllOfFromJSON(x []byte) (*AllOf, error) { + result := new(AllOf) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AllOfToJSON(x *AllOf) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AllOf)(nil) + _ json.Marshaler = (*AllOf)(nil) +) + +func (r *AllOf) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAllOf(*r) +} +func (r *AllOf) _marshalJSONAllOf(x AllOf) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldTriggers []byte + fieldTriggers, err = r._marshalJSONSliceTriggerDescription(x.Triggers) + if err != nil { + return nil, fmt.Errorf("projection: AllOf._marshalJSONAllOf: field name Triggers; %w", err) + } + partial["Triggers"] = fieldTriggers + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AllOf._marshalJSONAllOf: struct; %w", err) + } + return result, nil +} +func (r *AllOf) _marshalJSONSliceTriggerDescription(x []TriggerDescription) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONTriggerDescription(v) + if err != nil { + return nil, fmt.Errorf("projection: AllOf._marshalJSONSliceTriggerDescription: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AllOf._marshalJSONSliceTriggerDescription:; %w", err) + } + return result, nil +} +func (r *AllOf) _marshalJSONTriggerDescription(x TriggerDescription) ([]byte, error) { + result, err := shared.JSONMarshal[TriggerDescription](x) + if err != nil { + return nil, fmt.Errorf("projection: AllOf._marshalJSONTriggerDescription:; %w", err) + } + return result, nil +} +func (r *AllOf) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAllOf(data) + if err != nil { + return fmt.Errorf("projection: AllOf.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AllOf) _unmarshalJSONAllOf(data []byte) (AllOf, error) { + result := AllOf{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AllOf._unmarshalJSONAllOf: native struct unwrap; %w", err) + } + if fieldTriggers, ok := partial["Triggers"]; ok { + result.Triggers, err = r._unmarshalJSONSliceTriggerDescription(fieldTriggers) + if err != nil { + return result, fmt.Errorf("projection: AllOf._unmarshalJSONAllOf: field Triggers; %w", err) + } + } + return result, nil +} +func (r *AllOf) _unmarshalJSONSliceTriggerDescription(data []byte) ([]TriggerDescription, error) { + result := make([]TriggerDescription, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AllOf._unmarshalJSONSliceTriggerDescription: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONTriggerDescription(v) + if err != nil { + return result, fmt.Errorf("projection: AllOf._unmarshalJSONSliceTriggerDescription: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *AllOf) _unmarshalJSONTriggerDescription(data []byte) (TriggerDescription, error) { + result, err := shared.JSONUnmarshal[TriggerDescription](data) + if err != nil { + return result, fmt.Errorf("projection: AllOf._unmarshalJSONTriggerDescription: native ref unwrap; %w", err) + } + return result, nil +} + +type TriggerTypeVisitor interface { + VisitAtPeriod1(v *AtPeriod1) any + VisitAtWindowItemSize1(v *AtWindowItemSize1) any + VisitAtWatermark1(v *AtWatermark1) any +} + +type TriggerType interface { + AcceptTriggerType(g TriggerTypeVisitor) any +} + +var ( + _ TriggerType = (*AtPeriod1)(nil) + _ TriggerType = (*AtWindowItemSize1)(nil) + _ TriggerType = (*AtWatermark1)(nil) +) + +func (r *AtPeriod1) AcceptTriggerType(v TriggerTypeVisitor) any { return v.VisitAtPeriod1(r) } +func (r *AtWindowItemSize1) AcceptTriggerType(v TriggerTypeVisitor) any { + return v.VisitAtWindowItemSize1(r) +} +func (r *AtWatermark1) AcceptTriggerType(v TriggerTypeVisitor) any { return v.VisitAtWatermark1(r) } + +func MatchTriggerTypeR3[T0, T1, T2 any]( + x TriggerType, + f1 func(x *AtPeriod1) (T0, T1, T2), + f2 func(x *AtWindowItemSize1) (T0, T1, T2), + f3 func(x *AtWatermark1) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *AtPeriod1: + return f1(v) + case *AtWindowItemSize1: + return f2(v) + case *AtWatermark1: + return f3(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchTriggerTypeR2[T0, T1 any]( + x TriggerType, + f1 func(x *AtPeriod1) (T0, T1), + f2 func(x *AtWindowItemSize1) (T0, T1), + f3 func(x *AtWatermark1) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *AtPeriod1: + return f1(v) + case *AtWindowItemSize1: + return f2(v) + case *AtWatermark1: + return f3(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchTriggerTypeR1[T0 any]( + x TriggerType, + f1 func(x *AtPeriod1) T0, + f2 func(x *AtWindowItemSize1) T0, + f3 func(x *AtWatermark1) T0, +) T0 { + switch v := x.(type) { + case *AtPeriod1: + return f1(v) + case *AtWindowItemSize1: + return f2(v) + case *AtWatermark1: + return f3(v) + } + var result1 T0 + return result1 +} + +func MatchTriggerTypeR0( + x TriggerType, + f1 func(x *AtPeriod1), + f2 func(x *AtWindowItemSize1), + f3 func(x *AtWatermark1), +) { + switch v := x.(type) { + case *AtPeriod1: + f1(v) + case *AtWindowItemSize1: + f2(v) + case *AtWatermark1: + f3(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.TriggerType", TriggerTypeFromJSON, TriggerTypeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AtPeriod1", AtPeriod1FromJSON, AtPeriod1ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AtWindowItemSize1", AtWindowItemSize1FromJSON, AtWindowItemSize1ToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AtWatermark1", AtWatermark1FromJSON, AtWatermark1ToJSON) +} + +type TriggerTypeUnionJSON struct { + Type string `json:"$type,omitempty"` + AtPeriod1 json.RawMessage `json:"projection.AtPeriod1,omitempty"` + AtWindowItemSize1 json.RawMessage `json:"projection.AtWindowItemSize1,omitempty"` + AtWatermark1 json.RawMessage `json:"projection.AtWatermark1,omitempty"` +} + +func TriggerTypeFromJSON(x []byte) (TriggerType, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data TriggerTypeUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "projection.AtPeriod1": + return AtPeriod1FromJSON(data.AtPeriod1) + case "projection.AtWindowItemSize1": + return AtWindowItemSize1FromJSON(data.AtWindowItemSize1) + case "projection.AtWatermark1": + return AtWatermark1FromJSON(data.AtWatermark1) + } + + if data.AtPeriod1 != nil { + return AtPeriod1FromJSON(data.AtPeriod1) + } else if data.AtWindowItemSize1 != nil { + return AtWindowItemSize1FromJSON(data.AtWindowItemSize1) + } else if data.AtWatermark1 != nil { + return AtWatermark1FromJSON(data.AtWatermark1) + } + + return nil, fmt.Errorf("projection.TriggerType: unknown type %s", data.Type) +} + +func TriggerTypeToJSON(x TriggerType) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchTriggerTypeR2( + x, + func(x *AtPeriod1) ([]byte, error) { + body, err := AtPeriod1ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerTypeUnionJSON{ + Type: "projection.AtPeriod1", + AtPeriod1: body, + }) + }, + func(x *AtWindowItemSize1) ([]byte, error) { + body, err := AtWindowItemSize1ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerTypeUnionJSON{ + Type: "projection.AtWindowItemSize1", + AtWindowItemSize1: body, + }) + }, + func(x *AtWatermark1) ([]byte, error) { + body, err := AtWatermark1ToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(TriggerTypeUnionJSON{ + Type: "projection.AtWatermark1", + AtWatermark1: body, + }) + }, + ) +} + +func AtPeriod1FromJSON(x []byte) (*AtPeriod1, error) { + result := new(AtPeriod1) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AtPeriod1ToJSON(x *AtPeriod1) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AtPeriod1)(nil) + _ json.Marshaler = (*AtPeriod1)(nil) +) + +func AtWindowItemSize1FromJSON(x []byte) (*AtWindowItemSize1, error) { + result := new(AtWindowItemSize1) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AtWindowItemSize1ToJSON(x *AtWindowItemSize1) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AtWindowItemSize1)(nil) + _ json.Marshaler = (*AtWindowItemSize1)(nil) +) + +func AtWatermark1FromJSON(x []byte) (*AtWatermark1, error) { + result := new(AtWatermark1) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AtWatermark1ToJSON(x *AtWatermark1) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AtWatermark1)(nil) + _ json.Marshaler = (*AtWatermark1)(nil) +) + +type WindowFlushModeVisitor interface { + VisitAccumulate(v *Accumulate) any + VisitDiscard(v *Discard) any + VisitAccumulatingAndRetracting(v *AccumulatingAndRetracting) any +} + +type WindowFlushMode interface { + AcceptWindowFlushMode(g WindowFlushModeVisitor) any +} + +var ( + _ WindowFlushMode = (*Accumulate)(nil) + _ WindowFlushMode = (*Discard)(nil) + _ WindowFlushMode = (*AccumulatingAndRetracting)(nil) +) + +func (r *Accumulate) AcceptWindowFlushMode(v WindowFlushModeVisitor) any { return v.VisitAccumulate(r) } +func (r *Discard) AcceptWindowFlushMode(v WindowFlushModeVisitor) any { return v.VisitDiscard(r) } +func (r *AccumulatingAndRetracting) AcceptWindowFlushMode(v WindowFlushModeVisitor) any { + return v.VisitAccumulatingAndRetracting(r) +} + +func MatchWindowFlushModeR3[T0, T1, T2 any]( + x WindowFlushMode, + f1 func(x *Accumulate) (T0, T1, T2), + f2 func(x *Discard) (T0, T1, T2), + f3 func(x *AccumulatingAndRetracting) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *Accumulate: + return f1(v) + case *Discard: + return f2(v) + case *AccumulatingAndRetracting: + return f3(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchWindowFlushModeR2[T0, T1 any]( + x WindowFlushMode, + f1 func(x *Accumulate) (T0, T1), + f2 func(x *Discard) (T0, T1), + f3 func(x *AccumulatingAndRetracting) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *Accumulate: + return f1(v) + case *Discard: + return f2(v) + case *AccumulatingAndRetracting: + return f3(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchWindowFlushModeR1[T0 any]( + x WindowFlushMode, + f1 func(x *Accumulate) T0, + f2 func(x *Discard) T0, + f3 func(x *AccumulatingAndRetracting) T0, +) T0 { + switch v := x.(type) { + case *Accumulate: + return f1(v) + case *Discard: + return f2(v) + case *AccumulatingAndRetracting: + return f3(v) + } + var result1 T0 + return result1 +} + +func MatchWindowFlushModeR0( + x WindowFlushMode, + f1 func(x *Accumulate), + f2 func(x *Discard), + f3 func(x *AccumulatingAndRetracting), +) { + switch v := x.(type) { + case *Accumulate: + f1(v) + case *Discard: + f2(v) + case *AccumulatingAndRetracting: + f3(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.WindowFlushMode", WindowFlushModeFromJSON, WindowFlushModeToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.Accumulate", AccumulateFromJSON, AccumulateToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.Discard", DiscardFromJSON, DiscardToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.AccumulatingAndRetracting", AccumulatingAndRetractingFromJSON, AccumulatingAndRetractingToJSON) +} + +type WindowFlushModeUnionJSON struct { + Type string `json:"$type,omitempty"` + Accumulate json.RawMessage `json:"projection.Accumulate,omitempty"` + Discard json.RawMessage `json:"projection.Discard,omitempty"` + AccumulatingAndRetracting json.RawMessage `json:"projection.AccumulatingAndRetracting,omitempty"` +} + +func WindowFlushModeFromJSON(x []byte) (WindowFlushMode, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data WindowFlushModeUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "projection.Accumulate": + return AccumulateFromJSON(data.Accumulate) + case "projection.Discard": + return DiscardFromJSON(data.Discard) + case "projection.AccumulatingAndRetracting": + return AccumulatingAndRetractingFromJSON(data.AccumulatingAndRetracting) + } + + if data.Accumulate != nil { + return AccumulateFromJSON(data.Accumulate) + } else if data.Discard != nil { + return DiscardFromJSON(data.Discard) + } else if data.AccumulatingAndRetracting != nil { + return AccumulatingAndRetractingFromJSON(data.AccumulatingAndRetracting) + } + + return nil, fmt.Errorf("projection.WindowFlushMode: unknown type %s", data.Type) +} + +func WindowFlushModeToJSON(x WindowFlushMode) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchWindowFlushModeR2( + x, + func(x *Accumulate) ([]byte, error) { + body, err := AccumulateToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WindowFlushModeUnionJSON{ + Type: "projection.Accumulate", + Accumulate: body, + }) + }, + func(x *Discard) ([]byte, error) { + body, err := DiscardToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WindowFlushModeUnionJSON{ + Type: "projection.Discard", + Discard: body, + }) + }, + func(x *AccumulatingAndRetracting) ([]byte, error) { + body, err := AccumulatingAndRetractingToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WindowFlushModeUnionJSON{ + Type: "projection.AccumulatingAndRetracting", + AccumulatingAndRetracting: body, + }) + }, + ) +} + +func AccumulateFromJSON(x []byte) (*Accumulate, error) { + result := new(Accumulate) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AccumulateToJSON(x *Accumulate) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Accumulate)(nil) + _ json.Marshaler = (*Accumulate)(nil) +) + +func (r *Accumulate) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAccumulate(*r) +} +func (r *Accumulate) _marshalJSONAccumulate(x Accumulate) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldAllowLateArrival []byte + fieldAllowLateArrival, err = r._marshalJSONtime_Duration(x.AllowLateArrival) + if err != nil { + return nil, fmt.Errorf("projection: Accumulate._marshalJSONAccumulate: field name AllowLateArrival; %w", err) + } + partial["AllowLateArrival"] = fieldAllowLateArrival + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: Accumulate._marshalJSONAccumulate: struct; %w", err) + } + return result, nil +} +func (r *Accumulate) _marshalJSONtime_Duration(x time.Duration) ([]byte, error) { + result, err := shared.JSONMarshal[time.Duration](x) + if err != nil { + return nil, fmt.Errorf("projection: Accumulate._marshalJSONtime_Duration:; %w", err) + } + return result, nil +} +func (r *Accumulate) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAccumulate(data) + if err != nil { + return fmt.Errorf("projection: Accumulate.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Accumulate) _unmarshalJSONAccumulate(data []byte) (Accumulate, error) { + result := Accumulate{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: Accumulate._unmarshalJSONAccumulate: native struct unwrap; %w", err) + } + if fieldAllowLateArrival, ok := partial["AllowLateArrival"]; ok { + result.AllowLateArrival, err = r._unmarshalJSONtime_Duration(fieldAllowLateArrival) + if err != nil { + return result, fmt.Errorf("projection: Accumulate._unmarshalJSONAccumulate: field AllowLateArrival; %w", err) + } + } + return result, nil +} +func (r *Accumulate) _unmarshalJSONtime_Duration(data []byte) (time.Duration, error) { + result, err := shared.JSONUnmarshal[time.Duration](data) + if err != nil { + return result, fmt.Errorf("projection: Accumulate._unmarshalJSONtime_Duration: native ref unwrap; %w", err) + } + return result, nil +} + +func DiscardFromJSON(x []byte) (*Discard, error) { + result := new(Discard) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DiscardToJSON(x *Discard) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Discard)(nil) + _ json.Marshaler = (*Discard)(nil) +) + +func (r *Discard) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDiscard(*r) +} +func (r *Discard) _marshalJSONDiscard(x Discard) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: Discard._marshalJSONDiscard: struct; %w", err) + } + return result, nil +} +func (r *Discard) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDiscard(data) + if err != nil { + return fmt.Errorf("projection: Discard.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Discard) _unmarshalJSONDiscard(data []byte) (Discard, error) { + result := Discard{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: Discard._unmarshalJSONDiscard: native struct unwrap; %w", err) + } + return result, nil +} + +func AccumulatingAndRetractingFromJSON(x []byte) (*AccumulatingAndRetracting, error) { + result := new(AccumulatingAndRetracting) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AccumulatingAndRetractingToJSON(x *AccumulatingAndRetracting) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*AccumulatingAndRetracting)(nil) + _ json.Marshaler = (*AccumulatingAndRetracting)(nil) +) + +func (r *AccumulatingAndRetracting) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAccumulatingAndRetracting(*r) +} +func (r *AccumulatingAndRetracting) _marshalJSONAccumulatingAndRetracting(x AccumulatingAndRetracting) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldAllowLateArrival []byte + fieldAllowLateArrival, err = r._marshalJSONtime_Duration(x.AllowLateArrival) + if err != nil { + return nil, fmt.Errorf("projection: AccumulatingAndRetracting._marshalJSONAccumulatingAndRetracting: field name AllowLateArrival; %w", err) + } + partial["AllowLateArrival"] = fieldAllowLateArrival + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: AccumulatingAndRetracting._marshalJSONAccumulatingAndRetracting: struct; %w", err) + } + return result, nil +} +func (r *AccumulatingAndRetracting) _marshalJSONtime_Duration(x time.Duration) ([]byte, error) { + result, err := shared.JSONMarshal[time.Duration](x) + if err != nil { + return nil, fmt.Errorf("projection: AccumulatingAndRetracting._marshalJSONtime_Duration:; %w", err) + } + return result, nil +} +func (r *AccumulatingAndRetracting) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAccumulatingAndRetracting(data) + if err != nil { + return fmt.Errorf("projection: AccumulatingAndRetracting.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *AccumulatingAndRetracting) _unmarshalJSONAccumulatingAndRetracting(data []byte) (AccumulatingAndRetracting, error) { + result := AccumulatingAndRetracting{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: AccumulatingAndRetracting._unmarshalJSONAccumulatingAndRetracting: native struct unwrap; %w", err) + } + if fieldAllowLateArrival, ok := partial["AllowLateArrival"]; ok { + result.AllowLateArrival, err = r._unmarshalJSONtime_Duration(fieldAllowLateArrival) + if err != nil { + return result, fmt.Errorf("projection: AccumulatingAndRetracting._unmarshalJSONAccumulatingAndRetracting: field AllowLateArrival; %w", err) + } + } + return result, nil +} +func (r *AccumulatingAndRetracting) _unmarshalJSONtime_Duration(data []byte) (time.Duration, error) { + result, err := shared.JSONUnmarshal[time.Duration](data) + if err != nil { + return result, fmt.Errorf("projection: AccumulatingAndRetracting._unmarshalJSONtime_Duration: native ref unwrap; %w", err) + } + return result, nil +} diff --git a/x/storage/schemaless/projection/utils.go b/x/storage/schemaless/projection/utils.go new file mode 100644 index 00000000..be662b1a --- /dev/null +++ b/x/storage/schemaless/projection/utils.go @@ -0,0 +1,143 @@ +package projection + +import ( + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "sync" + "testing" + "time" +) + +func Each(x schema.Schema, f func(value schema.Schema)) { + _ = schema.MatchSchemaR1( + x, + func(x *schema.None) any { + return nil + }, + func(x *schema.Bool) any { + f(x) + return nil + }, + func(x *schema.Number) any { + f(x) + return nil + }, + func(x *schema.String) any { + f(x) + return nil + }, + func(x *schema.Binary) any { + f(x) + return nil + }, + func(x *schema.List) any { + for _, v := range *x { + f(v) + } + return nil + }, + func(x *schema.Map) any { + f(x) + return nil + }, + ) +} + +func GenerateItemsEvery(start int64, size int, every time.Duration) chan Item { + ch := make(chan Item) + t := time.Unix(0, start) + + go func() { + defer close(ch) + for i := 0; i < size; i++ { + ch <- Item{ + //Key: "key-" + strconv.Itoa(i), + Key: "key", + Data: schema.MkInt(int64(i)), + EventTime: t.UnixNano(), + } + t = t.Add(every) + time.Sleep(every) + } + }() + return ch +} + +func NewDual() *Dual { + return &Dual{} +} + +type Dual struct { + lock sync.Mutex + list []*Message + + aggIdx int + retIdx int +} + +func (d *Dual) ReturningAggregate(msg Item) { + d.lock.Lock() + defer d.lock.Unlock() + + d.list = append(d.list, &Message{ + Key: msg.Key, + Item: &msg, + }) + + d.aggIdx++ +} + +func (d *Dual) ReturningRetract(msg Item) { + d.lock.Lock() + defer d.lock.Unlock() + + if d.retIdx <= len(d.list) { + if d.list[d.retIdx].Key != msg.Key { + panic("key mismatch") + } + + //d.list[d.retIdx].Watermark = &msg + d.retIdx++ + } +} + +func (d *Dual) IsValid() bool { + return d.aggIdx == d.retIdx +} + +func (d *Dual) List() []*Message { + return d.list +} + +type ListAssert struct { + t *testing.T + Items []Item + Err error +} + +func (l *ListAssert) Returning(msg Item) { + if l.Err != nil { + panic(l.Err) + } + + l.Items = append(l.Items, msg) +} + +func (l *ListAssert) AssertLen(expected int) bool { + return assert.Equal(l.t, expected, len(l.Items)) +} + +func (l *ListAssert) AssertAt(index int, expected Item) bool { + return assert.Equal(l.t, expected, l.Items[index]) +} + +func (l *ListAssert) Contains(expected Item) bool { + for _, item := range l.Items { + if assert.Equal(l.t, expected, item) { + return true + } + } + + l.t.Errorf("expected to find %v in result set but failed", expected) + return false +} diff --git a/x/storage/schemaless/projection/windowing.go b/x/storage/schemaless/projection/windowing.go new file mode 100644 index 00000000..9bb0a774 --- /dev/null +++ b/x/storage/schemaless/projection/windowing.go @@ -0,0 +1,568 @@ +package projection + +import ( + "fmt" + "github.com/widmogrod/mkunion/x/schema" + "time" +) + +//go:generate go run ../../../../cmd/mkunion/main.go + +//go:tag mkunion:"WindowDescription" +type ( + SessionWindow struct { + GapDuration time.Duration + } + SlidingWindow struct { + Width time.Duration + Period time.Duration + } + FixedWindow struct { + Width time.Duration + } +) + +func AssignWindows(x []Item, wd WindowDescription) []Item { + return MatchWindowDescriptionR1( + wd, + func(wd *SessionWindow) []Item { + return assignSessionWindows(x, wd) + }, + func(wd *SlidingWindow) []Item { + return assignSlidingWindows(x, wd) + }, + func(wd *FixedWindow) []Item { + return assignFixedWindows(x, wd) + }, + ) +} + +func assignFixedWindows(x []Item, wd *FixedWindow) []Item { + result := make([]Item, 0, len(x)) + for _, item := range x { + start := item.EventTime - item.EventTime%wd.Width.Nanoseconds() + end := start + wd.Width.Nanoseconds() + result = append(result, Item{ + Key: item.Key, + Data: item.Data, + EventTime: item.EventTime, + Window: &Window{ + Start: start, + End: end, + }, + }) + } + return result +} + +func assignSlidingWindows(x []Item, wd *SlidingWindow) []Item { + result := make([]Item, 0, len(x)) + for _, item := range x { + eventTime := time.Unix(0, item.EventTime) + // slicing window is [start, end) + // left side inclusive, and right side exclusive, + // so we need to add 1 period to the end + for start := eventTime.Add(-wd.Width).Add(wd.Period); start.UnixNano() <= item.EventTime; start = start.Add(wd.Period) { + result = append(result, Item{ + Key: item.Key, + Data: item.Data, + EventTime: item.EventTime, + Window: &Window{ + Start: start.UnixNano(), + End: start.Add(wd.Width).UnixNano(), + }, + }) + } + } + return result +} + +func assignSessionWindows(x []Item, wd *SessionWindow) []Item { + result := make([]Item, 0, len(x)) + for _, item := range x { + result = append(result, Item{ + Key: item.Key, + Data: item.Data, + EventTime: item.EventTime, + Window: &Window{ + Start: item.EventTime, + End: time.Unix(0, item.EventTime).Add(wd.GapDuration).UnixNano(), + }, + }) + } + return result +} + +func MergeWindows(x []ItemGroupedByKey, wd WindowDescription) []ItemGroupedByKey { + return MatchWindowDescriptionR1( + wd, + func(wd *SessionWindow) []ItemGroupedByKey { + return mergeSessionWindows(x, wd) + }, + func(wd *SlidingWindow) []ItemGroupedByKey { + // assumption here is that before calling MergeWindows, + // items got assigned window using the same WindowDefinition, + // so we can assume that all items in the group have the same value for sliding & fixed windows + // that don't need to be adjusted, like in session windows + return x + }, + func(wd *FixedWindow) []ItemGroupedByKey { + // assumption here is that before calling MergeWindows, + // items got assigned window using the same WindowDefinition, + // so we can assume that all items in the group have the same value for sliding & fixed windows + // that don't need to be adjusted, like in session windows + return x + }, + ) +} + +func winNo(w *Window, min int64, wd *SessionWindow) int64 { + return int64((time.Unix(0, w.Start).Sub(time.Unix(0, min)) + wd.GapDuration) / wd.GapDuration) +} + +func mergeSessionWindows(x []ItemGroupedByKey, wd *SessionWindow) []ItemGroupedByKey { + result := make([]ItemGroupedByKey, 0, len(x)) + for _, group := range x { + var min int64 + for _, item := range group.Data { + if min > item.Window.Start { + min = item.Window.Start + } + } + + window := map[int64]*Window{} + for _, item := range group.Data { + // detect where in which session window item belongs + // if in window session there are no items, then leave element as is + // when there are items, then merge them and set window to the min start and max end of elements in this window + + windowNo := winNo(item.Window, min, wd) + if _, ok := window[windowNo]; !ok { + window[windowNo] = &Window{ + Start: item.Window.Start, + End: item.Window.End, + } + } else { + w := window[windowNo] + if w.Start > item.Window.Start { + w.Start = item.Window.Start + } + if w.End < item.Window.End { + w.End = item.Window.End + } + } + } + + newGroup := ItemGroupedByKey{ + Key: group.Key, + Data: make([]Item, 0, len(group.Data)), + } + for _, item := range group.Data { + windowNo := winNo(item.Window, min, wd) + newGroup.Data = append(newGroup.Data, Item{ + Key: item.Key, + Data: item.Data, + EventTime: item.EventTime, + Window: &Window{ + Start: window[windowNo].Start, + End: window[windowNo].End, + }, + }) + } + + result = append(result, newGroup) + } + + return result +} + +func DropTimestamps(x []Item) []Item { + result := make([]Item, 0, len(x)) + for _, item := range x { + result = append(result, Item{ + Key: item.Key, + Data: item.Data, + EventTime: 0, + Window: item.Window, + }) + } + return result +} + +func GroupByKey(x []Item) []ItemGroupedByKey { + result := make([]*ItemGroupedByKey, 0, 0) + groups := map[string]*ItemGroupedByKey{} + for _, item := range x { + group, ok := groups[item.Key] + if !ok { + group = &ItemGroupedByKey{Key: item.Key} + groups[item.Key] = group + result = append(result, group) + } + group.Data = append(group.Data, item) + } + + // yet another workaround for unordered maps in golang + final := make([]ItemGroupedByKey, 0, len(result)) + for _, group := range result { + final = append(final, *group) + } + + return final +} + +func GroupAlsoByWindow(x []ItemGroupedByKey) []ItemGroupedByWindow { + result := make([]ItemGroupedByWindow, 0, len(x)) + windowGroups := map[int64]map[int64]*ItemGroupedByWindow{} + + for _, group := range x { + for _, item := range group.Data { + if _, ok := windowGroups[item.Window.Start]; !ok { + windowGroups[item.Window.Start] = map[int64]*ItemGroupedByWindow{} + } + if _, ok := windowGroups[item.Window.Start][item.Window.End]; !ok { + windowGroups[item.Window.Start][item.Window.End] = &ItemGroupedByWindow{ + Key: group.Key, + Data: &schema.List{}, + Window: item.Window, + } + } + + windowGroups[item.Window.Start][item.Window.End].Data = + schema.AppendList(windowGroups[item.Window.Start][item.Window.End].Data, item.Data) + } + + // because golang maps are not ordered, + // to create ordered result we need to iterate over data again in order to get ordered result + for _, item := range group.Data { + if _, ok := windowGroups[item.Window.Start]; !ok { + continue + } + if _, ok := windowGroups[item.Window.Start][item.Window.End]; !ok { + continue + } + + result = append(result, *windowGroups[item.Window.Start][item.Window.End]) + delete(windowGroups[item.Window.Start], item.Window.End) + } + } + + return result +} + +func ExpandToElements(x []ItemGroupedByWindow) []Item { + result := make([]Item, 0, len(x)) + for _, group := range x { + result = append(result, ToElement(&group)) + } + return result +} + +func ToElement(group *ItemGroupedByWindow) Item { + return Item{ + Key: group.Key, + Data: group.Data, + EventTime: group.Window.End, + Window: group.Window, + } +} + +func WindowKey(window *Window) string { + return fmt.Sprintf("%d.%d", window.Start, window.End) +} + +func KeyedWindowKey(x *KeyedWindow) string { + return fmt.Sprintf("%s:%s", x.Key, WindowKey(x.Window)) +} + +type KeyedWindow struct { + Key string + Window *Window +} + +func ToKeyedWindowFromItem(x *Item) *KeyedWindow { + return &KeyedWindow{ + Key: x.Key, + Window: x.Window, + } +} + +func ToKeyedWindowFromGrouped(x *ItemGroupedByWindow) *KeyedWindow { + return &KeyedWindow{ + Key: x.Key, + Window: x.Window, + } +} + +func KeyWithNamespace(key string, namespace string) string { + return fmt.Sprintf("%s:%s", namespace, key) +} + +func NewWindowBuffer(wd WindowDescription, sig WindowBufferSignaler) *WindowBuffer { + return &WindowBuffer{ + wd: wd, + sig: sig, + windowGroups: map[string]*ItemGroupedByWindow{}, + } +} + +type WindowBuffer struct { + wd WindowDescription + sig WindowBufferSignaler + windowGroups map[string]*ItemGroupedByWindow +} + +func (wb *WindowBuffer) Append(x Item) { + list1 := AssignWindows([]Item{x}, wb.wd) + list2 := DropTimestamps(list1) + list3 := GroupByKey(list2) + list4 := MergeWindows(list3, wb.wd) + wb.GroupAlsoByWindow(list4) +} + +// FlushItemGroupedByWindow makes sure that windows that needs to be flushed are delivered to the function f. +// +// Some operations that require aggregate or aggregateAndRetract are not expressed by window buffer, +// but by the function f that is responsible for grouping windows and knowing whenever value of window was calculated, +// and aggregation can add previous value, or retract previous value. +// +// Snapshotting process works as follows: +// - store information about last message that was successfully processed +// - store outbox of windows that were successfully processed and need to be flushed +// +// When process is restarted, it will: +// - restore information about last message that was successfully processed, and ask runtime to continue sending messages from that point +// - start emptying outbox +// +// Flush process works as follows: +// - for each window in outbox, call flush function, that function needs to return OK or error +// - if flush function returns OK, remove window from outbox +// - if flush function returns error, stop flushing, and retry on next flush +// +// Because each of the processes is independent by key, we can retry flushing only for windows that failed to flush. +// Because each of outbox pattern, we have order of windows guaranteed. +// _ +// Because we make failure first class citizen, client can define failure stream and decide that after N retries, +// message should be sent to dead letter queue, or other error handling mechanism. +// +// Because we can model backfilling as a failure, we can use same mechanism to backfill windows that failed to flush, +// in the same way as we would backfill normal messages from time window +// +// Backfill is the same as using already existing DAG, but only with different input. + +func (wb *WindowBuffer) EachItemGroupedByWindow(f func(group *ItemGroupedByWindow)) { + for _, group := range wb.windowGroups { + f(group) + } +} + +func (wb *WindowBuffer) EachKeyedWindow(kw *KeyedWindow, f func(group *ItemGroupedByWindow)) { + key := KeyedWindowKey(kw) + if group, ok := wb.windowGroups[key]; ok { + f(group) + } +} + +func (wb *WindowBuffer) RemoveItemGropedByWindow(item *ItemGroupedByWindow) { + kw := ToKeyedWindowFromGrouped(item) + key := KeyedWindowKey(kw) + delete(wb.windowGroups, key) + wb.sig.SignalWindowDeleted(kw) +} + +func (wb *WindowBuffer) GroupAlsoByWindow(x []ItemGroupedByKey) { + for _, group := range x { + for _, item := range group.Data { + kw := ToKeyedWindowFromItem(&item) + key := KeyedWindowKey(kw) + if _, ok := wb.windowGroups[key]; !ok { + wb.windowGroups[key] = &ItemGroupedByWindow{ + Key: group.Key, + Data: &schema.List{}, + Window: item.Window, + } + + wb.sig.SignalWindowCreated(kw) + } + + wb.windowGroups[key].Data = schema.AppendList( + wb.windowGroups[key].Data, + item.Data, + ) + + wb.sig.SignalWindowSizeReached(kw, len(*wb.windowGroups[key].Data)) + } + } +} + +// Problem with tests that use period based tirggers +// result in windows that due to internal latency, may not have all events at the time of trigger +// but watermark could say, hey wait with this trigger, because I see event that will land in this window +// so trigger at the arrival of watermark + +func NewWindowTrigger(w *Window, td TriggerDescription) *WindowTrigger { + wt := &WindowTrigger{ + w: w, + td: td, + } + wt.init() + + return wt +} + +type WindowTrigger struct { + w *Window + td TriggerDescription + ts *TriggerState + shouldTrigger bool +} + +func (wt *WindowTrigger) init() { + if wt.ts != nil { + return + } + + wt.ts = wt.initState(wt.td) +} + +func Bool(b bool) *bool { + return &b +} + +func (wt *WindowTrigger) initState(td TriggerDescription) *TriggerState { + return MatchTriggerDescriptionR1( + td, + func(x *AtPeriod) *TriggerState { + return &TriggerState{ + desc: td, + } + }, + func(x *AtWindowItemSize) *TriggerState { + return &TriggerState{ + desc: td, + } + }, + func(x *AtWatermark) *TriggerState { + return &TriggerState{ + desc: &AtWatermark{ + Timestamp: wt.w.End, + }, + } + }, + func(x *AnyOf) *TriggerState { + result := &TriggerState{ + desc: td, + } + + for _, desc := range x.Triggers { + result.nexts = append(result.nexts, wt.initState(desc)) + } + + return result + }, + func(x *AllOf) *TriggerState { + result := &TriggerState{ + desc: td, + } + + for _, desc := range x.Triggers { + result.nexts = append(result.nexts, wt.initState(desc)) + } + + return result + }, + ) +} + +func (wt *WindowTrigger) ReceiveEvent(triggerType TriggerType) { + // continue evaluation until state is true + // but when it's true, we don't need to evaluate + // conditions for window flush + if !wt.ts.isTrue() { + result := wt.ts.evaluate(triggerType, 0) + wt.ts.result = &result + } + + wt.shouldTrigger = wt.ts.isTrue() +} + +func (wt *WindowTrigger) ShouldTrigger() bool { + return wt.shouldTrigger +} + +func (wt *WindowTrigger) Reset() { + wt.shouldTrigger = false + wt.ts = wt.initState(wt.td) +} + +//go:generate go run ../../../../cmd/mkunion/main.go match -name=EvaluateTrigger +type EvaluateTrigger[T0 TriggerDescription, T1 TriggerType] interface { + MatchPeriod(*AtPeriod, *AtPeriod) + MatchCount(*AtWindowItemSize, *AtWindowItemSize) + MatchWatermark(*AtWatermark, *AtWatermark) + MatchAnyOfAny(*AnyOf, TriggerType) + MatchAllOfAny(*AllOf, TriggerType) + MatchDefault(T0, T1) +} + +type TriggerState struct { + desc TriggerDescription + nexts []*TriggerState + result *bool +} + +func (ts *TriggerState) isTrue() bool { + return ts.result != nil && *ts.result +} + +func (ts *TriggerState) evaluate(triggerType TriggerType, depth int) bool { + return EvaluateTriggerR1( + ts.desc, triggerType, + func(x0 *AtPeriod, x1 *AtPeriod) bool { + return x0.Duration == x1.Duration + }, + func(x0 *AtWindowItemSize, x1 *AtWindowItemSize) bool { + return x0.Number == x1.Number + }, + func(x0 *AtWatermark, x1 *AtWatermark) bool { + return x0.Timestamp <= x1.Timestamp + }, + func(x0 *AnyOf, x1 TriggerType) bool { + found := false + for _, state := range ts.nexts { + if !state.isTrue() { + matched := state.evaluate(triggerType, depth+1) + if matched { + state.result = Bool(true) + } + } + + // be exhaustive, and allow other triggers to be evaluated + // that way, with different triggers an complete state can be build + found = found || state.isTrue() + } + + return found + }, + func(x0 *AllOf, x1 TriggerType) bool { + found := true + for _, state := range ts.nexts { + if !state.isTrue() { + result := state.evaluate(triggerType, depth+1) + if result { + state.result = Bool(true) + } + } + + // be exhaustive, and allow other triggers to be evaluated + // that way, with different triggers an complete state can be build + found = found && state.isTrue() + } + + return found + }, + func(x0 TriggerDescription, x1 TriggerType) bool { + return false + }, + ) +} diff --git a/x/storage/schemaless/projection/windowing_match_evaluatetrigger.go b/x/storage/schemaless/projection/windowing_match_evaluatetrigger.go new file mode 100644 index 00000000..42b16e7b --- /dev/null +++ b/x/storage/schemaless/projection/windowing_match_evaluatetrigger.go @@ -0,0 +1,204 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +func EvaluateTriggerR0[T0 TriggerDescription, T1 TriggerType]( + t0 T0, + t1 T1, + f0 func(x0 *AtPeriod, x1 *AtPeriod), + f1 func(x0 *AtWindowItemSize, x1 *AtWindowItemSize), + f2 func(x0 *AtWatermark, x1 *AtWatermark), + f3 func(x0 *AnyOf, x1 TriggerType), + f4 func(x0 *AllOf, x1 TriggerType), + f5 func(x0 T0, x1 T1), +) { + c0t0, c0t0ok := any(t0).(*AtPeriod) + c0t1, c0t1ok := any(t1).(*AtPeriod) + if c0t0ok && c0t1ok { + f0(c0t0, c0t1) + return + } + + c1t0, c1t0ok := any(t0).(*AtWindowItemSize) + c1t1, c1t1ok := any(t1).(*AtWindowItemSize) + if c1t0ok && c1t1ok { + f1(c1t0, c1t1) + return + } + + c2t0, c2t0ok := any(t0).(*AtWatermark) + c2t1, c2t1ok := any(t1).(*AtWatermark) + if c2t0ok && c2t1ok { + f2(c2t0, c2t1) + return + } + + c3t0, c3t0ok := any(t0).(*AnyOf) + c3t1, c3t1ok := any(t1).(TriggerType) + if c3t0ok && c3t1ok { + f3(c3t0, c3t1) + return + } + + c4t0, c4t0ok := any(t0).(*AllOf) + c4t1, c4t1ok := any(t1).(TriggerType) + if c4t0ok && c4t1ok { + f4(c4t0, c4t1) + return + } + + c5t0, c5t0ok := any(t0).(T0) + c5t1, c5t1ok := any(t1).(T1) + if c5t0ok && c5t1ok { + f5(c5t0, c5t1) + return + } + + panic("EvaluateTriggerR0 is not exhaustive") +} + +func EvaluateTriggerR1[T0 TriggerDescription, T1 TriggerType, TOut1 any]( + t0 T0, + t1 T1, + f0 func(x0 *AtPeriod, x1 *AtPeriod) TOut1, + f1 func(x0 *AtWindowItemSize, x1 *AtWindowItemSize) TOut1, + f2 func(x0 *AtWatermark, x1 *AtWatermark) TOut1, + f3 func(x0 *AnyOf, x1 TriggerType) TOut1, + f4 func(x0 *AllOf, x1 TriggerType) TOut1, + f5 func(x0 T0, x1 T1) TOut1, +) TOut1 { + c0t0, c0t0ok := any(t0).(*AtPeriod) + c0t1, c0t1ok := any(t1).(*AtPeriod) + if c0t0ok && c0t1ok { + return f0(c0t0, c0t1) + } + + c1t0, c1t0ok := any(t0).(*AtWindowItemSize) + c1t1, c1t1ok := any(t1).(*AtWindowItemSize) + if c1t0ok && c1t1ok { + return f1(c1t0, c1t1) + } + + c2t0, c2t0ok := any(t0).(*AtWatermark) + c2t1, c2t1ok := any(t1).(*AtWatermark) + if c2t0ok && c2t1ok { + return f2(c2t0, c2t1) + } + + c3t0, c3t0ok := any(t0).(*AnyOf) + c3t1, c3t1ok := any(t1).(TriggerType) + if c3t0ok && c3t1ok { + return f3(c3t0, c3t1) + } + + c4t0, c4t0ok := any(t0).(*AllOf) + c4t1, c4t1ok := any(t1).(TriggerType) + if c4t0ok && c4t1ok { + return f4(c4t0, c4t1) + } + + c5t0, c5t0ok := any(t0).(T0) + c5t1, c5t1ok := any(t1).(T1) + if c5t0ok && c5t1ok { + return f5(c5t0, c5t1) + } + + panic("EvaluateTriggerR0 is not exhaustive") +} + +func EvaluateTriggerR2[T0 TriggerDescription, T1 TriggerType, TOut1 any, TOut2 any]( + t0 T0, + t1 T1, + f0 func(x0 *AtPeriod, x1 *AtPeriod) (TOut1, TOut2), + f1 func(x0 *AtWindowItemSize, x1 *AtWindowItemSize) (TOut1, TOut2), + f2 func(x0 *AtWatermark, x1 *AtWatermark) (TOut1, TOut2), + f3 func(x0 *AnyOf, x1 TriggerType) (TOut1, TOut2), + f4 func(x0 *AllOf, x1 TriggerType) (TOut1, TOut2), + f5 func(x0 T0, x1 T1) (TOut1, TOut2), +) (TOut1, TOut2) { + c0t0, c0t0ok := any(t0).(*AtPeriod) + c0t1, c0t1ok := any(t1).(*AtPeriod) + if c0t0ok && c0t1ok { + return f0(c0t0, c0t1) + } + + c1t0, c1t0ok := any(t0).(*AtWindowItemSize) + c1t1, c1t1ok := any(t1).(*AtWindowItemSize) + if c1t0ok && c1t1ok { + return f1(c1t0, c1t1) + } + + c2t0, c2t0ok := any(t0).(*AtWatermark) + c2t1, c2t1ok := any(t1).(*AtWatermark) + if c2t0ok && c2t1ok { + return f2(c2t0, c2t1) + } + + c3t0, c3t0ok := any(t0).(*AnyOf) + c3t1, c3t1ok := any(t1).(TriggerType) + if c3t0ok && c3t1ok { + return f3(c3t0, c3t1) + } + + c4t0, c4t0ok := any(t0).(*AllOf) + c4t1, c4t1ok := any(t1).(TriggerType) + if c4t0ok && c4t1ok { + return f4(c4t0, c4t1) + } + + c5t0, c5t0ok := any(t0).(T0) + c5t1, c5t1ok := any(t1).(T1) + if c5t0ok && c5t1ok { + return f5(c5t0, c5t1) + } + + panic("EvaluateTriggerR0 is not exhaustive") +} + +func EvaluateTriggerR3[T0 TriggerDescription, T1 TriggerType, TOut1 any, TOut2 any, TOut3 any]( + t0 T0, + t1 T1, + f0 func(x0 *AtPeriod, x1 *AtPeriod) (TOut1, TOut2, TOut3), + f1 func(x0 *AtWindowItemSize, x1 *AtWindowItemSize) (TOut1, TOut2, TOut3), + f2 func(x0 *AtWatermark, x1 *AtWatermark) (TOut1, TOut2, TOut3), + f3 func(x0 *AnyOf, x1 TriggerType) (TOut1, TOut2, TOut3), + f4 func(x0 *AllOf, x1 TriggerType) (TOut1, TOut2, TOut3), + f5 func(x0 T0, x1 T1) (TOut1, TOut2, TOut3), +) (TOut1, TOut2, TOut3) { + c0t0, c0t0ok := any(t0).(*AtPeriod) + c0t1, c0t1ok := any(t1).(*AtPeriod) + if c0t0ok && c0t1ok { + return f0(c0t0, c0t1) + } + + c1t0, c1t0ok := any(t0).(*AtWindowItemSize) + c1t1, c1t1ok := any(t1).(*AtWindowItemSize) + if c1t0ok && c1t1ok { + return f1(c1t0, c1t1) + } + + c2t0, c2t0ok := any(t0).(*AtWatermark) + c2t1, c2t1ok := any(t1).(*AtWatermark) + if c2t0ok && c2t1ok { + return f2(c2t0, c2t1) + } + + c3t0, c3t0ok := any(t0).(*AnyOf) + c3t1, c3t1ok := any(t1).(TriggerType) + if c3t0ok && c3t1ok { + return f3(c3t0, c3t1) + } + + c4t0, c4t0ok := any(t0).(*AllOf) + c4t1, c4t1ok := any(t1).(TriggerType) + if c4t0ok && c4t1ok { + return f4(c4t0, c4t1) + } + + c5t0, c5t0ok := any(t0).(T0) + c5t1, c5t1ok := any(t1).(T1) + if c5t0ok && c5t1ok { + return f5(c5t0, c5t1) + } + + panic("EvaluateTriggerR0 is not exhaustive") +} diff --git a/x/storage/schemaless/projection/windowing_shape_gen.go b/x/storage/schemaless/projection/windowing_shape_gen.go new file mode 100644 index 00000000..0304ed80 --- /dev/null +++ b/x/storage/schemaless/projection/windowing_shape_gen.go @@ -0,0 +1,146 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(FixedWindowShape()) + shape.Register(KeyedWindowShape()) + shape.Register(SessionWindowShape()) + shape.Register(SlidingWindowShape()) + shape.Register(TriggerStateShape()) + shape.Register(WindowBufferShape()) + shape.Register(WindowDescriptionShape()) + shape.Register(WindowTriggerShape()) +} + +//shape:shape + +func WindowDescriptionShape() shape.Shape { + return &shape.UnionLike{ + Name: "WindowDescription", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Variant: []shape.Shape{ + SessionWindowShape(), + SlidingWindowShape(), + FixedWindowShape(), + }, + } +} + +func SessionWindowShape() shape.Shape { + return &shape.StructLike{ + Name: "SessionWindow", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "GapDuration", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + }, + } +} + +func SlidingWindowShape() shape.Shape { + return &shape.StructLike{ + Name: "SlidingWindow", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Width", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + { + Name: "Period", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + }, + } +} + +func FixedWindowShape() shape.Shape { + return &shape.StructLike{ + Name: "FixedWindow", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Width", + Type: &shape.RefName{ + Name: "Duration", + PkgName: "time", + PkgImportName: "time", + }, + }, + }, + } +} + +//shape:shape +func KeyedWindowShape() shape.Shape { + return &shape.StructLike{ + Name: "KeyedWindow", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + Fields: []*shape.FieldLike{ + { + Name: "Key", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Window", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "Window", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + }, + }, + }, + }, + } +} + +//shape:shape +func TriggerStateShape() shape.Shape { + return &shape.StructLike{ + Name: "TriggerState", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +//shape:shape +func WindowBufferShape() shape.Shape { + return &shape.StructLike{ + Name: "WindowBuffer", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} + +//shape:shape +func WindowTriggerShape() shape.Shape { + return &shape.StructLike{ + Name: "WindowTrigger", + PkgName: "projection", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless/projection", + } +} diff --git a/x/storage/schemaless/projection/windowing_test.go b/x/storage/schemaless/projection/windowing_test.go new file mode 100644 index 00000000..275649bf --- /dev/null +++ b/x/storage/schemaless/projection/windowing_test.go @@ -0,0 +1,908 @@ +package projection + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "github.com/widmogrod/mkunion/x/schema" + "os" + "testing" + "time" +) + +func withTime(hour, minute int) int64 { + return time. + Date(2019, 1, 1, hour, minute, 0, 0, time.UTC). + UnixNano() +} + +func printWindow(w *Window) { + fmt.Printf("Window(%s, %s)\n", + time.Unix(0, w.Start).Format("15:04"), + time.Unix(0, w.End).Format("15:04"), + ) +} + +func TestWindowing(t *testing.T) { + if os.Getenv("RUN_EXPERIMENTAL_TEST") == "false" { + t.Skip(`Skipping test because: +- RUN_EXPERIMENTAL_TEST=false is set. +`) + } + + list := []Item{ + { + Key: "a", + Data: nil, + EventTime: withTime(10, 2), + }, + { + Key: "a", + Data: nil, + EventTime: withTime(10, 28), + }, + } + + t.Run("assign session windows", func(t *testing.T) { + result := AssignWindows(list, &SessionWindow{ + GapDuration: 30 * time.Minute, + }) + expected := []Item{ + { + Key: "a", + Data: nil, + EventTime: withTime(10, 2), + Window: &Window{ + Start: withTime(10, 2), + End: withTime(10, 32), + }, + }, + { + Key: "a", + Data: nil, + EventTime: withTime(10, 28), + Window: &Window{ + Start: withTime(10, 28), + End: withTime(10, 58), + }, + }, + } + + assert.Equal(t, expected, result) + }) + t.Run("assign sliding windows", func(t *testing.T) { + result := AssignWindows(list, &SlidingWindow{ + Width: 2 * time.Minute, + Period: 1 * time.Minute, + }) + expected := []Item{ + { + Key: "a", + Data: nil, + EventTime: withTime(10, 2), + Window: &Window{ + Start: withTime(10, 1), + End: withTime(10, 3), + }, + }, + { + Key: "a", + Data: nil, + EventTime: withTime(10, 2), + Window: &Window{ + Start: withTime(10, 2), + End: withTime(10, 4), + }, + }, + { + Key: "a", + Data: nil, + EventTime: withTime(10, 28), + Window: &Window{ + Start: withTime(10, 27), + End: withTime(10, 29), + }, + }, + { + Key: "a", + Data: nil, + EventTime: withTime(10, 28), + Window: &Window{ + Start: withTime(10, 28), + End: withTime(10, 30), + }, + }, + } + + assert.Len(t, result, 4) + if !assert.Equal(t, expected, result) { + for idx := range result { + printWindow(result[idx].Window) + printWindow(expected[idx].Window) + } + } + }) + t.Run("assign fixed windows", func(t *testing.T) { + result := AssignWindows(list, &FixedWindow{ + Width: 30 * time.Minute, + }) + expected := []Item{ + { + Key: "a", + Data: nil, + EventTime: withTime(10, 2), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 30), + }, + }, + { + Key: "a", + Data: nil, + EventTime: withTime(10, 28), + Window: &Window{ + Start: withTime(10, 0), + End: withTime(10, 30), + }, + }, + } + + assert.Equal(t, expected, result) + }) +} + +func TestMergeWindows(t *testing.T) { + if os.Getenv("RUN_EXPERIMENTAL_TEST") == "false" { + t.Skip(`Skipping test because: +- RUN_EXPERIMENTAL_TEST=false is set. +`) + } + + list := []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + }, + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + }, + } + + list2 := AssignWindows(list, &SessionWindow{ + GapDuration: 30 * time.Minute, + }) + assert.Equal(t, []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 32), + }, + }, + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + Window: &Window{ + Start: withTime(13, 20), + End: withTime(13, 50), + }, + }, + }, list2, "AssignWindows") + + list3 := DropTimestamps(list2) + assert.Equal(t, []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 32), + }, + }, + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 20), + End: withTime(13, 50), + }, + }, + }, list3, "DropTimestamps") + + list4 := GroupByKey(list3) + assert.Equal(t, []ItemGroupedByKey{ + { + Key: "k1", + Data: []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 32), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 20), + End: withTime(13, 50), + }, + }, + }, + }, + { + Key: "k2", + Data: []Item{ + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + }, + }, + }, list4, "GroupByKey") + + list5 := MergeWindows(list4, &SessionWindow{ + GapDuration: 30 * time.Minute, + }) + assert.Equal(t, []ItemGroupedByKey{ + { + Key: "k1", + Data: []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 50), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 50), + }, + }, + }, + }, + { + Key: "k2", + Data: []Item{ + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: 0, + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + }, + }, + }, list5, "MergeWindows") + + list6 := GroupAlsoByWindow(list5) + assert.Equal(t, []ItemGroupedByWindow{ + { + Key: "k1", + Data: schema.MkList(schema.MkString("v1"), schema.MkString("v4")), + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 50), + }, + }, + { + Key: "k1", + Data: schema.MkList(schema.MkString("v3")), + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k2", + Data: schema.MkList(schema.MkString("v2")), + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + }, list6, "GroupAlsoByWindow") + + list7 := ExpandToElements(list6) + assert.Equal(t, []Item{ + { + Key: "k1", + Data: schema.MkList(schema.MkString("v1"), schema.MkString("v4")), + EventTime: withTime(13, 50), + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 50), + }, + }, + { + Key: "k1", + Data: schema.MkList(schema.MkString("v3")), + EventTime: withTime(14, 27), + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k2", + Data: schema.MkList(schema.MkString("v2")), + EventTime: withTime(13, 44), + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + }, list7) +} + +func TestWindowMerginOnly(t *testing.T) { + if os.Getenv("RUN_EXPERIMENTAL_TEST") == "false" { + t.Skip(`Skipping test because: +- RUN_EXPERIMENTAL_TEST=false is set. +`) + } + + list := []ItemGroupedByKey{ + { + Key: "k1", + Data: []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + }, + }, + }, + { + Key: "k2", + Data: []Item{ + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + }, + }, + }, + } + + t.Run("merge session windows", func(t *testing.T) { + window := &SessionWindow{ + GapDuration: 30 * time.Minute, + } + var list2 []ItemGroupedByKey + for _, item := range list { + list2 = append(list2, ItemGroupedByKey{ + Key: item.Key, + Data: AssignWindows(item.Data, window), + }) + } + result := MergeWindows(list2, window) + assert.Equal(t, []ItemGroupedByKey{ + { + Key: "k1", + Data: []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 50), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + Window: &Window{ + Start: withTime(13, 57), + End: withTime(14, 27), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 50), + }, + }, + }, + }, + { + Key: "k2", + Data: []Item{ + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 44), + }, + }, + }, + }, + }, result, "MergeWindows") + }) + t.Run("merge sliding windows", func(t *testing.T) { + window := &SlidingWindow{ + Width: 2 * time.Minute, + Period: 1 * time.Minute, + } + var list2 []ItemGroupedByKey + for _, item := range list { + list2 = append(list2, ItemGroupedByKey{ + Key: item.Key, + Data: AssignWindows(item.Data, window), + }) + } + + result := MergeWindows(list2, window) + assert.Equal(t, []ItemGroupedByKey{ + { + Key: "k1", + Data: []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + Window: &Window{ + Start: withTime(13, 1), + End: withTime(13, 3), + }, + }, + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + Window: &Window{ + Start: withTime(13, 2), + End: withTime(13, 4), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + Window: &Window{ + Start: withTime(13, 56), + End: withTime(13, 58), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + Window: &Window{ + Start: withTime(13, 57), + End: withTime(13, 59), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + Window: &Window{ + Start: withTime(13, 19), + End: withTime(13, 21), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + Window: &Window{ + Start: withTime(13, 20), + End: withTime(13, 22), + }, + }, + }, + }, + { + Key: "k2", + Data: []Item{ + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + Window: &Window{ + Start: withTime(13, 13), + End: withTime(13, 15), + }, + }, + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + Window: &Window{ + Start: withTime(13, 14), + End: withTime(13, 16), + }, + }, + }, + }, + }, result, "MergeWindows") + }) + t.Run("merge fixed windows", func(t *testing.T) { + window := &FixedWindow{ + Width: 30 * time.Minute, + } + var list2 []ItemGroupedByKey + for _, item := range list { + list2 = append(list2, ItemGroupedByKey{ + Key: item.Key, + Data: AssignWindows(item.Data, window), + }) + } + result := MergeWindows(list2, window) + assert.Equal(t, []ItemGroupedByKey{ + { + Key: "k1", + Data: []Item{ + { + Key: "k1", + Data: schema.MkString("v1"), + EventTime: withTime(13, 2), + Window: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + }, + { + Key: "k1", + Data: schema.MkString("v3"), + EventTime: withTime(13, 57), + Window: &Window{ + Start: withTime(13, 30), + End: withTime(14, 0), + }, + }, + { + Key: "k1", + Data: schema.MkString("v4"), + EventTime: withTime(13, 20), + Window: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + }, + }, + }, + { + Key: "k2", + Data: []Item{ + { + Key: "k2", + Data: schema.MkString("v2"), + EventTime: withTime(13, 14), + Window: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + }, + }, + }, + }, result, "MergeWindows") + + byWindow := GroupAlsoByWindow(result) + + assert.Equal(t, []ItemGroupedByWindow{ + { + Key: "k1", + Data: schema.MkList(schema.MkString("v1"), schema.MkString("v4")), + Window: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + }, + { + Key: "k1", + Data: schema.MkList(schema.MkString("v3")), + Window: &Window{ + Start: withTime(13, 30), + End: withTime(14, 0), + }, + }, + { + Key: "k2", + Data: schema.MkList(schema.MkString("v2")), + Window: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + }, + }, byWindow, "MergeWindows") + }) +} + +type triggerCase struct { + trigger TriggerType + shouldTrigger bool +} + +func TestWindowTrigger(t *testing.T) { + if os.Getenv("RUN_EXPERIMENTAL_TEST") == "false" { + t.Skip(`Skipping test because: +- RUN_EXPERIMENTAL_TEST=false is set. +`) + } + + useCases := map[string]struct { + w *Window + td TriggerDescription + events []triggerCase + }{ + "should trigger aways at correct AtPeriod": { + w: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + td: &AtPeriod{ + Duration: 10 * time.Minute, + }, + events: []triggerCase{ + { + trigger: &AtPeriod{ + Duration: 1 * time.Minute, + }, + shouldTrigger: false, + }, + { + trigger: &AtPeriod{ + Duration: 10 * time.Minute, + }, + shouldTrigger: true, + }, + // at this point, we know that we see all triggers + // that window need to be flushed + { + trigger: &AtPeriod{ + Duration: 10 * time.Minute, + }, + shouldTrigger: true, + }, + { + trigger: &AtPeriod{ + Duration: 1 * time.Minute, + }, + shouldTrigger: true, + }, + { + trigger: &AtPeriod{ + Duration: 10 * time.Minute, + }, + shouldTrigger: true, + }, + }, + }, + "should trigger when all conditions are true": { + w: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + td: &AllOf{ + Triggers: []TriggerDescription{ + &AtPeriod{ + Duration: 10 * time.Minute, + }, + &AtPeriod{ + Duration: 1 * time.Minute, + }, + }, + }, + events: []triggerCase{ + { + trigger: &AtPeriod{ + Duration: 1 * time.Minute, + }, + shouldTrigger: false, + }, + { + trigger: &AtPeriod{ + Duration: 3 * time.Minute, + }, + shouldTrigger: false, + }, + { + trigger: &AtPeriod{ + Duration: 10 * time.Minute, + }, + shouldTrigger: true, + }, + }, + }, + "should trigger when any conditions are true": { + w: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + td: &AnyOf{ + Triggers: []TriggerDescription{ + &AtPeriod{ + Duration: 10 * time.Minute, + }, + &AtWindowItemSize{ + Number: 2, + }, + }, + }, + events: []triggerCase{ + { + trigger: &AtWindowItemSize{ + Number: 1, + }, + shouldTrigger: false, + }, + { + trigger: &AtPeriod{ + Duration: 10 * time.Minute, + }, + shouldTrigger: true, + }, + }, + }, + "should trigger window flush after timeout, but if watermark says that there are events that will fall under this window, then let's wait": { + w: &Window{ + Start: withTime(13, 0), + End: withTime(13, 30), + }, + td: &AnyOf{ + Triggers: []TriggerDescription{ + // when watermark says that there most likely won't be any older events + // so that we can flush this window + &AtWatermark{}, + // or we are at flush period, but watermark haven't reached this window yet + // so wait, and flush imminently, when watermark will reach this window + &AllOf{ + Triggers: []TriggerDescription{ + &AtWatermark{}, + &AtPeriod{ + Duration: 10 * time.Minute, + }, + }, + }, + // for very low latency granularity, we can flush window on every event + &AtWindowItemSize{ + Number: 1, + }, + }, + }, + events: []triggerCase{ + { + trigger: &AtPeriod{ + Duration: 10 * time.Minute, + }, + shouldTrigger: false, + }, + { + trigger: &AtWatermark{ + // watermark is at 13:00, so we should wait, since window ends at 13:30 + Timestamp: withTime(13, 0), + }, + shouldTrigger: false, + }, + { + trigger: &AtWatermark{ + Timestamp: withTime(13, 30), + }, + shouldTrigger: true, + }, + }, + }, + } + for name, uc := range useCases { + t.Run(name, func(t *testing.T) { + wt := NewWindowTrigger(uc.w, uc.td) + for idx, event := range uc.events { + wt.ReceiveEvent(event.trigger) + + if event.shouldTrigger { + assert.Truef(t, wt.ShouldTrigger(), "should flush on trigger but didn't; idx=%d", idx) + } else { + assert.Falsef(t, wt.ShouldTrigger(), "should NOT flush on trigger but did; idx=%d", idx) + } + } + }) + } +} diff --git a/x/storage/schemaless/projection/windowing_union_gen.go b/x/storage/schemaless/projection/windowing_union_gen.go new file mode 100644 index 00000000..6817e74d --- /dev/null +++ b/x/storage/schemaless/projection/windowing_union_gen.go @@ -0,0 +1,443 @@ +// Code generated by mkunion. DO NOT EDIT. +package projection + +import ( + "encoding/json" + "fmt" + "github.com/widmogrod/mkunion/x/shared" + "time" +) + +type WindowDescriptionVisitor interface { + VisitSessionWindow(v *SessionWindow) any + VisitSlidingWindow(v *SlidingWindow) any + VisitFixedWindow(v *FixedWindow) any +} + +type WindowDescription interface { + AcceptWindowDescription(g WindowDescriptionVisitor) any +} + +var ( + _ WindowDescription = (*SessionWindow)(nil) + _ WindowDescription = (*SlidingWindow)(nil) + _ WindowDescription = (*FixedWindow)(nil) +) + +func (r *SessionWindow) AcceptWindowDescription(v WindowDescriptionVisitor) any { + return v.VisitSessionWindow(r) +} +func (r *SlidingWindow) AcceptWindowDescription(v WindowDescriptionVisitor) any { + return v.VisitSlidingWindow(r) +} +func (r *FixedWindow) AcceptWindowDescription(v WindowDescriptionVisitor) any { + return v.VisitFixedWindow(r) +} + +func MatchWindowDescriptionR3[T0, T1, T2 any]( + x WindowDescription, + f1 func(x *SessionWindow) (T0, T1, T2), + f2 func(x *SlidingWindow) (T0, T1, T2), + f3 func(x *FixedWindow) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *SessionWindow: + return f1(v) + case *SlidingWindow: + return f2(v) + case *FixedWindow: + return f3(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchWindowDescriptionR2[T0, T1 any]( + x WindowDescription, + f1 func(x *SessionWindow) (T0, T1), + f2 func(x *SlidingWindow) (T0, T1), + f3 func(x *FixedWindow) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *SessionWindow: + return f1(v) + case *SlidingWindow: + return f2(v) + case *FixedWindow: + return f3(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchWindowDescriptionR1[T0 any]( + x WindowDescription, + f1 func(x *SessionWindow) T0, + f2 func(x *SlidingWindow) T0, + f3 func(x *FixedWindow) T0, +) T0 { + switch v := x.(type) { + case *SessionWindow: + return f1(v) + case *SlidingWindow: + return f2(v) + case *FixedWindow: + return f3(v) + } + var result1 T0 + return result1 +} + +func MatchWindowDescriptionR0( + x WindowDescription, + f1 func(x *SessionWindow), + f2 func(x *SlidingWindow), + f3 func(x *FixedWindow), +) { + switch v := x.(type) { + case *SessionWindow: + f1(v) + case *SlidingWindow: + f2(v) + case *FixedWindow: + f3(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.WindowDescription", WindowDescriptionFromJSON, WindowDescriptionToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.SessionWindow", SessionWindowFromJSON, SessionWindowToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.SlidingWindow", SlidingWindowFromJSON, SlidingWindowToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/storage/schemaless/projection.FixedWindow", FixedWindowFromJSON, FixedWindowToJSON) +} + +type WindowDescriptionUnionJSON struct { + Type string `json:"$type,omitempty"` + SessionWindow json.RawMessage `json:"projection.SessionWindow,omitempty"` + SlidingWindow json.RawMessage `json:"projection.SlidingWindow,omitempty"` + FixedWindow json.RawMessage `json:"projection.FixedWindow,omitempty"` +} + +func WindowDescriptionFromJSON(x []byte) (WindowDescription, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data WindowDescriptionUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "projection.SessionWindow": + return SessionWindowFromJSON(data.SessionWindow) + case "projection.SlidingWindow": + return SlidingWindowFromJSON(data.SlidingWindow) + case "projection.FixedWindow": + return FixedWindowFromJSON(data.FixedWindow) + } + + if data.SessionWindow != nil { + return SessionWindowFromJSON(data.SessionWindow) + } else if data.SlidingWindow != nil { + return SlidingWindowFromJSON(data.SlidingWindow) + } else if data.FixedWindow != nil { + return FixedWindowFromJSON(data.FixedWindow) + } + + return nil, fmt.Errorf("projection.WindowDescription: unknown type %s", data.Type) +} + +func WindowDescriptionToJSON(x WindowDescription) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchWindowDescriptionR2( + x, + func(x *SessionWindow) ([]byte, error) { + body, err := SessionWindowToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WindowDescriptionUnionJSON{ + Type: "projection.SessionWindow", + SessionWindow: body, + }) + }, + func(x *SlidingWindow) ([]byte, error) { + body, err := SlidingWindowToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WindowDescriptionUnionJSON{ + Type: "projection.SlidingWindow", + SlidingWindow: body, + }) + }, + func(x *FixedWindow) ([]byte, error) { + body, err := FixedWindowToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WindowDescriptionUnionJSON{ + Type: "projection.FixedWindow", + FixedWindow: body, + }) + }, + ) +} + +func SessionWindowFromJSON(x []byte) (*SessionWindow, error) { + result := new(SessionWindow) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func SessionWindowToJSON(x *SessionWindow) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*SessionWindow)(nil) + _ json.Marshaler = (*SessionWindow)(nil) +) + +func (r *SessionWindow) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONSessionWindow(*r) +} +func (r *SessionWindow) _marshalJSONSessionWindow(x SessionWindow) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldGapDuration []byte + fieldGapDuration, err = r._marshalJSONtime_Duration(x.GapDuration) + if err != nil { + return nil, fmt.Errorf("projection: SessionWindow._marshalJSONSessionWindow: field name GapDuration; %w", err) + } + partial["GapDuration"] = fieldGapDuration + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: SessionWindow._marshalJSONSessionWindow: struct; %w", err) + } + return result, nil +} +func (r *SessionWindow) _marshalJSONtime_Duration(x time.Duration) ([]byte, error) { + result, err := shared.JSONMarshal[time.Duration](x) + if err != nil { + return nil, fmt.Errorf("projection: SessionWindow._marshalJSONtime_Duration:; %w", err) + } + return result, nil +} +func (r *SessionWindow) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONSessionWindow(data) + if err != nil { + return fmt.Errorf("projection: SessionWindow.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *SessionWindow) _unmarshalJSONSessionWindow(data []byte) (SessionWindow, error) { + result := SessionWindow{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: SessionWindow._unmarshalJSONSessionWindow: native struct unwrap; %w", err) + } + if fieldGapDuration, ok := partial["GapDuration"]; ok { + result.GapDuration, err = r._unmarshalJSONtime_Duration(fieldGapDuration) + if err != nil { + return result, fmt.Errorf("projection: SessionWindow._unmarshalJSONSessionWindow: field GapDuration; %w", err) + } + } + return result, nil +} +func (r *SessionWindow) _unmarshalJSONtime_Duration(data []byte) (time.Duration, error) { + result, err := shared.JSONUnmarshal[time.Duration](data) + if err != nil { + return result, fmt.Errorf("projection: SessionWindow._unmarshalJSONtime_Duration: native ref unwrap; %w", err) + } + return result, nil +} + +func SlidingWindowFromJSON(x []byte) (*SlidingWindow, error) { + result := new(SlidingWindow) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func SlidingWindowToJSON(x *SlidingWindow) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*SlidingWindow)(nil) + _ json.Marshaler = (*SlidingWindow)(nil) +) + +func (r *SlidingWindow) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONSlidingWindow(*r) +} +func (r *SlidingWindow) _marshalJSONSlidingWindow(x SlidingWindow) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldWidth []byte + fieldWidth, err = r._marshalJSONtime_Duration(x.Width) + if err != nil { + return nil, fmt.Errorf("projection: SlidingWindow._marshalJSONSlidingWindow: field name Width; %w", err) + } + partial["Width"] = fieldWidth + var fieldPeriod []byte + fieldPeriod, err = r._marshalJSONtime_Duration(x.Period) + if err != nil { + return nil, fmt.Errorf("projection: SlidingWindow._marshalJSONSlidingWindow: field name Period; %w", err) + } + partial["Period"] = fieldPeriod + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: SlidingWindow._marshalJSONSlidingWindow: struct; %w", err) + } + return result, nil +} +func (r *SlidingWindow) _marshalJSONtime_Duration(x time.Duration) ([]byte, error) { + result, err := shared.JSONMarshal[time.Duration](x) + if err != nil { + return nil, fmt.Errorf("projection: SlidingWindow._marshalJSONtime_Duration:; %w", err) + } + return result, nil +} +func (r *SlidingWindow) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONSlidingWindow(data) + if err != nil { + return fmt.Errorf("projection: SlidingWindow.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *SlidingWindow) _unmarshalJSONSlidingWindow(data []byte) (SlidingWindow, error) { + result := SlidingWindow{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: SlidingWindow._unmarshalJSONSlidingWindow: native struct unwrap; %w", err) + } + if fieldWidth, ok := partial["Width"]; ok { + result.Width, err = r._unmarshalJSONtime_Duration(fieldWidth) + if err != nil { + return result, fmt.Errorf("projection: SlidingWindow._unmarshalJSONSlidingWindow: field Width; %w", err) + } + } + if fieldPeriod, ok := partial["Period"]; ok { + result.Period, err = r._unmarshalJSONtime_Duration(fieldPeriod) + if err != nil { + return result, fmt.Errorf("projection: SlidingWindow._unmarshalJSONSlidingWindow: field Period; %w", err) + } + } + return result, nil +} +func (r *SlidingWindow) _unmarshalJSONtime_Duration(data []byte) (time.Duration, error) { + result, err := shared.JSONUnmarshal[time.Duration](data) + if err != nil { + return result, fmt.Errorf("projection: SlidingWindow._unmarshalJSONtime_Duration: native ref unwrap; %w", err) + } + return result, nil +} + +func FixedWindowFromJSON(x []byte) (*FixedWindow, error) { + result := new(FixedWindow) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func FixedWindowToJSON(x *FixedWindow) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*FixedWindow)(nil) + _ json.Marshaler = (*FixedWindow)(nil) +) + +func (r *FixedWindow) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONFixedWindow(*r) +} +func (r *FixedWindow) _marshalJSONFixedWindow(x FixedWindow) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldWidth []byte + fieldWidth, err = r._marshalJSONtime_Duration(x.Width) + if err != nil { + return nil, fmt.Errorf("projection: FixedWindow._marshalJSONFixedWindow: field name Width; %w", err) + } + partial["Width"] = fieldWidth + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("projection: FixedWindow._marshalJSONFixedWindow: struct; %w", err) + } + return result, nil +} +func (r *FixedWindow) _marshalJSONtime_Duration(x time.Duration) ([]byte, error) { + result, err := shared.JSONMarshal[time.Duration](x) + if err != nil { + return nil, fmt.Errorf("projection: FixedWindow._marshalJSONtime_Duration:; %w", err) + } + return result, nil +} +func (r *FixedWindow) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONFixedWindow(data) + if err != nil { + return fmt.Errorf("projection: FixedWindow.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *FixedWindow) _unmarshalJSONFixedWindow(data []byte) (FixedWindow, error) { + result := FixedWindow{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("projection: FixedWindow._unmarshalJSONFixedWindow: native struct unwrap; %w", err) + } + if fieldWidth, ok := partial["Width"]; ok { + result.Width, err = r._unmarshalJSONtime_Duration(fieldWidth) + if err != nil { + return result, fmt.Errorf("projection: FixedWindow._unmarshalJSONFixedWindow: field Width; %w", err) + } + } + return result, nil +} +func (r *FixedWindow) _unmarshalJSONtime_Duration(data []byte) (time.Duration, error) { + result, err := shared.JSONUnmarshal[time.Duration](data) + if err != nil { + return result, fmt.Errorf("projection: FixedWindow._unmarshalJSONtime_Duration: native ref unwrap; %w", err) + } + return result, nil +} diff --git a/x/storage/schemaless/storage.go b/x/storage/schemaless/storage.go index f7097da0..51b6f2f8 100644 --- a/x/storage/schemaless/storage.go +++ b/x/storage/schemaless/storage.go @@ -6,7 +6,7 @@ import ( "github.com/widmogrod/mkunion/x/storage/predicate" ) -//go:generate go run ../../../cmd/mkunion/main.go serde +//go:generate go run ../../../cmd/mkunion/main.go type RecordType = string type Repository[T any] interface { diff --git a/x/storage/schemaless/storage_serde_gen.go b/x/storage/schemaless/storage_serde_gen.go index 5dad522c..0f20e119 100644 --- a/x/storage/schemaless/storage_serde_gen.go +++ b/x/storage/schemaless/storage_serde_gen.go @@ -4,130 +4,9 @@ package schemaless import ( "encoding/json" "fmt" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(SortFieldShape()) - shape.Register(PageResultShape()) - shape.Register(RecordShape()) -} - -var ( - _ json.Unmarshaler = (*SortField)(nil) - _ json.Marshaler = (*SortField)(nil) -) - -func (r *SortField) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil - } - return r._marshalJSONSortField(*r) -} -func (r *SortField) _marshalJSONSortField(x SortField) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - var fieldField []byte - fieldField, err = r._marshalJSONstring(x.Field) - if err != nil { - return nil, fmt.Errorf("schemaless: SortField._marshalJSONSortField: field name Field; %w", err) - } - partial["Field"] = fieldField - var fieldDescending []byte - fieldDescending, err = r._marshalJSONbool(x.Descending) - if err != nil { - return nil, fmt.Errorf("schemaless: SortField._marshalJSONSortField: field name Descending; %w", err) - } - partial["Descending"] = fieldDescending - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("schemaless: SortField._marshalJSONSortField: struct; %w", err) - } - return result, nil -} -func (r *SortField) _marshalJSONstring(x string) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("schemaless: SortField._marshalJSONstring:; %w", err) - } - return result, nil -} -func (r *SortField) _marshalJSONbool(x bool) ([]byte, error) { - result, err := json.Marshal(x) - if err != nil { - return nil, fmt.Errorf("schemaless: SortField._marshalJSONbool:; %w", err) - } - return result, nil -} -func (r *SortField) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONSortField(data) - if err != nil { - return fmt.Errorf("schemaless: SortField.UnmarshalJSON: %w", err) - } - *r = result - return nil -} -func (r *SortField) _unmarshalJSONSortField(data []byte) (SortField, error) { - result := SortField{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("schemaless: SortField._unmarshalJSONSortField: native struct unwrap; %w", err) - } - if fieldField, ok := partial["Field"]; ok { - result.Field, err = r._unmarshalJSONstring(fieldField) - if err != nil { - return result, fmt.Errorf("schemaless: SortField._unmarshalJSONSortField: field Field; %w", err) - } - } - if fieldDescending, ok := partial["Descending"]; ok { - result.Descending, err = r._unmarshalJSONbool(fieldDescending) - if err != nil { - return result, fmt.Errorf("schemaless: SortField._unmarshalJSONSortField: field Descending; %w", err) - } - } - return result, nil -} -func (r *SortField) _unmarshalJSONstring(data []byte) (string, error) { - var result string - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("schemaless: SortField._unmarshalJSONstring: native primitive unwrap; %w", err) - } - return result, nil -} -func (r *SortField) _unmarshalJSONbool(data []byte) (bool, error) { - var result bool - err := json.Unmarshal(data, &result) - if err != nil { - return result, fmt.Errorf("schemaless: SortField._unmarshalJSONbool: native primitive unwrap; %w", err) - } - return result, nil -} -func SortFieldShape() shape.Shape { - return &shape.StructLike{ - Name: "SortField", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - Fields: []*shape.FieldLike{ - { - Name: "Field", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Descending", - Type: &shape.PrimitiveLike{Kind: &shape.BooleanLike{}}, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} - var ( _ json.Unmarshaler = (*PageResult[any])(nil) _ json.Marshaler = (*PageResult[any])(nil) @@ -283,70 +162,6 @@ func (r *PageResult[A]) _unmarshalJSONFindingRecordsLb_A_bL(data []byte) (Findin } return result, nil } -func PageResultShape() shape.Shape { - return &shape.StructLike{ - Name: "PageResult", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - TypeParams: []shape.TypeParam{ - shape.TypeParam{ - Name: "A", - Type: &shape.Any{}, - }, - }, - Fields: []*shape.FieldLike{ - { - Name: "Items", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - }, - }, - { - Name: "Next", - Type: &shape.PointerLike{ - Type: &shape.RefName{ - Name: "FindingRecords", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - Indexed: []shape.Shape{ - &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - }, - }, - }, - }, - { - Name: "Prev", - Type: &shape.PointerLike{ - Type: &shape.RefName{ - Name: "FindingRecords", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - Indexed: []shape.Shape{ - &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - }, - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} var ( _ json.Unmarshaler = (*Record[any])(nil) @@ -477,47 +292,95 @@ func (r *Record[A]) _unmarshalJSONuint16(data []byte) (uint16, error) { } return result, nil } -func RecordShape() shape.Shape { - return &shape.StructLike{ - Name: "Record", - PkgName: "schemaless", - PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", - TypeParams: []shape.TypeParam{ - shape.TypeParam{ - Name: "A", - Type: &shape.Any{}, - }, - }, - Fields: []*shape.FieldLike{ - { - Name: "ID", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Type", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Data", - Type: &shape.RefName{ - Name: "A", - PkgName: "", - PkgImportName: "", - }, - }, - { - Name: "Version", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.UInt16{}, - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, + +var ( + _ json.Unmarshaler = (*SortField)(nil) + _ json.Marshaler = (*SortField)(nil) +) + +func (r *SortField) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONSortField(*r) +} +func (r *SortField) _marshalJSONSortField(x SortField) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldField []byte + fieldField, err = r._marshalJSONstring(x.Field) + if err != nil { + return nil, fmt.Errorf("schemaless: SortField._marshalJSONSortField: field name Field; %w", err) + } + partial["Field"] = fieldField + var fieldDescending []byte + fieldDescending, err = r._marshalJSONbool(x.Descending) + if err != nil { + return nil, fmt.Errorf("schemaless: SortField._marshalJSONSortField: field name Descending; %w", err) + } + partial["Descending"] = fieldDescending + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("schemaless: SortField._marshalJSONSortField: struct; %w", err) + } + return result, nil +} +func (r *SortField) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("schemaless: SortField._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *SortField) _marshalJSONbool(x bool) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("schemaless: SortField._marshalJSONbool:; %w", err) + } + return result, nil +} +func (r *SortField) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONSortField(data) + if err != nil { + return fmt.Errorf("schemaless: SortField.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *SortField) _unmarshalJSONSortField(data []byte) (SortField, error) { + result := SortField{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("schemaless: SortField._unmarshalJSONSortField: native struct unwrap; %w", err) + } + if fieldField, ok := partial["Field"]; ok { + result.Field, err = r._unmarshalJSONstring(fieldField) + if err != nil { + return result, fmt.Errorf("schemaless: SortField._unmarshalJSONSortField: field Field; %w", err) + } } + if fieldDescending, ok := partial["Descending"]; ok { + result.Descending, err = r._unmarshalJSONbool(fieldDescending) + if err != nil { + return result, fmt.Errorf("schemaless: SortField._unmarshalJSONSortField: field Descending; %w", err) + } + } + return result, nil +} +func (r *SortField) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("schemaless: SortField._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *SortField) _unmarshalJSONbool(data []byte) (bool, error) { + var result bool + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("schemaless: SortField._unmarshalJSONbool: native primitive unwrap; %w", err) + } + return result, nil } diff --git a/x/storage/schemaless/storage_shape_gen.go b/x/storage/schemaless/storage_shape_gen.go new file mode 100644 index 00000000..d54e5f5e --- /dev/null +++ b/x/storage/schemaless/storage_shape_gen.go @@ -0,0 +1,305 @@ +// Code generated by mkunion. DO NOT EDIT. +package schemaless + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(CursorShape()) + shape.Register(FindingRecordsShape()) + shape.Register(PageResultShape()) + shape.Register(RecordShape()) + shape.Register(RecordTypeShape()) + shape.Register(SortFieldShape()) + shape.Register(UpdateRecordsShape()) + shape.Register(UpdatingPolicyShape()) +} + +//shape:shape +func CursorShape() shape.Shape { + return &shape.AliasLike{ + Name: "Cursor", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + IsAlias: true, + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + } +} + +//shape:shape +func FindingRecordsShape() shape.Shape { + return &shape.StructLike{ + Name: "FindingRecords", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "T", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "RecordType", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Where", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "WherePredicates", + PkgName: "predicate", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/predicate", + }, + }, + }, + { + Name: "Sort", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "SortField", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + }, + }, + }, + { + Name: "Limit", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.UInt8{}, + }, + }, + }, + { + Name: "After", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "Cursor", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + }, + }, + }, + { + Name: "Before", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "Cursor", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + }, + }, + }, + }, + } +} + +//shape:shape +func SortFieldShape() shape.Shape { + return &shape.StructLike{ + Name: "SortField", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Fields: []*shape.FieldLike{ + { + Name: "Field", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Descending", + Type: &shape.PrimitiveLike{Kind: &shape.BooleanLike{}}, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func PageResultShape() shape.Shape { + return &shape.StructLike{ + Name: "PageResult", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "Items", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + }, + }, + { + Name: "Next", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "FindingRecords", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Indexed: []shape.Shape{ + &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + }, + }, + }, + }, + { + Name: "Prev", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "FindingRecords", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Indexed: []shape.Shape{ + &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + }, + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func RecordShape() shape.Shape { + return &shape.StructLike{ + Name: "Record", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "A", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "ID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Type", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Data", + Type: &shape.RefName{ + Name: "A", + PkgName: "", + PkgImportName: "", + }, + }, + { + Name: "Version", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.UInt16{}, + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func RecordTypeShape() shape.Shape { + return &shape.AliasLike{ + Name: "RecordType", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + IsAlias: true, + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + } +} + +//shape:shape +func UpdateRecordsShape() shape.Shape { + return &shape.StructLike{ + Name: "UpdateRecords", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + TypeParams: []shape.TypeParam{ + shape.TypeParam{ + Name: "T", + Type: &shape.Any{}, + }, + }, + Fields: []*shape.FieldLike{ + { + Name: "UpdatingPolicy", + Type: &shape.RefName{ + Name: "UpdatingPolicy", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + }, + }, + { + Name: "Saving", + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.RefName{ + Name: "T", + PkgName: "", + PkgImportName: "", + }, + }, + }, + { + Name: "Deleting", + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.RefName{ + Name: "T", + PkgName: "", + PkgImportName: "", + }, + }, + }, + }, + } +} + +//shape:shape +func UpdatingPolicyShape() shape.Shape { + return &shape.AliasLike{ + Name: "UpdatingPolicy", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.UInt{}, + }, + }, + } +} diff --git a/x/storage/schemaless/testutil.go b/x/storage/schemaless/testutil.go index b5d9c4c8..990d658f 100644 --- a/x/storage/schemaless/testutil.go +++ b/x/storage/schemaless/testutil.go @@ -1,6 +1,6 @@ package schemaless -//go:generate go run ../../../cmd/mkunion/main.go serde +//go:generate go run ../../../cmd/mkunion/main.go //go:tag serde:"json" type ExampleRecord struct { diff --git a/x/storage/schemaless/testutil_serde_gen.go b/x/storage/schemaless/testutil_serde_gen.go new file mode 100644 index 00000000..da914f60 --- /dev/null +++ b/x/storage/schemaless/testutil_serde_gen.go @@ -0,0 +1,99 @@ +// Code generated by mkunion. DO NOT EDIT. +package schemaless + +import ( + "encoding/json" + "fmt" +) + +var ( + _ json.Unmarshaler = (*ExampleRecord)(nil) + _ json.Marshaler = (*ExampleRecord)(nil) +) + +func (r *ExampleRecord) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONExampleRecord(*r) +} +func (r *ExampleRecord) _marshalJSONExampleRecord(x ExampleRecord) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) + if err != nil { + return nil, fmt.Errorf("schemaless: ExampleRecord._marshalJSONExampleRecord: field name Name; %w", err) + } + partial["Name"] = fieldName + var fieldAge []byte + fieldAge, err = r._marshalJSONint(x.Age) + if err != nil { + return nil, fmt.Errorf("schemaless: ExampleRecord._marshalJSONExampleRecord: field name Age; %w", err) + } + partial["Age"] = fieldAge + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("schemaless: ExampleRecord._marshalJSONExampleRecord: struct; %w", err) + } + return result, nil +} +func (r *ExampleRecord) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("schemaless: ExampleRecord._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *ExampleRecord) _marshalJSONint(x int) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("schemaless: ExampleRecord._marshalJSONint:; %w", err) + } + return result, nil +} +func (r *ExampleRecord) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONExampleRecord(data) + if err != nil { + return fmt.Errorf("schemaless: ExampleRecord.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *ExampleRecord) _unmarshalJSONExampleRecord(data []byte) (ExampleRecord, error) { + result := ExampleRecord{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("schemaless: ExampleRecord._unmarshalJSONExampleRecord: native struct unwrap; %w", err) + } + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) + if err != nil { + return result, fmt.Errorf("schemaless: ExampleRecord._unmarshalJSONExampleRecord: field Name; %w", err) + } + } + if fieldAge, ok := partial["Age"]; ok { + result.Age, err = r._unmarshalJSONint(fieldAge) + if err != nil { + return result, fmt.Errorf("schemaless: ExampleRecord._unmarshalJSONExampleRecord: field Age; %w", err) + } + } + return result, nil +} +func (r *ExampleRecord) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("schemaless: ExampleRecord._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *ExampleRecord) _unmarshalJSONint(data []byte) (int, error) { + var result int + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("schemaless: ExampleRecord._unmarshalJSONint: native primitive unwrap; %w", err) + } + return result, nil +} diff --git a/x/storage/schemaless/testutil_shape_gen.go b/x/storage/schemaless/testutil_shape_gen.go new file mode 100644 index 00000000..e900244a --- /dev/null +++ b/x/storage/schemaless/testutil_shape_gen.go @@ -0,0 +1,38 @@ +// Code generated by mkunion. DO NOT EDIT. +package schemaless + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(ExampleRecordShape()) +} + +//shape:shape +func ExampleRecordShape() shape.Shape { + return &shape.StructLike{ + Name: "ExampleRecord", + PkgName: "schemaless", + PkgImportName: "github.com/widmogrod/mkunion/x/storage/schemaless", + Fields: []*shape.FieldLike{ + { + Name: "Name", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Age", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int{}, + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} diff --git a/x/storage/schemaless/typedful/testutil.go b/x/storage/schemaless/typedful/testutil.go index f4e8313f..943deb91 100644 --- a/x/storage/schemaless/typedful/testutil.go +++ b/x/storage/schemaless/typedful/testutil.go @@ -2,15 +2,13 @@ package typedful import "github.com/widmogrod/mkunion/x/storage/schemaless" -//go:generate go run ../../../../cmd/mkunion/main.go serde +//go:generate go run ../../../../cmd/mkunion/main.go -//go:tag serde:"json" type User struct { Name string Age int } -//go:tag serde:"json" type UsersCountByAge struct { Count int } @@ -27,29 +25,33 @@ func AgeRangeKey(age int) string { } } -var exampleUserRecords = schemaless.Save( - schemaless.Record[User]{ - ID: "1", - Type: "user", - Data: User{ - Name: "John", - Age: 20, +var exampleUserRecords schemaless.UpdateRecords[schemaless.Record[User]] + +func init() { + exampleUserRecords = schemaless.Save( + schemaless.Record[User]{ + ID: "1", + Type: "user", + Data: User{ + Name: "John", + Age: 20, + }, }, - }, - schemaless.Record[User]{ - ID: "2", - Type: "user", - Data: User{ - Name: "Jane", - Age: 30, + schemaless.Record[User]{ + ID: "2", + Type: "user", + Data: User{ + Name: "Jane", + Age: 30, + }, }, - }, - schemaless.Record[User]{ - ID: "3", - Type: "user", - Data: User{ - Name: "Alice", - Age: 39, + schemaless.Record[User]{ + ID: "3", + Type: "user", + Data: User{ + Name: "Alice", + Age: 39, + }, }, - }, -) + ) +} diff --git a/x/workflow/workflow_machine.go b/x/workflow/workflow_machine.go index 547d94c5..7abbfe25 100644 --- a/x/workflow/workflow_machine.go +++ b/x/workflow/workflow_machine.go @@ -5,7 +5,6 @@ import ( ) //go:generate go run ../../cmd/mkunion/main.go -//go:generate go run ../../cmd/mkunion/main.go serde type Execution struct { FlowID string diff --git a/x/workflow/workflow_machine_serde_gen.go b/x/workflow/workflow_machine_serde_gen.go index 0d5cab5f..804aeb08 100644 --- a/x/workflow/workflow_machine_serde_gen.go +++ b/x/workflow/workflow_machine_serde_gen.go @@ -5,16 +5,9 @@ import ( "encoding/json" "fmt" "github.com/widmogrod/mkunion/x/schema" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(ApplyAwaitOptionsShape()) - shape.Register(BaseStateShape()) - shape.Register(ResumeOptionsShape()) -} - var ( _ json.Unmarshaler = (*ApplyAwaitOptions)(nil) _ json.Marshaler = (*ApplyAwaitOptions)(nil) @@ -79,28 +72,6 @@ func (r *ApplyAwaitOptions) _unmarshalJSONint64(data []byte) (int64, error) { } return result, nil } -func ApplyAwaitOptionsShape() shape.Shape { - return &shape.StructLike{ - Name: "ApplyAwaitOptions", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - Fields: []*shape.FieldLike{ - { - Name: "Timeout", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int64{}, - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} var ( _ json.Unmarshaler = (*BaseState)(nil) @@ -328,74 +299,6 @@ func (r *BaseState) _unmarshalJSONRunOption(data []byte) (RunOption, error) { } return result, nil } -func BaseStateShape() shape.Shape { - return &shape.StructLike{ - Name: "BaseState", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - Fields: []*shape.FieldLike{ - { - Name: "Flow", - Type: &shape.RefName{ - Name: "Workflow", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - }, - }, - { - Name: "RunID", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "StepID", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Variables", - Type: &shape.MapLike{ - Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - Val: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - }, - { - Name: "ExprResult", - Type: &shape.MapLike{ - Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - Val: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - }, - { - Name: "DefaultMaxRetries", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int64{}, - }, - }, - }, - { - Name: "RunOption", - Type: &shape.RefName{ - Name: "RunOption", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} var ( _ json.Unmarshaler = (*ResumeOptions)(nil) @@ -461,25 +364,3 @@ func (r *ResumeOptions) _unmarshalJSONint64(data []byte) (int64, error) { } return result, nil } -func ResumeOptionsShape() shape.Shape { - return &shape.StructLike{ - Name: "ResumeOptions", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - Fields: []*shape.FieldLike{ - { - Name: "Timeout", - Type: &shape.PrimitiveLike{ - Kind: &shape.NumberLike{ - Kind: &shape.Int64{}, - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} diff --git a/x/workflow/workflow_machine_shape_gen.go b/x/workflow/workflow_machine_shape_gen.go new file mode 100644 index 00000000..998e3387 --- /dev/null +++ b/x/workflow/workflow_machine_shape_gen.go @@ -0,0 +1,914 @@ +// Code generated by mkunion. DO NOT EDIT. +package workflow + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(AndShape()) + shape.Register(ApplyAwaitOptionsShape()) + shape.Register(ApplyShape()) + shape.Register(AssignShape()) + shape.Register(AwaitShape()) + shape.Register(BaseStateShape()) + shape.Register(CallbackShape()) + shape.Register(ChooseShape()) + shape.Register(CommandShape()) + shape.Register(CompareShape()) + shape.Register(DelayRunShape()) + shape.Register(DoneShape()) + shape.Register(EndShape()) + shape.Register(ErrorShape()) + shape.Register(ExecutionShape()) + shape.Register(ExprShape()) + shape.Register(FlowRefShape()) + shape.Register(FlowShape()) + shape.Register(GetValueShape()) + shape.Register(NextOperationShape()) + shape.Register(NotShape()) + shape.Register(OrShape()) + shape.Register(PredicateShape()) + shape.Register(ReshaperShape()) + shape.Register(ResumeOptionsShape()) + shape.Register(ResumeScheduleShape()) + shape.Register(RunOptionShape()) + shape.Register(RunShape()) + shape.Register(ScheduleRunShape()) + shape.Register(ScheduleStoppedShape()) + shape.Register(ScheduledShape()) + shape.Register(SetValueShape()) + shape.Register(StateShape()) + shape.Register(StopScheduleShape()) + shape.Register(TryRecoverShape()) + shape.Register(WorkflowShape()) +} + +//shape:shape + +func CommandShape() shape.Shape { + return &shape.UnionLike{ + Name: "Command", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + RunShape(), + CallbackShape(), + TryRecoverShape(), + StopScheduleShape(), + ResumeScheduleShape(), + }, + } +} + +func RunShape() shape.Shape { + return &shape.StructLike{ + Name: "Run", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Flow", + Type: &shape.RefName{ + Name: "Workflow", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + { + Name: "Input", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + { + Name: "RunOption", + Type: &shape.RefName{ + Name: "RunOption", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func CallbackShape() shape.Shape { + return &shape.StructLike{ + Name: "Callback", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "CallbackID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Result", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + } +} + +func TryRecoverShape() shape.Shape { + return &shape.StructLike{ + Name: "TryRecover", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "RunID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +func StopScheduleShape() shape.Shape { + return &shape.StructLike{ + Name: "StopSchedule", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ParentRunID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +func ResumeScheduleShape() shape.Shape { + return &shape.StructLike{ + Name: "ResumeSchedule", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ParentRunID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +//shape:shape + +func WorkflowShape() shape.Shape { + return &shape.UnionLike{ + Name: "Workflow", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + FlowShape(), + FlowRefShape(), + }, + } +} + +func FlowShape() shape.Shape { + return &shape.StructLike{ + Name: "Flow", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Name", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Arg", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Body", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Expr", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + }, + } +} + +func FlowRefShape() shape.Shape { + return &shape.StructLike{ + Name: "FlowRef", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "FlowID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +//shape:shape + +func RunOptionShape() shape.Shape { + return &shape.UnionLike{ + Name: "RunOption", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + ScheduleRunShape(), + DelayRunShape(), + }, + } +} + +func ScheduleRunShape() shape.Shape { + return &shape.StructLike{ + Name: "ScheduleRun", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Interval", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "ParentRunID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +func DelayRunShape() shape.Shape { + return &shape.StructLike{ + Name: "DelayRun", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "DelayBySeconds", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + }, + } +} + +//shape:shape + +func ExprShape() shape.Shape { + return &shape.UnionLike{ + Name: "Expr", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + EndShape(), + AssignShape(), + ApplyShape(), + ChooseShape(), + }, + } +} + +func EndShape() shape.Shape { + return &shape.StructLike{ + Name: "End", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Result", + Type: &shape.RefName{ + Name: "Reshaper", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func AssignShape() shape.Shape { + return &shape.StructLike{ + Name: "Assign", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "VarOk", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "VarErr", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Val", + Type: &shape.RefName{ + Name: "Expr", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func ApplyShape() shape.Shape { + return &shape.StructLike{ + Name: "Apply", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Name", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Args", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Reshaper", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + { + Name: "Await", + Type: &shape.PointerLike{ + Type: &shape.RefName{ + Name: "ApplyAwaitOptions", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + }, + } +} + +func ChooseShape() shape.Shape { + return &shape.StructLike{ + Name: "Choose", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "If", + Type: &shape.RefName{ + Name: "Predicate", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + { + Name: "Then", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Expr", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + { + Name: "Else", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Expr", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + }, + } +} + +//shape:shape + +func ReshaperShape() shape.Shape { + return &shape.UnionLike{ + Name: "Reshaper", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + GetValueShape(), + SetValueShape(), + }, + } +} + +func GetValueShape() shape.Shape { + return &shape.StructLike{ + Name: "GetValue", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Path", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + }, + } +} + +func SetValueShape() shape.Shape { + return &shape.StructLike{ + Name: "SetValue", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Value", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + } +} + +//shape:shape +func ApplyAwaitOptionsShape() shape.Shape { + return &shape.StructLike{ + Name: "ApplyAwaitOptions", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Timeout", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape + +func PredicateShape() shape.Shape { + return &shape.UnionLike{ + Name: "Predicate", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + AndShape(), + OrShape(), + NotShape(), + CompareShape(), + }, + } +} + +func AndShape() shape.Shape { + return &shape.StructLike{ + Name: "And", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "L", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Predicate", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + }, + } +} + +func OrShape() shape.Shape { + return &shape.StructLike{ + Name: "Or", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "L", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Predicate", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + }, + } +} + +func NotShape() shape.Shape { + return &shape.StructLike{ + Name: "Not", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "P", + Type: &shape.RefName{ + Name: "Predicate", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func CompareShape() shape.Shape { + return &shape.StructLike{ + Name: "Compare", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Operation", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Left", + Type: &shape.RefName{ + Name: "Reshaper", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + { + Name: "Right", + Type: &shape.RefName{ + Name: "Reshaper", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +//shape:shape + +func StateShape() shape.Shape { + return &shape.UnionLike{ + Name: "State", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Variant: []shape.Shape{ + NextOperationShape(), + DoneShape(), + ErrorShape(), + AwaitShape(), + ScheduledShape(), + ScheduleStoppedShape(), + }, + } +} + +func NextOperationShape() shape.Shape { + return &shape.StructLike{ + Name: "NextOperation", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Result", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + { + Name: "BaseState", + Type: &shape.RefName{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func DoneShape() shape.Shape { + return &shape.StructLike{ + Name: "Done", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Result", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + { + Name: "BaseState", + Type: &shape.RefName{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func ErrorShape() shape.Shape { + return &shape.StructLike{ + Name: "Error", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Code", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Reason", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Retried", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "BaseState", + Type: &shape.RefName{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func AwaitShape() shape.Shape { + return &shape.StructLike{ + Name: "Await", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "CallbackID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Timeout", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "BaseState", + Type: &shape.RefName{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func ScheduledShape() shape.Shape { + return &shape.StructLike{ + Name: "Scheduled", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "ExpectedRunTimestamp", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "BaseState", + Type: &shape.RefName{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +func ScheduleStoppedShape() shape.Shape { + return &shape.StructLike{ + Name: "ScheduleStopped", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "BaseState", + Type: &shape.RefName{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + } +} + +//shape:shape +func BaseStateShape() shape.Shape { + return &shape.StructLike{ + Name: "BaseState", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Flow", + Type: &shape.RefName{ + Name: "Workflow", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + { + Name: "RunID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "StepID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Variables", + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + { + Name: "ExprResult", + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + { + Name: "DefaultMaxRetries", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "RunOption", + Type: &shape.RefName{ + Name: "RunOption", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func ExecutionShape() shape.Shape { + return &shape.StructLike{ + Name: "Execution", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "FlowID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Status", + Type: &shape.RefName{ + Name: "State", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + }, + }, + { + Name: "Location", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "StartTime", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "EndTime", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + { + Name: "Variables", + Type: &shape.MapLike{ + Key: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + Val: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + }, + } +} + +//shape:shape +func ResumeOptionsShape() shape.Shape { + return &shape.StructLike{ + Name: "ResumeOptions", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Timeout", + Type: &shape.PrimitiveLike{ + Kind: &shape.NumberLike{ + Kind: &shape.Int64{}, + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} diff --git a/x/workflow/workflow_machine_union_gen.go b/x/workflow/workflow_machine_union_gen.go new file mode 100644 index 00000000..a4cbc812 --- /dev/null +++ b/x/workflow/workflow_machine_union_gen.go @@ -0,0 +1,4120 @@ +// Code generated by mkunion. DO NOT EDIT. +package workflow + +import ( + "encoding/json" + "fmt" + "github.com/widmogrod/mkunion/x/schema" + "github.com/widmogrod/mkunion/x/shared" +) + +type CommandVisitor interface { + VisitRun(v *Run) any + VisitCallback(v *Callback) any + VisitTryRecover(v *TryRecover) any + VisitStopSchedule(v *StopSchedule) any + VisitResumeSchedule(v *ResumeSchedule) any +} + +type Command interface { + AcceptCommand(g CommandVisitor) any +} + +var ( + _ Command = (*Run)(nil) + _ Command = (*Callback)(nil) + _ Command = (*TryRecover)(nil) + _ Command = (*StopSchedule)(nil) + _ Command = (*ResumeSchedule)(nil) +) + +func (r *Run) AcceptCommand(v CommandVisitor) any { return v.VisitRun(r) } +func (r *Callback) AcceptCommand(v CommandVisitor) any { return v.VisitCallback(r) } +func (r *TryRecover) AcceptCommand(v CommandVisitor) any { return v.VisitTryRecover(r) } +func (r *StopSchedule) AcceptCommand(v CommandVisitor) any { return v.VisitStopSchedule(r) } +func (r *ResumeSchedule) AcceptCommand(v CommandVisitor) any { return v.VisitResumeSchedule(r) } + +func MatchCommandR3[T0, T1, T2 any]( + x Command, + f1 func(x *Run) (T0, T1, T2), + f2 func(x *Callback) (T0, T1, T2), + f3 func(x *TryRecover) (T0, T1, T2), + f4 func(x *StopSchedule) (T0, T1, T2), + f5 func(x *ResumeSchedule) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *Run: + return f1(v) + case *Callback: + return f2(v) + case *TryRecover: + return f3(v) + case *StopSchedule: + return f4(v) + case *ResumeSchedule: + return f5(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchCommandR2[T0, T1 any]( + x Command, + f1 func(x *Run) (T0, T1), + f2 func(x *Callback) (T0, T1), + f3 func(x *TryRecover) (T0, T1), + f4 func(x *StopSchedule) (T0, T1), + f5 func(x *ResumeSchedule) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *Run: + return f1(v) + case *Callback: + return f2(v) + case *TryRecover: + return f3(v) + case *StopSchedule: + return f4(v) + case *ResumeSchedule: + return f5(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchCommandR1[T0 any]( + x Command, + f1 func(x *Run) T0, + f2 func(x *Callback) T0, + f3 func(x *TryRecover) T0, + f4 func(x *StopSchedule) T0, + f5 func(x *ResumeSchedule) T0, +) T0 { + switch v := x.(type) { + case *Run: + return f1(v) + case *Callback: + return f2(v) + case *TryRecover: + return f3(v) + case *StopSchedule: + return f4(v) + case *ResumeSchedule: + return f5(v) + } + var result1 T0 + return result1 +} + +func MatchCommandR0( + x Command, + f1 func(x *Run), + f2 func(x *Callback), + f3 func(x *TryRecover), + f4 func(x *StopSchedule), + f5 func(x *ResumeSchedule), +) { + switch v := x.(type) { + case *Run: + f1(v) + case *Callback: + f2(v) + case *TryRecover: + f3(v) + case *StopSchedule: + f4(v) + case *ResumeSchedule: + f5(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Command", CommandFromJSON, CommandToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Run", RunFromJSON, RunToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Callback", CallbackFromJSON, CallbackToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.TryRecover", TryRecoverFromJSON, TryRecoverToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.StopSchedule", StopScheduleFromJSON, StopScheduleToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.ResumeSchedule", ResumeScheduleFromJSON, ResumeScheduleToJSON) +} + +type CommandUnionJSON struct { + Type string `json:"$type,omitempty"` + Run json.RawMessage `json:"workflow.Run,omitempty"` + Callback json.RawMessage `json:"workflow.Callback,omitempty"` + TryRecover json.RawMessage `json:"workflow.TryRecover,omitempty"` + StopSchedule json.RawMessage `json:"workflow.StopSchedule,omitempty"` + ResumeSchedule json.RawMessage `json:"workflow.ResumeSchedule,omitempty"` +} + +func CommandFromJSON(x []byte) (Command, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data CommandUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.Run": + return RunFromJSON(data.Run) + case "workflow.Callback": + return CallbackFromJSON(data.Callback) + case "workflow.TryRecover": + return TryRecoverFromJSON(data.TryRecover) + case "workflow.StopSchedule": + return StopScheduleFromJSON(data.StopSchedule) + case "workflow.ResumeSchedule": + return ResumeScheduleFromJSON(data.ResumeSchedule) + } + + if data.Run != nil { + return RunFromJSON(data.Run) + } else if data.Callback != nil { + return CallbackFromJSON(data.Callback) + } else if data.TryRecover != nil { + return TryRecoverFromJSON(data.TryRecover) + } else if data.StopSchedule != nil { + return StopScheduleFromJSON(data.StopSchedule) + } else if data.ResumeSchedule != nil { + return ResumeScheduleFromJSON(data.ResumeSchedule) + } + + return nil, fmt.Errorf("workflow.Command: unknown type %s", data.Type) +} + +func CommandToJSON(x Command) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchCommandR2( + x, + func(x *Run) ([]byte, error) { + body, err := RunToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(CommandUnionJSON{ + Type: "workflow.Run", + Run: body, + }) + }, + func(x *Callback) ([]byte, error) { + body, err := CallbackToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(CommandUnionJSON{ + Type: "workflow.Callback", + Callback: body, + }) + }, + func(x *TryRecover) ([]byte, error) { + body, err := TryRecoverToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(CommandUnionJSON{ + Type: "workflow.TryRecover", + TryRecover: body, + }) + }, + func(x *StopSchedule) ([]byte, error) { + body, err := StopScheduleToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(CommandUnionJSON{ + Type: "workflow.StopSchedule", + StopSchedule: body, + }) + }, + func(x *ResumeSchedule) ([]byte, error) { + body, err := ResumeScheduleToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(CommandUnionJSON{ + Type: "workflow.ResumeSchedule", + ResumeSchedule: body, + }) + }, + ) +} + +func RunFromJSON(x []byte) (*Run, error) { + result := new(Run) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func RunToJSON(x *Run) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Run)(nil) + _ json.Marshaler = (*Run)(nil) +) + +func (r *Run) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONRun(*r) +} +func (r *Run) _marshalJSONRun(x Run) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldFlow []byte + fieldFlow, err = r._marshalJSONWorkflow(x.Flow) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONRun: field name Flow; %w", err) + } + partial["Flow"] = fieldFlow + var fieldInput []byte + fieldInput, err = r._marshalJSONschema_Schema(x.Input) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONRun: field name Input; %w", err) + } + partial["Input"] = fieldInput + var fieldRunOption []byte + fieldRunOption, err = r._marshalJSONRunOption(x.RunOption) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONRun: field name RunOption; %w", err) + } + partial["RunOption"] = fieldRunOption + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONRun: struct; %w", err) + } + return result, nil +} +func (r *Run) _marshalJSONWorkflow(x Workflow) ([]byte, error) { + result, err := shared.JSONMarshal[Workflow](x) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONWorkflow:; %w", err) + } + return result, nil +} +func (r *Run) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *Run) _marshalJSONRunOption(x RunOption) ([]byte, error) { + result, err := shared.JSONMarshal[RunOption](x) + if err != nil { + return nil, fmt.Errorf("workflow: Run._marshalJSONRunOption:; %w", err) + } + return result, nil +} +func (r *Run) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONRun(data) + if err != nil { + return fmt.Errorf("workflow: Run.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Run) _unmarshalJSONRun(data []byte) (Run, error) { + result := Run{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONRun: native struct unwrap; %w", err) + } + if fieldFlow, ok := partial["Flow"]; ok { + result.Flow, err = r._unmarshalJSONWorkflow(fieldFlow) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONRun: field Flow; %w", err) + } + } + if fieldInput, ok := partial["Input"]; ok { + result.Input, err = r._unmarshalJSONschema_Schema(fieldInput) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONRun: field Input; %w", err) + } + } + if fieldRunOption, ok := partial["RunOption"]; ok { + result.RunOption, err = r._unmarshalJSONRunOption(fieldRunOption) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONRun: field RunOption; %w", err) + } + } + return result, nil +} +func (r *Run) _unmarshalJSONWorkflow(data []byte) (Workflow, error) { + result, err := shared.JSONUnmarshal[Workflow](data) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONWorkflow: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Run) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Run) _unmarshalJSONRunOption(data []byte) (RunOption, error) { + result, err := shared.JSONUnmarshal[RunOption](data) + if err != nil { + return result, fmt.Errorf("workflow: Run._unmarshalJSONRunOption: native ref unwrap; %w", err) + } + return result, nil +} + +func CallbackFromJSON(x []byte) (*Callback, error) { + result := new(Callback) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func CallbackToJSON(x *Callback) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Callback)(nil) + _ json.Marshaler = (*Callback)(nil) +) + +func (r *Callback) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONCallback(*r) +} +func (r *Callback) _marshalJSONCallback(x Callback) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCallbackID []byte + fieldCallbackID, err = r._marshalJSONstring(x.CallbackID) + if err != nil { + return nil, fmt.Errorf("workflow: Callback._marshalJSONCallback: field name CallbackID; %w", err) + } + partial["CallbackID"] = fieldCallbackID + var fieldResult []byte + fieldResult, err = r._marshalJSONschema_Schema(x.Result) + if err != nil { + return nil, fmt.Errorf("workflow: Callback._marshalJSONCallback: field name Result; %w", err) + } + partial["Result"] = fieldResult + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Callback._marshalJSONCallback: struct; %w", err) + } + return result, nil +} +func (r *Callback) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Callback._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Callback) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("workflow: Callback._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *Callback) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONCallback(data) + if err != nil { + return fmt.Errorf("workflow: Callback.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Callback) _unmarshalJSONCallback(data []byte) (Callback, error) { + result := Callback{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Callback._unmarshalJSONCallback: native struct unwrap; %w", err) + } + if fieldCallbackID, ok := partial["CallbackID"]; ok { + result.CallbackID, err = r._unmarshalJSONstring(fieldCallbackID) + if err != nil { + return result, fmt.Errorf("workflow: Callback._unmarshalJSONCallback: field CallbackID; %w", err) + } + } + if fieldResult, ok := partial["Result"]; ok { + result.Result, err = r._unmarshalJSONschema_Schema(fieldResult) + if err != nil { + return result, fmt.Errorf("workflow: Callback._unmarshalJSONCallback: field Result; %w", err) + } + } + return result, nil +} +func (r *Callback) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Callback._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Callback) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("workflow: Callback._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil +} + +func TryRecoverFromJSON(x []byte) (*TryRecover, error) { + result := new(TryRecover) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func TryRecoverToJSON(x *TryRecover) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*TryRecover)(nil) + _ json.Marshaler = (*TryRecover)(nil) +) + +func (r *TryRecover) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONTryRecover(*r) +} +func (r *TryRecover) _marshalJSONTryRecover(x TryRecover) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldRunID []byte + fieldRunID, err = r._marshalJSONstring(x.RunID) + if err != nil { + return nil, fmt.Errorf("workflow: TryRecover._marshalJSONTryRecover: field name RunID; %w", err) + } + partial["RunID"] = fieldRunID + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: TryRecover._marshalJSONTryRecover: struct; %w", err) + } + return result, nil +} +func (r *TryRecover) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: TryRecover._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *TryRecover) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONTryRecover(data) + if err != nil { + return fmt.Errorf("workflow: TryRecover.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *TryRecover) _unmarshalJSONTryRecover(data []byte) (TryRecover, error) { + result := TryRecover{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: TryRecover._unmarshalJSONTryRecover: native struct unwrap; %w", err) + } + if fieldRunID, ok := partial["RunID"]; ok { + result.RunID, err = r._unmarshalJSONstring(fieldRunID) + if err != nil { + return result, fmt.Errorf("workflow: TryRecover._unmarshalJSONTryRecover: field RunID; %w", err) + } + } + return result, nil +} +func (r *TryRecover) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: TryRecover._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} + +func StopScheduleFromJSON(x []byte) (*StopSchedule, error) { + result := new(StopSchedule) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func StopScheduleToJSON(x *StopSchedule) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*StopSchedule)(nil) + _ json.Marshaler = (*StopSchedule)(nil) +) + +func (r *StopSchedule) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONStopSchedule(*r) +} +func (r *StopSchedule) _marshalJSONStopSchedule(x StopSchedule) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldParentRunID []byte + fieldParentRunID, err = r._marshalJSONstring(x.ParentRunID) + if err != nil { + return nil, fmt.Errorf("workflow: StopSchedule._marshalJSONStopSchedule: field name ParentRunID; %w", err) + } + partial["ParentRunID"] = fieldParentRunID + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: StopSchedule._marshalJSONStopSchedule: struct; %w", err) + } + return result, nil +} +func (r *StopSchedule) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: StopSchedule._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *StopSchedule) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONStopSchedule(data) + if err != nil { + return fmt.Errorf("workflow: StopSchedule.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *StopSchedule) _unmarshalJSONStopSchedule(data []byte) (StopSchedule, error) { + result := StopSchedule{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: StopSchedule._unmarshalJSONStopSchedule: native struct unwrap; %w", err) + } + if fieldParentRunID, ok := partial["ParentRunID"]; ok { + result.ParentRunID, err = r._unmarshalJSONstring(fieldParentRunID) + if err != nil { + return result, fmt.Errorf("workflow: StopSchedule._unmarshalJSONStopSchedule: field ParentRunID; %w", err) + } + } + return result, nil +} +func (r *StopSchedule) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: StopSchedule._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} + +func ResumeScheduleFromJSON(x []byte) (*ResumeSchedule, error) { + result := new(ResumeSchedule) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ResumeScheduleToJSON(x *ResumeSchedule) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*ResumeSchedule)(nil) + _ json.Marshaler = (*ResumeSchedule)(nil) +) + +func (r *ResumeSchedule) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONResumeSchedule(*r) +} +func (r *ResumeSchedule) _marshalJSONResumeSchedule(x ResumeSchedule) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldParentRunID []byte + fieldParentRunID, err = r._marshalJSONstring(x.ParentRunID) + if err != nil { + return nil, fmt.Errorf("workflow: ResumeSchedule._marshalJSONResumeSchedule: field name ParentRunID; %w", err) + } + partial["ParentRunID"] = fieldParentRunID + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: ResumeSchedule._marshalJSONResumeSchedule: struct; %w", err) + } + return result, nil +} +func (r *ResumeSchedule) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: ResumeSchedule._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *ResumeSchedule) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONResumeSchedule(data) + if err != nil { + return fmt.Errorf("workflow: ResumeSchedule.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *ResumeSchedule) _unmarshalJSONResumeSchedule(data []byte) (ResumeSchedule, error) { + result := ResumeSchedule{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: ResumeSchedule._unmarshalJSONResumeSchedule: native struct unwrap; %w", err) + } + if fieldParentRunID, ok := partial["ParentRunID"]; ok { + result.ParentRunID, err = r._unmarshalJSONstring(fieldParentRunID) + if err != nil { + return result, fmt.Errorf("workflow: ResumeSchedule._unmarshalJSONResumeSchedule: field ParentRunID; %w", err) + } + } + return result, nil +} +func (r *ResumeSchedule) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: ResumeSchedule._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} + +type ExprVisitor interface { + VisitEnd(v *End) any + VisitAssign(v *Assign) any + VisitApply(v *Apply) any + VisitChoose(v *Choose) any +} + +type Expr interface { + AcceptExpr(g ExprVisitor) any +} + +var ( + _ Expr = (*End)(nil) + _ Expr = (*Assign)(nil) + _ Expr = (*Apply)(nil) + _ Expr = (*Choose)(nil) +) + +func (r *End) AcceptExpr(v ExprVisitor) any { return v.VisitEnd(r) } +func (r *Assign) AcceptExpr(v ExprVisitor) any { return v.VisitAssign(r) } +func (r *Apply) AcceptExpr(v ExprVisitor) any { return v.VisitApply(r) } +func (r *Choose) AcceptExpr(v ExprVisitor) any { return v.VisitChoose(r) } + +func MatchExprR3[T0, T1, T2 any]( + x Expr, + f1 func(x *End) (T0, T1, T2), + f2 func(x *Assign) (T0, T1, T2), + f3 func(x *Apply) (T0, T1, T2), + f4 func(x *Choose) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *End: + return f1(v) + case *Assign: + return f2(v) + case *Apply: + return f3(v) + case *Choose: + return f4(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchExprR2[T0, T1 any]( + x Expr, + f1 func(x *End) (T0, T1), + f2 func(x *Assign) (T0, T1), + f3 func(x *Apply) (T0, T1), + f4 func(x *Choose) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *End: + return f1(v) + case *Assign: + return f2(v) + case *Apply: + return f3(v) + case *Choose: + return f4(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchExprR1[T0 any]( + x Expr, + f1 func(x *End) T0, + f2 func(x *Assign) T0, + f3 func(x *Apply) T0, + f4 func(x *Choose) T0, +) T0 { + switch v := x.(type) { + case *End: + return f1(v) + case *Assign: + return f2(v) + case *Apply: + return f3(v) + case *Choose: + return f4(v) + } + var result1 T0 + return result1 +} + +func MatchExprR0( + x Expr, + f1 func(x *End), + f2 func(x *Assign), + f3 func(x *Apply), + f4 func(x *Choose), +) { + switch v := x.(type) { + case *End: + f1(v) + case *Assign: + f2(v) + case *Apply: + f3(v) + case *Choose: + f4(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Expr", ExprFromJSON, ExprToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.End", EndFromJSON, EndToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Assign", AssignFromJSON, AssignToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Apply", ApplyFromJSON, ApplyToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Choose", ChooseFromJSON, ChooseToJSON) +} + +type ExprUnionJSON struct { + Type string `json:"$type,omitempty"` + End json.RawMessage `json:"workflow.End,omitempty"` + Assign json.RawMessage `json:"workflow.Assign,omitempty"` + Apply json.RawMessage `json:"workflow.Apply,omitempty"` + Choose json.RawMessage `json:"workflow.Choose,omitempty"` +} + +func ExprFromJSON(x []byte) (Expr, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data ExprUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.End": + return EndFromJSON(data.End) + case "workflow.Assign": + return AssignFromJSON(data.Assign) + case "workflow.Apply": + return ApplyFromJSON(data.Apply) + case "workflow.Choose": + return ChooseFromJSON(data.Choose) + } + + if data.End != nil { + return EndFromJSON(data.End) + } else if data.Assign != nil { + return AssignFromJSON(data.Assign) + } else if data.Apply != nil { + return ApplyFromJSON(data.Apply) + } else if data.Choose != nil { + return ChooseFromJSON(data.Choose) + } + + return nil, fmt.Errorf("workflow.Expr: unknown type %s", data.Type) +} + +func ExprToJSON(x Expr) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchExprR2( + x, + func(x *End) ([]byte, error) { + body, err := EndToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ExprUnionJSON{ + Type: "workflow.End", + End: body, + }) + }, + func(x *Assign) ([]byte, error) { + body, err := AssignToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ExprUnionJSON{ + Type: "workflow.Assign", + Assign: body, + }) + }, + func(x *Apply) ([]byte, error) { + body, err := ApplyToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ExprUnionJSON{ + Type: "workflow.Apply", + Apply: body, + }) + }, + func(x *Choose) ([]byte, error) { + body, err := ChooseToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ExprUnionJSON{ + Type: "workflow.Choose", + Choose: body, + }) + }, + ) +} + +func EndFromJSON(x []byte) (*End, error) { + result := new(End) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func EndToJSON(x *End) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*End)(nil) + _ json.Marshaler = (*End)(nil) +) + +func (r *End) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONEnd(*r) +} +func (r *End) _marshalJSONEnd(x End) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldID []byte + fieldID, err = r._marshalJSONstring(x.ID) + if err != nil { + return nil, fmt.Errorf("workflow: End._marshalJSONEnd: field name ID; %w", err) + } + partial["ID"] = fieldID + var fieldResult []byte + fieldResult, err = r._marshalJSONReshaper(x.Result) + if err != nil { + return nil, fmt.Errorf("workflow: End._marshalJSONEnd: field name Result; %w", err) + } + partial["Result"] = fieldResult + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: End._marshalJSONEnd: struct; %w", err) + } + return result, nil +} +func (r *End) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: End._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *End) _marshalJSONReshaper(x Reshaper) ([]byte, error) { + result, err := shared.JSONMarshal[Reshaper](x) + if err != nil { + return nil, fmt.Errorf("workflow: End._marshalJSONReshaper:; %w", err) + } + return result, nil +} +func (r *End) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONEnd(data) + if err != nil { + return fmt.Errorf("workflow: End.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *End) _unmarshalJSONEnd(data []byte) (End, error) { + result := End{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: End._unmarshalJSONEnd: native struct unwrap; %w", err) + } + if fieldID, ok := partial["ID"]; ok { + result.ID, err = r._unmarshalJSONstring(fieldID) + if err != nil { + return result, fmt.Errorf("workflow: End._unmarshalJSONEnd: field ID; %w", err) + } + } + if fieldResult, ok := partial["Result"]; ok { + result.Result, err = r._unmarshalJSONReshaper(fieldResult) + if err != nil { + return result, fmt.Errorf("workflow: End._unmarshalJSONEnd: field Result; %w", err) + } + } + return result, nil +} +func (r *End) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: End._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *End) _unmarshalJSONReshaper(data []byte) (Reshaper, error) { + result, err := shared.JSONUnmarshal[Reshaper](data) + if err != nil { + return result, fmt.Errorf("workflow: End._unmarshalJSONReshaper: native ref unwrap; %w", err) + } + return result, nil +} + +func AssignFromJSON(x []byte) (*Assign, error) { + result := new(Assign) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AssignToJSON(x *Assign) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Assign)(nil) + _ json.Marshaler = (*Assign)(nil) +) + +func (r *Assign) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAssign(*r) +} +func (r *Assign) _marshalJSONAssign(x Assign) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldID []byte + fieldID, err = r._marshalJSONstring(x.ID) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONAssign: field name ID; %w", err) + } + partial["ID"] = fieldID + var fieldVarOk []byte + fieldVarOk, err = r._marshalJSONstring(x.VarOk) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONAssign: field name VarOk; %w", err) + } + partial["VarOk"] = fieldVarOk + var fieldVarErr []byte + fieldVarErr, err = r._marshalJSONstring(x.VarErr) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONAssign: field name VarErr; %w", err) + } + partial["VarErr"] = fieldVarErr + var fieldVal []byte + fieldVal, err = r._marshalJSONExpr(x.Val) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONAssign: field name Val; %w", err) + } + partial["Val"] = fieldVal + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONAssign: struct; %w", err) + } + return result, nil +} +func (r *Assign) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Assign) _marshalJSONExpr(x Expr) ([]byte, error) { + result, err := shared.JSONMarshal[Expr](x) + if err != nil { + return nil, fmt.Errorf("workflow: Assign._marshalJSONExpr:; %w", err) + } + return result, nil +} +func (r *Assign) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAssign(data) + if err != nil { + return fmt.Errorf("workflow: Assign.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Assign) _unmarshalJSONAssign(data []byte) (Assign, error) { + result := Assign{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONAssign: native struct unwrap; %w", err) + } + if fieldID, ok := partial["ID"]; ok { + result.ID, err = r._unmarshalJSONstring(fieldID) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONAssign: field ID; %w", err) + } + } + if fieldVarOk, ok := partial["VarOk"]; ok { + result.VarOk, err = r._unmarshalJSONstring(fieldVarOk) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONAssign: field VarOk; %w", err) + } + } + if fieldVarErr, ok := partial["VarErr"]; ok { + result.VarErr, err = r._unmarshalJSONstring(fieldVarErr) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONAssign: field VarErr; %w", err) + } + } + if fieldVal, ok := partial["Val"]; ok { + result.Val, err = r._unmarshalJSONExpr(fieldVal) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONAssign: field Val; %w", err) + } + } + return result, nil +} +func (r *Assign) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Assign) _unmarshalJSONExpr(data []byte) (Expr, error) { + result, err := shared.JSONUnmarshal[Expr](data) + if err != nil { + return result, fmt.Errorf("workflow: Assign._unmarshalJSONExpr: native ref unwrap; %w", err) + } + return result, nil +} + +func ApplyFromJSON(x []byte) (*Apply, error) { + result := new(Apply) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ApplyToJSON(x *Apply) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Apply)(nil) + _ json.Marshaler = (*Apply)(nil) +) + +func (r *Apply) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONApply(*r) +} +func (r *Apply) _marshalJSONApply(x Apply) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldID []byte + fieldID, err = r._marshalJSONstring(x.ID) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONApply: field name ID; %w", err) + } + partial["ID"] = fieldID + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONApply: field name Name; %w", err) + } + partial["Name"] = fieldName + var fieldArgs []byte + fieldArgs, err = r._marshalJSONSliceReshaper(x.Args) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONApply: field name Args; %w", err) + } + partial["Args"] = fieldArgs + var fieldAwait []byte + fieldAwait, err = r._marshalJSONPtrApplyAwaitOptions(x.Await) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONApply: field name Await; %w", err) + } + if fieldAwait != nil { + partial["Await"] = fieldAwait + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONApply: struct; %w", err) + } + return result, nil +} +func (r *Apply) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Apply) _marshalJSONSliceReshaper(x []Reshaper) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONReshaper(v) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONSliceReshaper: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONSliceReshaper:; %w", err) + } + return result, nil +} +func (r *Apply) _marshalJSONReshaper(x Reshaper) ([]byte, error) { + result, err := shared.JSONMarshal[Reshaper](x) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONReshaper:; %w", err) + } + return result, nil +} +func (r *Apply) _marshalJSONPtrApplyAwaitOptions(x *ApplyAwaitOptions) ([]byte, error) { + if x == nil { + return nil, nil + } + return r._marshalJSONApplyAwaitOptions(*x) +} +func (r *Apply) _marshalJSONApplyAwaitOptions(x ApplyAwaitOptions) ([]byte, error) { + result, err := shared.JSONMarshal[ApplyAwaitOptions](x) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._marshalJSONApplyAwaitOptions:; %w", err) + } + return result, nil +} +func (r *Apply) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONApply(data) + if err != nil { + return fmt.Errorf("workflow: Apply.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Apply) _unmarshalJSONApply(data []byte) (Apply, error) { + result := Apply{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONApply: native struct unwrap; %w", err) + } + if fieldID, ok := partial["ID"]; ok { + result.ID, err = r._unmarshalJSONstring(fieldID) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONApply: field ID; %w", err) + } + } + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONApply: field Name; %w", err) + } + } + if fieldArgs, ok := partial["Args"]; ok { + result.Args, err = r._unmarshalJSONSliceReshaper(fieldArgs) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONApply: field Args; %w", err) + } + } + if fieldAwait, ok := partial["Await"]; ok { + result.Await, err = r._unmarshalJSONPtrApplyAwaitOptions(fieldAwait) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONApply: field Await; %w", err) + } + } + return result, nil +} +func (r *Apply) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Apply) _unmarshalJSONSliceReshaper(data []byte) ([]Reshaper, error) { + result := make([]Reshaper, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONSliceReshaper: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONReshaper(v) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONSliceReshaper: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *Apply) _unmarshalJSONReshaper(data []byte) (Reshaper, error) { + result, err := shared.JSONUnmarshal[Reshaper](data) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONReshaper: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Apply) _unmarshalJSONPtrApplyAwaitOptions(data []byte) (*ApplyAwaitOptions, error) { + if len(data) == 0 { + return nil, nil + } + if string(data[:4]) == "null" { + return nil, nil + } + result, err := r._unmarshalJSONApplyAwaitOptions(data) + if err != nil { + return nil, fmt.Errorf("workflow: Apply._unmarshalJSONPtrApplyAwaitOptions: pointer; %w", err) + } + return &result, nil +} +func (r *Apply) _unmarshalJSONApplyAwaitOptions(data []byte) (ApplyAwaitOptions, error) { + result, err := shared.JSONUnmarshal[ApplyAwaitOptions](data) + if err != nil { + return result, fmt.Errorf("workflow: Apply._unmarshalJSONApplyAwaitOptions: native ref unwrap; %w", err) + } + return result, nil +} + +func ChooseFromJSON(x []byte) (*Choose, error) { + result := new(Choose) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ChooseToJSON(x *Choose) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Choose)(nil) + _ json.Marshaler = (*Choose)(nil) +) + +func (r *Choose) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONChoose(*r) +} +func (r *Choose) _marshalJSONChoose(x Choose) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldID []byte + fieldID, err = r._marshalJSONstring(x.ID) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONChoose: field name ID; %w", err) + } + partial["ID"] = fieldID + var fieldIf []byte + fieldIf, err = r._marshalJSONPredicate(x.If) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONChoose: field name If; %w", err) + } + partial["If"] = fieldIf + var fieldThen []byte + fieldThen, err = r._marshalJSONSliceExpr(x.Then) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONChoose: field name Then; %w", err) + } + partial["Then"] = fieldThen + var fieldElse []byte + fieldElse, err = r._marshalJSONSliceExpr(x.Else) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONChoose: field name Else; %w", err) + } + partial["Else"] = fieldElse + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONChoose: struct; %w", err) + } + return result, nil +} +func (r *Choose) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Choose) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONPredicate:; %w", err) + } + return result, nil +} +func (r *Choose) _marshalJSONSliceExpr(x []Expr) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONExpr(v) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONSliceExpr: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONSliceExpr:; %w", err) + } + return result, nil +} +func (r *Choose) _marshalJSONExpr(x Expr) ([]byte, error) { + result, err := shared.JSONMarshal[Expr](x) + if err != nil { + return nil, fmt.Errorf("workflow: Choose._marshalJSONExpr:; %w", err) + } + return result, nil +} +func (r *Choose) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONChoose(data) + if err != nil { + return fmt.Errorf("workflow: Choose.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Choose) _unmarshalJSONChoose(data []byte) (Choose, error) { + result := Choose{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONChoose: native struct unwrap; %w", err) + } + if fieldID, ok := partial["ID"]; ok { + result.ID, err = r._unmarshalJSONstring(fieldID) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONChoose: field ID; %w", err) + } + } + if fieldIf, ok := partial["If"]; ok { + result.If, err = r._unmarshalJSONPredicate(fieldIf) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONChoose: field If; %w", err) + } + } + if fieldThen, ok := partial["Then"]; ok { + result.Then, err = r._unmarshalJSONSliceExpr(fieldThen) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONChoose: field Then; %w", err) + } + } + if fieldElse, ok := partial["Else"]; ok { + result.Else, err = r._unmarshalJSONSliceExpr(fieldElse) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONChoose: field Else; %w", err) + } + } + return result, nil +} +func (r *Choose) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Choose) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONPredicate: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Choose) _unmarshalJSONSliceExpr(data []byte) ([]Expr, error) { + result := make([]Expr, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONSliceExpr: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONExpr(v) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONSliceExpr: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *Choose) _unmarshalJSONExpr(data []byte) (Expr, error) { + result, err := shared.JSONUnmarshal[Expr](data) + if err != nil { + return result, fmt.Errorf("workflow: Choose._unmarshalJSONExpr: native ref unwrap; %w", err) + } + return result, nil +} + +type PredicateVisitor interface { + VisitAnd(v *And) any + VisitOr(v *Or) any + VisitNot(v *Not) any + VisitCompare(v *Compare) any +} + +type Predicate interface { + AcceptPredicate(g PredicateVisitor) any +} + +var ( + _ Predicate = (*And)(nil) + _ Predicate = (*Or)(nil) + _ Predicate = (*Not)(nil) + _ Predicate = (*Compare)(nil) +) + +func (r *And) AcceptPredicate(v PredicateVisitor) any { return v.VisitAnd(r) } +func (r *Or) AcceptPredicate(v PredicateVisitor) any { return v.VisitOr(r) } +func (r *Not) AcceptPredicate(v PredicateVisitor) any { return v.VisitNot(r) } +func (r *Compare) AcceptPredicate(v PredicateVisitor) any { return v.VisitCompare(r) } + +func MatchPredicateR3[T0, T1, T2 any]( + x Predicate, + f1 func(x *And) (T0, T1, T2), + f2 func(x *Or) (T0, T1, T2), + f3 func(x *Not) (T0, T1, T2), + f4 func(x *Compare) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *And: + return f1(v) + case *Or: + return f2(v) + case *Not: + return f3(v) + case *Compare: + return f4(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchPredicateR2[T0, T1 any]( + x Predicate, + f1 func(x *And) (T0, T1), + f2 func(x *Or) (T0, T1), + f3 func(x *Not) (T0, T1), + f4 func(x *Compare) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *And: + return f1(v) + case *Or: + return f2(v) + case *Not: + return f3(v) + case *Compare: + return f4(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchPredicateR1[T0 any]( + x Predicate, + f1 func(x *And) T0, + f2 func(x *Or) T0, + f3 func(x *Not) T0, + f4 func(x *Compare) T0, +) T0 { + switch v := x.(type) { + case *And: + return f1(v) + case *Or: + return f2(v) + case *Not: + return f3(v) + case *Compare: + return f4(v) + } + var result1 T0 + return result1 +} + +func MatchPredicateR0( + x Predicate, + f1 func(x *And), + f2 func(x *Or), + f3 func(x *Not), + f4 func(x *Compare), +) { + switch v := x.(type) { + case *And: + f1(v) + case *Or: + f2(v) + case *Not: + f3(v) + case *Compare: + f4(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Predicate", PredicateFromJSON, PredicateToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.And", AndFromJSON, AndToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Or", OrFromJSON, OrToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Not", NotFromJSON, NotToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Compare", CompareFromJSON, CompareToJSON) +} + +type PredicateUnionJSON struct { + Type string `json:"$type,omitempty"` + And json.RawMessage `json:"workflow.And,omitempty"` + Or json.RawMessage `json:"workflow.Or,omitempty"` + Not json.RawMessage `json:"workflow.Not,omitempty"` + Compare json.RawMessage `json:"workflow.Compare,omitempty"` +} + +func PredicateFromJSON(x []byte) (Predicate, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data PredicateUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.And": + return AndFromJSON(data.And) + case "workflow.Or": + return OrFromJSON(data.Or) + case "workflow.Not": + return NotFromJSON(data.Not) + case "workflow.Compare": + return CompareFromJSON(data.Compare) + } + + if data.And != nil { + return AndFromJSON(data.And) + } else if data.Or != nil { + return OrFromJSON(data.Or) + } else if data.Not != nil { + return NotFromJSON(data.Not) + } else if data.Compare != nil { + return CompareFromJSON(data.Compare) + } + + return nil, fmt.Errorf("workflow.Predicate: unknown type %s", data.Type) +} + +func PredicateToJSON(x Predicate) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchPredicateR2( + x, + func(x *And) ([]byte, error) { + body, err := AndToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(PredicateUnionJSON{ + Type: "workflow.And", + And: body, + }) + }, + func(x *Or) ([]byte, error) { + body, err := OrToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(PredicateUnionJSON{ + Type: "workflow.Or", + Or: body, + }) + }, + func(x *Not) ([]byte, error) { + body, err := NotToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(PredicateUnionJSON{ + Type: "workflow.Not", + Not: body, + }) + }, + func(x *Compare) ([]byte, error) { + body, err := CompareToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(PredicateUnionJSON{ + Type: "workflow.Compare", + Compare: body, + }) + }, + ) +} + +func AndFromJSON(x []byte) (*And, error) { + result := new(And) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AndToJSON(x *And) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*And)(nil) + _ json.Marshaler = (*And)(nil) +) + +func (r *And) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAnd(*r) +} +func (r *And) _marshalJSONAnd(x And) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldL []byte + fieldL, err = r._marshalJSONSlicePredicate(x.L) + if err != nil { + return nil, fmt.Errorf("workflow: And._marshalJSONAnd: field name L; %w", err) + } + partial["L"] = fieldL + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: And._marshalJSONAnd: struct; %w", err) + } + return result, nil +} +func (r *And) _marshalJSONSlicePredicate(x []Predicate) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONPredicate(v) + if err != nil { + return nil, fmt.Errorf("workflow: And._marshalJSONSlicePredicate: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: And._marshalJSONSlicePredicate:; %w", err) + } + return result, nil +} +func (r *And) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) + if err != nil { + return nil, fmt.Errorf("workflow: And._marshalJSONPredicate:; %w", err) + } + return result, nil +} +func (r *And) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAnd(data) + if err != nil { + return fmt.Errorf("workflow: And.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *And) _unmarshalJSONAnd(data []byte) (And, error) { + result := And{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: And._unmarshalJSONAnd: native struct unwrap; %w", err) + } + if fieldL, ok := partial["L"]; ok { + result.L, err = r._unmarshalJSONSlicePredicate(fieldL) + if err != nil { + return result, fmt.Errorf("workflow: And._unmarshalJSONAnd: field L; %w", err) + } + } + return result, nil +} +func (r *And) _unmarshalJSONSlicePredicate(data []byte) ([]Predicate, error) { + result := make([]Predicate, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: And._unmarshalJSONSlicePredicate: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONPredicate(v) + if err != nil { + return result, fmt.Errorf("workflow: And._unmarshalJSONSlicePredicate: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *And) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) + if err != nil { + return result, fmt.Errorf("workflow: And._unmarshalJSONPredicate: native ref unwrap; %w", err) + } + return result, nil +} + +func OrFromJSON(x []byte) (*Or, error) { + result := new(Or) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func OrToJSON(x *Or) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Or)(nil) + _ json.Marshaler = (*Or)(nil) +) + +func (r *Or) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONOr(*r) +} +func (r *Or) _marshalJSONOr(x Or) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldL []byte + fieldL, err = r._marshalJSONSlicePredicate(x.L) + if err != nil { + return nil, fmt.Errorf("workflow: Or._marshalJSONOr: field name L; %w", err) + } + partial["L"] = fieldL + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Or._marshalJSONOr: struct; %w", err) + } + return result, nil +} +func (r *Or) _marshalJSONSlicePredicate(x []Predicate) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONPredicate(v) + if err != nil { + return nil, fmt.Errorf("workflow: Or._marshalJSONSlicePredicate: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Or._marshalJSONSlicePredicate:; %w", err) + } + return result, nil +} +func (r *Or) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) + if err != nil { + return nil, fmt.Errorf("workflow: Or._marshalJSONPredicate:; %w", err) + } + return result, nil +} +func (r *Or) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONOr(data) + if err != nil { + return fmt.Errorf("workflow: Or.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Or) _unmarshalJSONOr(data []byte) (Or, error) { + result := Or{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Or._unmarshalJSONOr: native struct unwrap; %w", err) + } + if fieldL, ok := partial["L"]; ok { + result.L, err = r._unmarshalJSONSlicePredicate(fieldL) + if err != nil { + return result, fmt.Errorf("workflow: Or._unmarshalJSONOr: field L; %w", err) + } + } + return result, nil +} +func (r *Or) _unmarshalJSONSlicePredicate(data []byte) ([]Predicate, error) { + result := make([]Predicate, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Or._unmarshalJSONSlicePredicate: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONPredicate(v) + if err != nil { + return result, fmt.Errorf("workflow: Or._unmarshalJSONSlicePredicate: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *Or) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) + if err != nil { + return result, fmt.Errorf("workflow: Or._unmarshalJSONPredicate: native ref unwrap; %w", err) + } + return result, nil +} + +func NotFromJSON(x []byte) (*Not, error) { + result := new(Not) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func NotToJSON(x *Not) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Not)(nil) + _ json.Marshaler = (*Not)(nil) +) + +func (r *Not) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONNot(*r) +} +func (r *Not) _marshalJSONNot(x Not) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldP []byte + fieldP, err = r._marshalJSONPredicate(x.P) + if err != nil { + return nil, fmt.Errorf("workflow: Not._marshalJSONNot: field name P; %w", err) + } + partial["P"] = fieldP + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Not._marshalJSONNot: struct; %w", err) + } + return result, nil +} +func (r *Not) _marshalJSONPredicate(x Predicate) ([]byte, error) { + result, err := shared.JSONMarshal[Predicate](x) + if err != nil { + return nil, fmt.Errorf("workflow: Not._marshalJSONPredicate:; %w", err) + } + return result, nil +} +func (r *Not) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONNot(data) + if err != nil { + return fmt.Errorf("workflow: Not.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Not) _unmarshalJSONNot(data []byte) (Not, error) { + result := Not{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Not._unmarshalJSONNot: native struct unwrap; %w", err) + } + if fieldP, ok := partial["P"]; ok { + result.P, err = r._unmarshalJSONPredicate(fieldP) + if err != nil { + return result, fmt.Errorf("workflow: Not._unmarshalJSONNot: field P; %w", err) + } + } + return result, nil +} +func (r *Not) _unmarshalJSONPredicate(data []byte) (Predicate, error) { + result, err := shared.JSONUnmarshal[Predicate](data) + if err != nil { + return result, fmt.Errorf("workflow: Not._unmarshalJSONPredicate: native ref unwrap; %w", err) + } + return result, nil +} + +func CompareFromJSON(x []byte) (*Compare, error) { + result := new(Compare) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func CompareToJSON(x *Compare) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Compare)(nil) + _ json.Marshaler = (*Compare)(nil) +) + +func (r *Compare) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONCompare(*r) +} +func (r *Compare) _marshalJSONCompare(x Compare) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldOperation []byte + fieldOperation, err = r._marshalJSONstring(x.Operation) + if err != nil { + return nil, fmt.Errorf("workflow: Compare._marshalJSONCompare: field name Operation; %w", err) + } + partial["Operation"] = fieldOperation + var fieldLeft []byte + fieldLeft, err = r._marshalJSONReshaper(x.Left) + if err != nil { + return nil, fmt.Errorf("workflow: Compare._marshalJSONCompare: field name Left; %w", err) + } + partial["Left"] = fieldLeft + var fieldRight []byte + fieldRight, err = r._marshalJSONReshaper(x.Right) + if err != nil { + return nil, fmt.Errorf("workflow: Compare._marshalJSONCompare: field name Right; %w", err) + } + partial["Right"] = fieldRight + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Compare._marshalJSONCompare: struct; %w", err) + } + return result, nil +} +func (r *Compare) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Compare._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Compare) _marshalJSONReshaper(x Reshaper) ([]byte, error) { + result, err := shared.JSONMarshal[Reshaper](x) + if err != nil { + return nil, fmt.Errorf("workflow: Compare._marshalJSONReshaper:; %w", err) + } + return result, nil +} +func (r *Compare) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONCompare(data) + if err != nil { + return fmt.Errorf("workflow: Compare.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Compare) _unmarshalJSONCompare(data []byte) (Compare, error) { + result := Compare{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Compare._unmarshalJSONCompare: native struct unwrap; %w", err) + } + if fieldOperation, ok := partial["Operation"]; ok { + result.Operation, err = r._unmarshalJSONstring(fieldOperation) + if err != nil { + return result, fmt.Errorf("workflow: Compare._unmarshalJSONCompare: field Operation; %w", err) + } + } + if fieldLeft, ok := partial["Left"]; ok { + result.Left, err = r._unmarshalJSONReshaper(fieldLeft) + if err != nil { + return result, fmt.Errorf("workflow: Compare._unmarshalJSONCompare: field Left; %w", err) + } + } + if fieldRight, ok := partial["Right"]; ok { + result.Right, err = r._unmarshalJSONReshaper(fieldRight) + if err != nil { + return result, fmt.Errorf("workflow: Compare._unmarshalJSONCompare: field Right; %w", err) + } + } + return result, nil +} +func (r *Compare) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Compare._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Compare) _unmarshalJSONReshaper(data []byte) (Reshaper, error) { + result, err := shared.JSONUnmarshal[Reshaper](data) + if err != nil { + return result, fmt.Errorf("workflow: Compare._unmarshalJSONReshaper: native ref unwrap; %w", err) + } + return result, nil +} + +type ReshaperVisitor interface { + VisitGetValue(v *GetValue) any + VisitSetValue(v *SetValue) any +} + +type Reshaper interface { + AcceptReshaper(g ReshaperVisitor) any +} + +var ( + _ Reshaper = (*GetValue)(nil) + _ Reshaper = (*SetValue)(nil) +) + +func (r *GetValue) AcceptReshaper(v ReshaperVisitor) any { return v.VisitGetValue(r) } +func (r *SetValue) AcceptReshaper(v ReshaperVisitor) any { return v.VisitSetValue(r) } + +func MatchReshaperR3[T0, T1, T2 any]( + x Reshaper, + f1 func(x *GetValue) (T0, T1, T2), + f2 func(x *SetValue) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *GetValue: + return f1(v) + case *SetValue: + return f2(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchReshaperR2[T0, T1 any]( + x Reshaper, + f1 func(x *GetValue) (T0, T1), + f2 func(x *SetValue) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *GetValue: + return f1(v) + case *SetValue: + return f2(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchReshaperR1[T0 any]( + x Reshaper, + f1 func(x *GetValue) T0, + f2 func(x *SetValue) T0, +) T0 { + switch v := x.(type) { + case *GetValue: + return f1(v) + case *SetValue: + return f2(v) + } + var result1 T0 + return result1 +} + +func MatchReshaperR0( + x Reshaper, + f1 func(x *GetValue), + f2 func(x *SetValue), +) { + switch v := x.(type) { + case *GetValue: + f1(v) + case *SetValue: + f2(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Reshaper", ReshaperFromJSON, ReshaperToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.GetValue", GetValueFromJSON, GetValueToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.SetValue", SetValueFromJSON, SetValueToJSON) +} + +type ReshaperUnionJSON struct { + Type string `json:"$type,omitempty"` + GetValue json.RawMessage `json:"workflow.GetValue,omitempty"` + SetValue json.RawMessage `json:"workflow.SetValue,omitempty"` +} + +func ReshaperFromJSON(x []byte) (Reshaper, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data ReshaperUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.GetValue": + return GetValueFromJSON(data.GetValue) + case "workflow.SetValue": + return SetValueFromJSON(data.SetValue) + } + + if data.GetValue != nil { + return GetValueFromJSON(data.GetValue) + } else if data.SetValue != nil { + return SetValueFromJSON(data.SetValue) + } + + return nil, fmt.Errorf("workflow.Reshaper: unknown type %s", data.Type) +} + +func ReshaperToJSON(x Reshaper) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchReshaperR2( + x, + func(x *GetValue) ([]byte, error) { + body, err := GetValueToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ReshaperUnionJSON{ + Type: "workflow.GetValue", + GetValue: body, + }) + }, + func(x *SetValue) ([]byte, error) { + body, err := SetValueToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(ReshaperUnionJSON{ + Type: "workflow.SetValue", + SetValue: body, + }) + }, + ) +} + +func GetValueFromJSON(x []byte) (*GetValue, error) { + result := new(GetValue) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func GetValueToJSON(x *GetValue) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*GetValue)(nil) + _ json.Marshaler = (*GetValue)(nil) +) + +func (r *GetValue) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONGetValue(*r) +} +func (r *GetValue) _marshalJSONGetValue(x GetValue) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldPath []byte + fieldPath, err = r._marshalJSONstring(x.Path) + if err != nil { + return nil, fmt.Errorf("workflow: GetValue._marshalJSONGetValue: field name Path; %w", err) + } + partial["Path"] = fieldPath + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: GetValue._marshalJSONGetValue: struct; %w", err) + } + return result, nil +} +func (r *GetValue) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: GetValue._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *GetValue) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONGetValue(data) + if err != nil { + return fmt.Errorf("workflow: GetValue.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *GetValue) _unmarshalJSONGetValue(data []byte) (GetValue, error) { + result := GetValue{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: GetValue._unmarshalJSONGetValue: native struct unwrap; %w", err) + } + if fieldPath, ok := partial["Path"]; ok { + result.Path, err = r._unmarshalJSONstring(fieldPath) + if err != nil { + return result, fmt.Errorf("workflow: GetValue._unmarshalJSONGetValue: field Path; %w", err) + } + } + return result, nil +} +func (r *GetValue) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: GetValue._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} + +func SetValueFromJSON(x []byte) (*SetValue, error) { + result := new(SetValue) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func SetValueToJSON(x *SetValue) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*SetValue)(nil) + _ json.Marshaler = (*SetValue)(nil) +) + +func (r *SetValue) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONSetValue(*r) +} +func (r *SetValue) _marshalJSONSetValue(x SetValue) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldValue []byte + fieldValue, err = r._marshalJSONschema_Schema(x.Value) + if err != nil { + return nil, fmt.Errorf("workflow: SetValue._marshalJSONSetValue: field name Value; %w", err) + } + partial["Value"] = fieldValue + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: SetValue._marshalJSONSetValue: struct; %w", err) + } + return result, nil +} +func (r *SetValue) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("workflow: SetValue._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *SetValue) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONSetValue(data) + if err != nil { + return fmt.Errorf("workflow: SetValue.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *SetValue) _unmarshalJSONSetValue(data []byte) (SetValue, error) { + result := SetValue{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: SetValue._unmarshalJSONSetValue: native struct unwrap; %w", err) + } + if fieldValue, ok := partial["Value"]; ok { + result.Value, err = r._unmarshalJSONschema_Schema(fieldValue) + if err != nil { + return result, fmt.Errorf("workflow: SetValue._unmarshalJSONSetValue: field Value; %w", err) + } + } + return result, nil +} +func (r *SetValue) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("workflow: SetValue._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil +} + +type RunOptionVisitor interface { + VisitScheduleRun(v *ScheduleRun) any + VisitDelayRun(v *DelayRun) any +} + +type RunOption interface { + AcceptRunOption(g RunOptionVisitor) any +} + +var ( + _ RunOption = (*ScheduleRun)(nil) + _ RunOption = (*DelayRun)(nil) +) + +func (r *ScheduleRun) AcceptRunOption(v RunOptionVisitor) any { return v.VisitScheduleRun(r) } +func (r *DelayRun) AcceptRunOption(v RunOptionVisitor) any { return v.VisitDelayRun(r) } + +func MatchRunOptionR3[T0, T1, T2 any]( + x RunOption, + f1 func(x *ScheduleRun) (T0, T1, T2), + f2 func(x *DelayRun) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *ScheduleRun: + return f1(v) + case *DelayRun: + return f2(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchRunOptionR2[T0, T1 any]( + x RunOption, + f1 func(x *ScheduleRun) (T0, T1), + f2 func(x *DelayRun) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *ScheduleRun: + return f1(v) + case *DelayRun: + return f2(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchRunOptionR1[T0 any]( + x RunOption, + f1 func(x *ScheduleRun) T0, + f2 func(x *DelayRun) T0, +) T0 { + switch v := x.(type) { + case *ScheduleRun: + return f1(v) + case *DelayRun: + return f2(v) + } + var result1 T0 + return result1 +} + +func MatchRunOptionR0( + x RunOption, + f1 func(x *ScheduleRun), + f2 func(x *DelayRun), +) { + switch v := x.(type) { + case *ScheduleRun: + f1(v) + case *DelayRun: + f2(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.RunOption", RunOptionFromJSON, RunOptionToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.ScheduleRun", ScheduleRunFromJSON, ScheduleRunToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.DelayRun", DelayRunFromJSON, DelayRunToJSON) +} + +type RunOptionUnionJSON struct { + Type string `json:"$type,omitempty"` + ScheduleRun json.RawMessage `json:"workflow.ScheduleRun,omitempty"` + DelayRun json.RawMessage `json:"workflow.DelayRun,omitempty"` +} + +func RunOptionFromJSON(x []byte) (RunOption, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data RunOptionUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.ScheduleRun": + return ScheduleRunFromJSON(data.ScheduleRun) + case "workflow.DelayRun": + return DelayRunFromJSON(data.DelayRun) + } + + if data.ScheduleRun != nil { + return ScheduleRunFromJSON(data.ScheduleRun) + } else if data.DelayRun != nil { + return DelayRunFromJSON(data.DelayRun) + } + + return nil, fmt.Errorf("workflow.RunOption: unknown type %s", data.Type) +} + +func RunOptionToJSON(x RunOption) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchRunOptionR2( + x, + func(x *ScheduleRun) ([]byte, error) { + body, err := ScheduleRunToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(RunOptionUnionJSON{ + Type: "workflow.ScheduleRun", + ScheduleRun: body, + }) + }, + func(x *DelayRun) ([]byte, error) { + body, err := DelayRunToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(RunOptionUnionJSON{ + Type: "workflow.DelayRun", + DelayRun: body, + }) + }, + ) +} + +func ScheduleRunFromJSON(x []byte) (*ScheduleRun, error) { + result := new(ScheduleRun) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ScheduleRunToJSON(x *ScheduleRun) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*ScheduleRun)(nil) + _ json.Marshaler = (*ScheduleRun)(nil) +) + +func (r *ScheduleRun) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONScheduleRun(*r) +} +func (r *ScheduleRun) _marshalJSONScheduleRun(x ScheduleRun) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldInterval []byte + fieldInterval, err = r._marshalJSONstring(x.Interval) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleRun._marshalJSONScheduleRun: field name Interval; %w", err) + } + partial["Interval"] = fieldInterval + var fieldParentRunID []byte + fieldParentRunID, err = r._marshalJSONstring(x.ParentRunID) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleRun._marshalJSONScheduleRun: field name ParentRunID; %w", err) + } + partial["ParentRunID"] = fieldParentRunID + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleRun._marshalJSONScheduleRun: struct; %w", err) + } + return result, nil +} +func (r *ScheduleRun) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleRun._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *ScheduleRun) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONScheduleRun(data) + if err != nil { + return fmt.Errorf("workflow: ScheduleRun.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *ScheduleRun) _unmarshalJSONScheduleRun(data []byte) (ScheduleRun, error) { + result := ScheduleRun{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleRun._unmarshalJSONScheduleRun: native struct unwrap; %w", err) + } + if fieldInterval, ok := partial["Interval"]; ok { + result.Interval, err = r._unmarshalJSONstring(fieldInterval) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleRun._unmarshalJSONScheduleRun: field Interval; %w", err) + } + } + if fieldParentRunID, ok := partial["ParentRunID"]; ok { + result.ParentRunID, err = r._unmarshalJSONstring(fieldParentRunID) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleRun._unmarshalJSONScheduleRun: field ParentRunID; %w", err) + } + } + return result, nil +} +func (r *ScheduleRun) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleRun._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} + +func DelayRunFromJSON(x []byte) (*DelayRun, error) { + result := new(DelayRun) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DelayRunToJSON(x *DelayRun) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*DelayRun)(nil) + _ json.Marshaler = (*DelayRun)(nil) +) + +func (r *DelayRun) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDelayRun(*r) +} +func (r *DelayRun) _marshalJSONDelayRun(x DelayRun) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldDelayBySeconds []byte + fieldDelayBySeconds, err = r._marshalJSONint64(x.DelayBySeconds) + if err != nil { + return nil, fmt.Errorf("workflow: DelayRun._marshalJSONDelayRun: field name DelayBySeconds; %w", err) + } + partial["DelayBySeconds"] = fieldDelayBySeconds + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: DelayRun._marshalJSONDelayRun: struct; %w", err) + } + return result, nil +} +func (r *DelayRun) _marshalJSONint64(x int64) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: DelayRun._marshalJSONint64:; %w", err) + } + return result, nil +} +func (r *DelayRun) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDelayRun(data) + if err != nil { + return fmt.Errorf("workflow: DelayRun.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *DelayRun) _unmarshalJSONDelayRun(data []byte) (DelayRun, error) { + result := DelayRun{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: DelayRun._unmarshalJSONDelayRun: native struct unwrap; %w", err) + } + if fieldDelayBySeconds, ok := partial["DelayBySeconds"]; ok { + result.DelayBySeconds, err = r._unmarshalJSONint64(fieldDelayBySeconds) + if err != nil { + return result, fmt.Errorf("workflow: DelayRun._unmarshalJSONDelayRun: field DelayBySeconds; %w", err) + } + } + return result, nil +} +func (r *DelayRun) _unmarshalJSONint64(data []byte) (int64, error) { + var result int64 + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: DelayRun._unmarshalJSONint64: native primitive unwrap; %w", err) + } + return result, nil +} + +type StateVisitor interface { + VisitNextOperation(v *NextOperation) any + VisitDone(v *Done) any + VisitError(v *Error) any + VisitAwait(v *Await) any + VisitScheduled(v *Scheduled) any + VisitScheduleStopped(v *ScheduleStopped) any +} + +type State interface { + AcceptState(g StateVisitor) any +} + +var ( + _ State = (*NextOperation)(nil) + _ State = (*Done)(nil) + _ State = (*Error)(nil) + _ State = (*Await)(nil) + _ State = (*Scheduled)(nil) + _ State = (*ScheduleStopped)(nil) +) + +func (r *NextOperation) AcceptState(v StateVisitor) any { return v.VisitNextOperation(r) } +func (r *Done) AcceptState(v StateVisitor) any { return v.VisitDone(r) } +func (r *Error) AcceptState(v StateVisitor) any { return v.VisitError(r) } +func (r *Await) AcceptState(v StateVisitor) any { return v.VisitAwait(r) } +func (r *Scheduled) AcceptState(v StateVisitor) any { return v.VisitScheduled(r) } +func (r *ScheduleStopped) AcceptState(v StateVisitor) any { return v.VisitScheduleStopped(r) } + +func MatchStateR3[T0, T1, T2 any]( + x State, + f1 func(x *NextOperation) (T0, T1, T2), + f2 func(x *Done) (T0, T1, T2), + f3 func(x *Error) (T0, T1, T2), + f4 func(x *Await) (T0, T1, T2), + f5 func(x *Scheduled) (T0, T1, T2), + f6 func(x *ScheduleStopped) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *NextOperation: + return f1(v) + case *Done: + return f2(v) + case *Error: + return f3(v) + case *Await: + return f4(v) + case *Scheduled: + return f5(v) + case *ScheduleStopped: + return f6(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchStateR2[T0, T1 any]( + x State, + f1 func(x *NextOperation) (T0, T1), + f2 func(x *Done) (T0, T1), + f3 func(x *Error) (T0, T1), + f4 func(x *Await) (T0, T1), + f5 func(x *Scheduled) (T0, T1), + f6 func(x *ScheduleStopped) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *NextOperation: + return f1(v) + case *Done: + return f2(v) + case *Error: + return f3(v) + case *Await: + return f4(v) + case *Scheduled: + return f5(v) + case *ScheduleStopped: + return f6(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchStateR1[T0 any]( + x State, + f1 func(x *NextOperation) T0, + f2 func(x *Done) T0, + f3 func(x *Error) T0, + f4 func(x *Await) T0, + f5 func(x *Scheduled) T0, + f6 func(x *ScheduleStopped) T0, +) T0 { + switch v := x.(type) { + case *NextOperation: + return f1(v) + case *Done: + return f2(v) + case *Error: + return f3(v) + case *Await: + return f4(v) + case *Scheduled: + return f5(v) + case *ScheduleStopped: + return f6(v) + } + var result1 T0 + return result1 +} + +func MatchStateR0( + x State, + f1 func(x *NextOperation), + f2 func(x *Done), + f3 func(x *Error), + f4 func(x *Await), + f5 func(x *Scheduled), + f6 func(x *ScheduleStopped), +) { + switch v := x.(type) { + case *NextOperation: + f1(v) + case *Done: + f2(v) + case *Error: + f3(v) + case *Await: + f4(v) + case *Scheduled: + f5(v) + case *ScheduleStopped: + f6(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.State", StateFromJSON, StateToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.NextOperation", NextOperationFromJSON, NextOperationToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Done", DoneFromJSON, DoneToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Error", ErrorFromJSON, ErrorToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Await", AwaitFromJSON, AwaitToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Scheduled", ScheduledFromJSON, ScheduledToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.ScheduleStopped", ScheduleStoppedFromJSON, ScheduleStoppedToJSON) +} + +type StateUnionJSON struct { + Type string `json:"$type,omitempty"` + NextOperation json.RawMessage `json:"workflow.NextOperation,omitempty"` + Done json.RawMessage `json:"workflow.Done,omitempty"` + Error json.RawMessage `json:"workflow.Error,omitempty"` + Await json.RawMessage `json:"workflow.Await,omitempty"` + Scheduled json.RawMessage `json:"workflow.Scheduled,omitempty"` + ScheduleStopped json.RawMessage `json:"workflow.ScheduleStopped,omitempty"` +} + +func StateFromJSON(x []byte) (State, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data StateUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.NextOperation": + return NextOperationFromJSON(data.NextOperation) + case "workflow.Done": + return DoneFromJSON(data.Done) + case "workflow.Error": + return ErrorFromJSON(data.Error) + case "workflow.Await": + return AwaitFromJSON(data.Await) + case "workflow.Scheduled": + return ScheduledFromJSON(data.Scheduled) + case "workflow.ScheduleStopped": + return ScheduleStoppedFromJSON(data.ScheduleStopped) + } + + if data.NextOperation != nil { + return NextOperationFromJSON(data.NextOperation) + } else if data.Done != nil { + return DoneFromJSON(data.Done) + } else if data.Error != nil { + return ErrorFromJSON(data.Error) + } else if data.Await != nil { + return AwaitFromJSON(data.Await) + } else if data.Scheduled != nil { + return ScheduledFromJSON(data.Scheduled) + } else if data.ScheduleStopped != nil { + return ScheduleStoppedFromJSON(data.ScheduleStopped) + } + + return nil, fmt.Errorf("workflow.State: unknown type %s", data.Type) +} + +func StateToJSON(x State) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchStateR2( + x, + func(x *NextOperation) ([]byte, error) { + body, err := NextOperationToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(StateUnionJSON{ + Type: "workflow.NextOperation", + NextOperation: body, + }) + }, + func(x *Done) ([]byte, error) { + body, err := DoneToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(StateUnionJSON{ + Type: "workflow.Done", + Done: body, + }) + }, + func(x *Error) ([]byte, error) { + body, err := ErrorToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(StateUnionJSON{ + Type: "workflow.Error", + Error: body, + }) + }, + func(x *Await) ([]byte, error) { + body, err := AwaitToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(StateUnionJSON{ + Type: "workflow.Await", + Await: body, + }) + }, + func(x *Scheduled) ([]byte, error) { + body, err := ScheduledToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(StateUnionJSON{ + Type: "workflow.Scheduled", + Scheduled: body, + }) + }, + func(x *ScheduleStopped) ([]byte, error) { + body, err := ScheduleStoppedToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(StateUnionJSON{ + Type: "workflow.ScheduleStopped", + ScheduleStopped: body, + }) + }, + ) +} + +func NextOperationFromJSON(x []byte) (*NextOperation, error) { + result := new(NextOperation) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func NextOperationToJSON(x *NextOperation) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*NextOperation)(nil) + _ json.Marshaler = (*NextOperation)(nil) +) + +func (r *NextOperation) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONNextOperation(*r) +} +func (r *NextOperation) _marshalJSONNextOperation(x NextOperation) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldResult []byte + fieldResult, err = r._marshalJSONschema_Schema(x.Result) + if err != nil { + return nil, fmt.Errorf("workflow: NextOperation._marshalJSONNextOperation: field name Result; %w", err) + } + partial["Result"] = fieldResult + var fieldBaseState []byte + fieldBaseState, err = r._marshalJSONBaseState(x.BaseState) + if err != nil { + return nil, fmt.Errorf("workflow: NextOperation._marshalJSONNextOperation: field name BaseState; %w", err) + } + partial["BaseState"] = fieldBaseState + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: NextOperation._marshalJSONNextOperation: struct; %w", err) + } + return result, nil +} +func (r *NextOperation) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("workflow: NextOperation._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *NextOperation) _marshalJSONBaseState(x BaseState) ([]byte, error) { + result, err := shared.JSONMarshal[BaseState](x) + if err != nil { + return nil, fmt.Errorf("workflow: NextOperation._marshalJSONBaseState:; %w", err) + } + return result, nil +} +func (r *NextOperation) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONNextOperation(data) + if err != nil { + return fmt.Errorf("workflow: NextOperation.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *NextOperation) _unmarshalJSONNextOperation(data []byte) (NextOperation, error) { + result := NextOperation{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: NextOperation._unmarshalJSONNextOperation: native struct unwrap; %w", err) + } + if fieldResult, ok := partial["Result"]; ok { + result.Result, err = r._unmarshalJSONschema_Schema(fieldResult) + if err != nil { + return result, fmt.Errorf("workflow: NextOperation._unmarshalJSONNextOperation: field Result; %w", err) + } + } + if fieldBaseState, ok := partial["BaseState"]; ok { + result.BaseState, err = r._unmarshalJSONBaseState(fieldBaseState) + if err != nil { + return result, fmt.Errorf("workflow: NextOperation._unmarshalJSONNextOperation: field BaseState; %w", err) + } + } + return result, nil +} +func (r *NextOperation) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("workflow: NextOperation._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil +} +func (r *NextOperation) _unmarshalJSONBaseState(data []byte) (BaseState, error) { + result, err := shared.JSONUnmarshal[BaseState](data) + if err != nil { + return result, fmt.Errorf("workflow: NextOperation._unmarshalJSONBaseState: native ref unwrap; %w", err) + } + return result, nil +} + +func DoneFromJSON(x []byte) (*Done, error) { + result := new(Done) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func DoneToJSON(x *Done) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Done)(nil) + _ json.Marshaler = (*Done)(nil) +) + +func (r *Done) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONDone(*r) +} +func (r *Done) _marshalJSONDone(x Done) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldResult []byte + fieldResult, err = r._marshalJSONschema_Schema(x.Result) + if err != nil { + return nil, fmt.Errorf("workflow: Done._marshalJSONDone: field name Result; %w", err) + } + partial["Result"] = fieldResult + var fieldBaseState []byte + fieldBaseState, err = r._marshalJSONBaseState(x.BaseState) + if err != nil { + return nil, fmt.Errorf("workflow: Done._marshalJSONDone: field name BaseState; %w", err) + } + partial["BaseState"] = fieldBaseState + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Done._marshalJSONDone: struct; %w", err) + } + return result, nil +} +func (r *Done) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("workflow: Done._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *Done) _marshalJSONBaseState(x BaseState) ([]byte, error) { + result, err := shared.JSONMarshal[BaseState](x) + if err != nil { + return nil, fmt.Errorf("workflow: Done._marshalJSONBaseState:; %w", err) + } + return result, nil +} +func (r *Done) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONDone(data) + if err != nil { + return fmt.Errorf("workflow: Done.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Done) _unmarshalJSONDone(data []byte) (Done, error) { + result := Done{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Done._unmarshalJSONDone: native struct unwrap; %w", err) + } + if fieldResult, ok := partial["Result"]; ok { + result.Result, err = r._unmarshalJSONschema_Schema(fieldResult) + if err != nil { + return result, fmt.Errorf("workflow: Done._unmarshalJSONDone: field Result; %w", err) + } + } + if fieldBaseState, ok := partial["BaseState"]; ok { + result.BaseState, err = r._unmarshalJSONBaseState(fieldBaseState) + if err != nil { + return result, fmt.Errorf("workflow: Done._unmarshalJSONDone: field BaseState; %w", err) + } + } + return result, nil +} +func (r *Done) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("workflow: Done._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil +} +func (r *Done) _unmarshalJSONBaseState(data []byte) (BaseState, error) { + result, err := shared.JSONUnmarshal[BaseState](data) + if err != nil { + return result, fmt.Errorf("workflow: Done._unmarshalJSONBaseState: native ref unwrap; %w", err) + } + return result, nil +} + +func ErrorFromJSON(x []byte) (*Error, error) { + result := new(Error) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ErrorToJSON(x *Error) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Error)(nil) + _ json.Marshaler = (*Error)(nil) +) + +func (r *Error) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONError(*r) +} +func (r *Error) _marshalJSONError(x Error) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCode []byte + fieldCode, err = r._marshalJSONstring(x.Code) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONError: field name Code; %w", err) + } + partial["Code"] = fieldCode + var fieldReason []byte + fieldReason, err = r._marshalJSONstring(x.Reason) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONError: field name Reason; %w", err) + } + partial["Reason"] = fieldReason + var fieldRetried []byte + fieldRetried, err = r._marshalJSONint64(x.Retried) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONError: field name Retried; %w", err) + } + partial["Retried"] = fieldRetried + var fieldBaseState []byte + fieldBaseState, err = r._marshalJSONBaseState(x.BaseState) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONError: field name BaseState; %w", err) + } + partial["BaseState"] = fieldBaseState + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONError: struct; %w", err) + } + return result, nil +} +func (r *Error) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Error) _marshalJSONint64(x int64) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONint64:; %w", err) + } + return result, nil +} +func (r *Error) _marshalJSONBaseState(x BaseState) ([]byte, error) { + result, err := shared.JSONMarshal[BaseState](x) + if err != nil { + return nil, fmt.Errorf("workflow: Error._marshalJSONBaseState:; %w", err) + } + return result, nil +} +func (r *Error) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONError(data) + if err != nil { + return fmt.Errorf("workflow: Error.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Error) _unmarshalJSONError(data []byte) (Error, error) { + result := Error{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONError: native struct unwrap; %w", err) + } + if fieldCode, ok := partial["Code"]; ok { + result.Code, err = r._unmarshalJSONstring(fieldCode) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONError: field Code; %w", err) + } + } + if fieldReason, ok := partial["Reason"]; ok { + result.Reason, err = r._unmarshalJSONstring(fieldReason) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONError: field Reason; %w", err) + } + } + if fieldRetried, ok := partial["Retried"]; ok { + result.Retried, err = r._unmarshalJSONint64(fieldRetried) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONError: field Retried; %w", err) + } + } + if fieldBaseState, ok := partial["BaseState"]; ok { + result.BaseState, err = r._unmarshalJSONBaseState(fieldBaseState) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONError: field BaseState; %w", err) + } + } + return result, nil +} +func (r *Error) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Error) _unmarshalJSONint64(data []byte) (int64, error) { + var result int64 + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONint64: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Error) _unmarshalJSONBaseState(data []byte) (BaseState, error) { + result, err := shared.JSONUnmarshal[BaseState](data) + if err != nil { + return result, fmt.Errorf("workflow: Error._unmarshalJSONBaseState: native ref unwrap; %w", err) + } + return result, nil +} + +func AwaitFromJSON(x []byte) (*Await, error) { + result := new(Await) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func AwaitToJSON(x *Await) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Await)(nil) + _ json.Marshaler = (*Await)(nil) +) + +func (r *Await) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONAwait(*r) +} +func (r *Await) _marshalJSONAwait(x Await) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldCallbackID []byte + fieldCallbackID, err = r._marshalJSONstring(x.CallbackID) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONAwait: field name CallbackID; %w", err) + } + partial["CallbackID"] = fieldCallbackID + var fieldTimeout []byte + fieldTimeout, err = r._marshalJSONint64(x.Timeout) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONAwait: field name Timeout; %w", err) + } + partial["Timeout"] = fieldTimeout + var fieldBaseState []byte + fieldBaseState, err = r._marshalJSONBaseState(x.BaseState) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONAwait: field name BaseState; %w", err) + } + partial["BaseState"] = fieldBaseState + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONAwait: struct; %w", err) + } + return result, nil +} +func (r *Await) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Await) _marshalJSONint64(x int64) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONint64:; %w", err) + } + return result, nil +} +func (r *Await) _marshalJSONBaseState(x BaseState) ([]byte, error) { + result, err := shared.JSONMarshal[BaseState](x) + if err != nil { + return nil, fmt.Errorf("workflow: Await._marshalJSONBaseState:; %w", err) + } + return result, nil +} +func (r *Await) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONAwait(data) + if err != nil { + return fmt.Errorf("workflow: Await.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Await) _unmarshalJSONAwait(data []byte) (Await, error) { + result := Await{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONAwait: native struct unwrap; %w", err) + } + if fieldCallbackID, ok := partial["CallbackID"]; ok { + result.CallbackID, err = r._unmarshalJSONstring(fieldCallbackID) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONAwait: field CallbackID; %w", err) + } + } + if fieldTimeout, ok := partial["Timeout"]; ok { + result.Timeout, err = r._unmarshalJSONint64(fieldTimeout) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONAwait: field Timeout; %w", err) + } + } + if fieldBaseState, ok := partial["BaseState"]; ok { + result.BaseState, err = r._unmarshalJSONBaseState(fieldBaseState) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONAwait: field BaseState; %w", err) + } + } + return result, nil +} +func (r *Await) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Await) _unmarshalJSONint64(data []byte) (int64, error) { + var result int64 + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONint64: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Await) _unmarshalJSONBaseState(data []byte) (BaseState, error) { + result, err := shared.JSONUnmarshal[BaseState](data) + if err != nil { + return result, fmt.Errorf("workflow: Await._unmarshalJSONBaseState: native ref unwrap; %w", err) + } + return result, nil +} + +func ScheduledFromJSON(x []byte) (*Scheduled, error) { + result := new(Scheduled) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ScheduledToJSON(x *Scheduled) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Scheduled)(nil) + _ json.Marshaler = (*Scheduled)(nil) +) + +func (r *Scheduled) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONScheduled(*r) +} +func (r *Scheduled) _marshalJSONScheduled(x Scheduled) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldExpectedRunTimestamp []byte + fieldExpectedRunTimestamp, err = r._marshalJSONint64(x.ExpectedRunTimestamp) + if err != nil { + return nil, fmt.Errorf("workflow: Scheduled._marshalJSONScheduled: field name ExpectedRunTimestamp; %w", err) + } + partial["ExpectedRunTimestamp"] = fieldExpectedRunTimestamp + var fieldBaseState []byte + fieldBaseState, err = r._marshalJSONBaseState(x.BaseState) + if err != nil { + return nil, fmt.Errorf("workflow: Scheduled._marshalJSONScheduled: field name BaseState; %w", err) + } + partial["BaseState"] = fieldBaseState + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Scheduled._marshalJSONScheduled: struct; %w", err) + } + return result, nil +} +func (r *Scheduled) _marshalJSONint64(x int64) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Scheduled._marshalJSONint64:; %w", err) + } + return result, nil +} +func (r *Scheduled) _marshalJSONBaseState(x BaseState) ([]byte, error) { + result, err := shared.JSONMarshal[BaseState](x) + if err != nil { + return nil, fmt.Errorf("workflow: Scheduled._marshalJSONBaseState:; %w", err) + } + return result, nil +} +func (r *Scheduled) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONScheduled(data) + if err != nil { + return fmt.Errorf("workflow: Scheduled.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Scheduled) _unmarshalJSONScheduled(data []byte) (Scheduled, error) { + result := Scheduled{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Scheduled._unmarshalJSONScheduled: native struct unwrap; %w", err) + } + if fieldExpectedRunTimestamp, ok := partial["ExpectedRunTimestamp"]; ok { + result.ExpectedRunTimestamp, err = r._unmarshalJSONint64(fieldExpectedRunTimestamp) + if err != nil { + return result, fmt.Errorf("workflow: Scheduled._unmarshalJSONScheduled: field ExpectedRunTimestamp; %w", err) + } + } + if fieldBaseState, ok := partial["BaseState"]; ok { + result.BaseState, err = r._unmarshalJSONBaseState(fieldBaseState) + if err != nil { + return result, fmt.Errorf("workflow: Scheduled._unmarshalJSONScheduled: field BaseState; %w", err) + } + } + return result, nil +} +func (r *Scheduled) _unmarshalJSONint64(data []byte) (int64, error) { + var result int64 + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Scheduled._unmarshalJSONint64: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Scheduled) _unmarshalJSONBaseState(data []byte) (BaseState, error) { + result, err := shared.JSONUnmarshal[BaseState](data) + if err != nil { + return result, fmt.Errorf("workflow: Scheduled._unmarshalJSONBaseState: native ref unwrap; %w", err) + } + return result, nil +} + +func ScheduleStoppedFromJSON(x []byte) (*ScheduleStopped, error) { + result := new(ScheduleStopped) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func ScheduleStoppedToJSON(x *ScheduleStopped) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*ScheduleStopped)(nil) + _ json.Marshaler = (*ScheduleStopped)(nil) +) + +func (r *ScheduleStopped) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONScheduleStopped(*r) +} +func (r *ScheduleStopped) _marshalJSONScheduleStopped(x ScheduleStopped) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldBaseState []byte + fieldBaseState, err = r._marshalJSONBaseState(x.BaseState) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleStopped._marshalJSONScheduleStopped: field name BaseState; %w", err) + } + partial["BaseState"] = fieldBaseState + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleStopped._marshalJSONScheduleStopped: struct; %w", err) + } + return result, nil +} +func (r *ScheduleStopped) _marshalJSONBaseState(x BaseState) ([]byte, error) { + result, err := shared.JSONMarshal[BaseState](x) + if err != nil { + return nil, fmt.Errorf("workflow: ScheduleStopped._marshalJSONBaseState:; %w", err) + } + return result, nil +} +func (r *ScheduleStopped) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONScheduleStopped(data) + if err != nil { + return fmt.Errorf("workflow: ScheduleStopped.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *ScheduleStopped) _unmarshalJSONScheduleStopped(data []byte) (ScheduleStopped, error) { + result := ScheduleStopped{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleStopped._unmarshalJSONScheduleStopped: native struct unwrap; %w", err) + } + if fieldBaseState, ok := partial["BaseState"]; ok { + result.BaseState, err = r._unmarshalJSONBaseState(fieldBaseState) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleStopped._unmarshalJSONScheduleStopped: field BaseState; %w", err) + } + } + return result, nil +} +func (r *ScheduleStopped) _unmarshalJSONBaseState(data []byte) (BaseState, error) { + result, err := shared.JSONUnmarshal[BaseState](data) + if err != nil { + return result, fmt.Errorf("workflow: ScheduleStopped._unmarshalJSONBaseState: native ref unwrap; %w", err) + } + return result, nil +} + +type WorkflowVisitor interface { + VisitFlow(v *Flow) any + VisitFlowRef(v *FlowRef) any +} + +type Workflow interface { + AcceptWorkflow(g WorkflowVisitor) any +} + +var ( + _ Workflow = (*Flow)(nil) + _ Workflow = (*FlowRef)(nil) +) + +func (r *Flow) AcceptWorkflow(v WorkflowVisitor) any { return v.VisitFlow(r) } +func (r *FlowRef) AcceptWorkflow(v WorkflowVisitor) any { return v.VisitFlowRef(r) } + +func MatchWorkflowR3[T0, T1, T2 any]( + x Workflow, + f1 func(x *Flow) (T0, T1, T2), + f2 func(x *FlowRef) (T0, T1, T2), +) (T0, T1, T2) { + switch v := x.(type) { + case *Flow: + return f1(v) + case *FlowRef: + return f2(v) + } + var result1 T0 + var result2 T1 + var result3 T2 + return result1, result2, result3 +} + +func MatchWorkflowR2[T0, T1 any]( + x Workflow, + f1 func(x *Flow) (T0, T1), + f2 func(x *FlowRef) (T0, T1), +) (T0, T1) { + switch v := x.(type) { + case *Flow: + return f1(v) + case *FlowRef: + return f2(v) + } + var result1 T0 + var result2 T1 + return result1, result2 +} + +func MatchWorkflowR1[T0 any]( + x Workflow, + f1 func(x *Flow) T0, + f2 func(x *FlowRef) T0, +) T0 { + switch v := x.(type) { + case *Flow: + return f1(v) + case *FlowRef: + return f2(v) + } + var result1 T0 + return result1 +} + +func MatchWorkflowR0( + x Workflow, + f1 func(x *Flow), + f2 func(x *FlowRef), +) { + switch v := x.(type) { + case *Flow: + f1(v) + case *FlowRef: + f2(v) + } +} +func init() { + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Workflow", WorkflowFromJSON, WorkflowToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.Flow", FlowFromJSON, FlowToJSON) + shared.JSONMarshallerRegister("github.com/widmogrod/mkunion/x/workflow.FlowRef", FlowRefFromJSON, FlowRefToJSON) +} + +type WorkflowUnionJSON struct { + Type string `json:"$type,omitempty"` + Flow json.RawMessage `json:"workflow.Flow,omitempty"` + FlowRef json.RawMessage `json:"workflow.FlowRef,omitempty"` +} + +func WorkflowFromJSON(x []byte) (Workflow, error) { + if x == nil || len(x) == 0 { + return nil, nil + } + if string(x[:4]) == "null" { + return nil, nil + } + + var data WorkflowUnionJSON + err := json.Unmarshal(x, &data) + if err != nil { + return nil, err + } + + switch data.Type { + case "workflow.Flow": + return FlowFromJSON(data.Flow) + case "workflow.FlowRef": + return FlowRefFromJSON(data.FlowRef) + } + + if data.Flow != nil { + return FlowFromJSON(data.Flow) + } else if data.FlowRef != nil { + return FlowRefFromJSON(data.FlowRef) + } + + return nil, fmt.Errorf("workflow.Workflow: unknown type %s", data.Type) +} + +func WorkflowToJSON(x Workflow) ([]byte, error) { + if x == nil { + return nil, nil + } + return MatchWorkflowR2( + x, + func(x *Flow) ([]byte, error) { + body, err := FlowToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WorkflowUnionJSON{ + Type: "workflow.Flow", + Flow: body, + }) + }, + func(x *FlowRef) ([]byte, error) { + body, err := FlowRefToJSON(x) + if err != nil { + return nil, err + } + + return json.Marshal(WorkflowUnionJSON{ + Type: "workflow.FlowRef", + FlowRef: body, + }) + }, + ) +} + +func FlowFromJSON(x []byte) (*Flow, error) { + result := new(Flow) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func FlowToJSON(x *Flow) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*Flow)(nil) + _ json.Marshaler = (*Flow)(nil) +) + +func (r *Flow) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONFlow(*r) +} +func (r *Flow) _marshalJSONFlow(x Flow) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldName []byte + fieldName, err = r._marshalJSONstring(x.Name) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONFlow: field name Name; %w", err) + } + partial["Name"] = fieldName + var fieldArg []byte + fieldArg, err = r._marshalJSONstring(x.Arg) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONFlow: field name Arg; %w", err) + } + partial["Arg"] = fieldArg + var fieldBody []byte + fieldBody, err = r._marshalJSONSliceExpr(x.Body) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONFlow: field name Body; %w", err) + } + partial["Body"] = fieldBody + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONFlow: struct; %w", err) + } + return result, nil +} +func (r *Flow) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *Flow) _marshalJSONSliceExpr(x []Expr) ([]byte, error) { + partial := make([]json.RawMessage, len(x)) + for i, v := range x { + item, err := r._marshalJSONExpr(v) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONSliceExpr: at index %d; %w", i, err) + } + partial[i] = item + } + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONSliceExpr:; %w", err) + } + return result, nil +} +func (r *Flow) _marshalJSONExpr(x Expr) ([]byte, error) { + result, err := shared.JSONMarshal[Expr](x) + if err != nil { + return nil, fmt.Errorf("workflow: Flow._marshalJSONExpr:; %w", err) + } + return result, nil +} +func (r *Flow) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONFlow(data) + if err != nil { + return fmt.Errorf("workflow: Flow.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *Flow) _unmarshalJSONFlow(data []byte) (Flow, error) { + result := Flow{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONFlow: native struct unwrap; %w", err) + } + if fieldName, ok := partial["Name"]; ok { + result.Name, err = r._unmarshalJSONstring(fieldName) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONFlow: field Name; %w", err) + } + } + if fieldArg, ok := partial["Arg"]; ok { + result.Arg, err = r._unmarshalJSONstring(fieldArg) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONFlow: field Arg; %w", err) + } + } + if fieldBody, ok := partial["Body"]; ok { + result.Body, err = r._unmarshalJSONSliceExpr(fieldBody) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONFlow: field Body; %w", err) + } + } + return result, nil +} +func (r *Flow) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} +func (r *Flow) _unmarshalJSONSliceExpr(data []byte) ([]Expr, error) { + result := make([]Expr, 0) + var partial []json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONSliceExpr: native list unwrap; %w", err) + } + for i, v := range partial { + item, err := r._unmarshalJSONExpr(v) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONSliceExpr: at index %d; %w", i, err) + } + result = append(result, item) + } + return result, nil +} +func (r *Flow) _unmarshalJSONExpr(data []byte) (Expr, error) { + result, err := shared.JSONUnmarshal[Expr](data) + if err != nil { + return result, fmt.Errorf("workflow: Flow._unmarshalJSONExpr: native ref unwrap; %w", err) + } + return result, nil +} + +func FlowRefFromJSON(x []byte) (*FlowRef, error) { + result := new(FlowRef) + err := result.UnmarshalJSON(x) + if err != nil { + return nil, err + } + + return result, nil +} + +func FlowRefToJSON(x *FlowRef) ([]byte, error) { + return x.MarshalJSON() +} + +var ( + _ json.Unmarshaler = (*FlowRef)(nil) + _ json.Marshaler = (*FlowRef)(nil) +) + +func (r *FlowRef) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil + } + return r._marshalJSONFlowRef(*r) +} +func (r *FlowRef) _marshalJSONFlowRef(x FlowRef) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldFlowID []byte + fieldFlowID, err = r._marshalJSONstring(x.FlowID) + if err != nil { + return nil, fmt.Errorf("workflow: FlowRef._marshalJSONFlowRef: field name FlowID; %w", err) + } + partial["FlowID"] = fieldFlowID + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: FlowRef._marshalJSONFlowRef: struct; %w", err) + } + return result, nil +} +func (r *FlowRef) _marshalJSONstring(x string) ([]byte, error) { + result, err := json.Marshal(x) + if err != nil { + return nil, fmt.Errorf("workflow: FlowRef._marshalJSONstring:; %w", err) + } + return result, nil +} +func (r *FlowRef) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONFlowRef(data) + if err != nil { + return fmt.Errorf("workflow: FlowRef.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *FlowRef) _unmarshalJSONFlowRef(data []byte) (FlowRef, error) { + result := FlowRef{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: FlowRef._unmarshalJSONFlowRef: native struct unwrap; %w", err) + } + if fieldFlowID, ok := partial["FlowID"]; ok { + result.FlowID, err = r._unmarshalJSONstring(fieldFlowID) + if err != nil { + return result, fmt.Errorf("workflow: FlowRef._unmarshalJSONFlowRef: field FlowID; %w", err) + } + } + return result, nil +} +func (r *FlowRef) _unmarshalJSONstring(data []byte) (string, error) { + var result string + err := json.Unmarshal(data, &result) + if err != nil { + return result, fmt.Errorf("workflow: FlowRef._unmarshalJSONstring: native primitive unwrap; %w", err) + } + return result, nil +} diff --git a/x/workflow/workflow_other.go b/x/workflow/workflow_other.go index e3b529ee..1a53a398 100644 --- a/x/workflow/workflow_other.go +++ b/x/workflow/workflow_other.go @@ -6,7 +6,7 @@ import ( type Function func(args *FunctionInput) (*FunctionOutput, error) -//go:generate go run ../../cmd/mkunion/main.go serde +//go:generate go run ../../cmd/mkunion/main.go type ( //go:tag serde:"json" diff --git a/x/workflow/workflow_other_serde_gen.go b/x/workflow/workflow_other_serde_gen.go index 92892665..d9b21461 100644 --- a/x/workflow/workflow_other_serde_gen.go +++ b/x/workflow/workflow_other_serde_gen.go @@ -5,101 +5,9 @@ import ( "encoding/json" "fmt" "github.com/widmogrod/mkunion/x/schema" - "github.com/widmogrod/mkunion/x/shape" "github.com/widmogrod/mkunion/x/shared" ) -func init() { - shape.Register(FunctionOutputShape()) - shape.Register(FunctionInputShape()) -} - -var ( - _ json.Unmarshaler = (*FunctionOutput)(nil) - _ json.Marshaler = (*FunctionOutput)(nil) -) - -func (r *FunctionOutput) MarshalJSON() ([]byte, error) { - if r == nil { - return nil, nil - } - return r._marshalJSONFunctionOutput(*r) -} -func (r *FunctionOutput) _marshalJSONFunctionOutput(x FunctionOutput) ([]byte, error) { - partial := make(map[string]json.RawMessage) - var err error - var fieldResult []byte - fieldResult, err = r._marshalJSONschema_Schema(x.Result) - if err != nil { - return nil, fmt.Errorf("workflow: FunctionOutput._marshalJSONFunctionOutput: field name Result; %w", err) - } - partial["Result"] = fieldResult - result, err := json.Marshal(partial) - if err != nil { - return nil, fmt.Errorf("workflow: FunctionOutput._marshalJSONFunctionOutput: struct; %w", err) - } - return result, nil -} -func (r *FunctionOutput) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { - result, err := shared.JSONMarshal[schema.Schema](x) - if err != nil { - return nil, fmt.Errorf("workflow: FunctionOutput._marshalJSONschema_Schema:; %w", err) - } - return result, nil -} -func (r *FunctionOutput) UnmarshalJSON(data []byte) error { - result, err := r._unmarshalJSONFunctionOutput(data) - if err != nil { - return fmt.Errorf("workflow: FunctionOutput.UnmarshalJSON: %w", err) - } - *r = result - return nil -} -func (r *FunctionOutput) _unmarshalJSONFunctionOutput(data []byte) (FunctionOutput, error) { - result := FunctionOutput{} - var partial map[string]json.RawMessage - err := json.Unmarshal(data, &partial) - if err != nil { - return result, fmt.Errorf("workflow: FunctionOutput._unmarshalJSONFunctionOutput: native struct unwrap; %w", err) - } - if fieldResult, ok := partial["Result"]; ok { - result.Result, err = r._unmarshalJSONschema_Schema(fieldResult) - if err != nil { - return result, fmt.Errorf("workflow: FunctionOutput._unmarshalJSONFunctionOutput: field Result; %w", err) - } - } - return result, nil -} -func (r *FunctionOutput) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { - result, err := shared.JSONUnmarshal[schema.Schema](data) - if err != nil { - return result, fmt.Errorf("workflow: FunctionOutput._unmarshalJSONschema_Schema: native ref unwrap; %w", err) - } - return result, nil -} -func FunctionOutputShape() shape.Shape { - return &shape.StructLike{ - Name: "FunctionOutput", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - Fields: []*shape.FieldLike{ - { - Name: "Result", - Type: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, - } -} - var ( _ json.Unmarshaler = (*FunctionInput)(nil) _ json.Marshaler = (*FunctionInput)(nil) @@ -233,35 +141,67 @@ func (r *FunctionInput) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, } return result, nil } -func FunctionInputShape() shape.Shape { - return &shape.StructLike{ - Name: "FunctionInput", - PkgName: "workflow", - PkgImportName: "github.com/widmogrod/mkunion/x/workflow", - Fields: []*shape.FieldLike{ - { - Name: "Name", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "CallbackID", - Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, - }, - { - Name: "Args", - Type: &shape.ListLike{ - Element: &shape.RefName{ - Name: "Schema", - PkgName: "schema", - PkgImportName: "github.com/widmogrod/mkunion/x/schema", - }, - }, - }, - }, - Tags: map[string]shape.Tag{ - "serde": { - Value: "json", - }, - }, + +var ( + _ json.Unmarshaler = (*FunctionOutput)(nil) + _ json.Marshaler = (*FunctionOutput)(nil) +) + +func (r *FunctionOutput) MarshalJSON() ([]byte, error) { + if r == nil { + return nil, nil } + return r._marshalJSONFunctionOutput(*r) +} +func (r *FunctionOutput) _marshalJSONFunctionOutput(x FunctionOutput) ([]byte, error) { + partial := make(map[string]json.RawMessage) + var err error + var fieldResult []byte + fieldResult, err = r._marshalJSONschema_Schema(x.Result) + if err != nil { + return nil, fmt.Errorf("workflow: FunctionOutput._marshalJSONFunctionOutput: field name Result; %w", err) + } + partial["Result"] = fieldResult + result, err := json.Marshal(partial) + if err != nil { + return nil, fmt.Errorf("workflow: FunctionOutput._marshalJSONFunctionOutput: struct; %w", err) + } + return result, nil +} +func (r *FunctionOutput) _marshalJSONschema_Schema(x schema.Schema) ([]byte, error) { + result, err := shared.JSONMarshal[schema.Schema](x) + if err != nil { + return nil, fmt.Errorf("workflow: FunctionOutput._marshalJSONschema_Schema:; %w", err) + } + return result, nil +} +func (r *FunctionOutput) UnmarshalJSON(data []byte) error { + result, err := r._unmarshalJSONFunctionOutput(data) + if err != nil { + return fmt.Errorf("workflow: FunctionOutput.UnmarshalJSON: %w", err) + } + *r = result + return nil +} +func (r *FunctionOutput) _unmarshalJSONFunctionOutput(data []byte) (FunctionOutput, error) { + result := FunctionOutput{} + var partial map[string]json.RawMessage + err := json.Unmarshal(data, &partial) + if err != nil { + return result, fmt.Errorf("workflow: FunctionOutput._unmarshalJSONFunctionOutput: native struct unwrap; %w", err) + } + if fieldResult, ok := partial["Result"]; ok { + result.Result, err = r._unmarshalJSONschema_Schema(fieldResult) + if err != nil { + return result, fmt.Errorf("workflow: FunctionOutput._unmarshalJSONFunctionOutput: field Result; %w", err) + } + } + return result, nil +} +func (r *FunctionOutput) _unmarshalJSONschema_Schema(data []byte) (schema.Schema, error) { + result, err := shared.JSONUnmarshal[schema.Schema](data) + if err != nil { + return result, fmt.Errorf("workflow: FunctionOutput._unmarshalJSONschema_Schema: native ref unwrap; %w", err) + } + return result, nil } diff --git a/x/workflow/workflow_other_shape_gen.go b/x/workflow/workflow_other_shape_gen.go new file mode 100644 index 00000000..c6d9f502 --- /dev/null +++ b/x/workflow/workflow_other_shape_gen.go @@ -0,0 +1,69 @@ +// Code generated by mkunion. DO NOT EDIT. +package workflow + +import ( + "github.com/widmogrod/mkunion/x/shape" +) + +func init() { + shape.Register(FunctionInputShape()) + shape.Register(FunctionOutputShape()) +} + +//shape:shape +func FunctionInputShape() shape.Shape { + return &shape.StructLike{ + Name: "FunctionInput", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Name", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "CallbackID", + Type: &shape.PrimitiveLike{Kind: &shape.StringLike{}}, + }, + { + Name: "Args", + Type: &shape.ListLike{ + Element: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +} + +//shape:shape +func FunctionOutputShape() shape.Shape { + return &shape.StructLike{ + Name: "FunctionOutput", + PkgName: "workflow", + PkgImportName: "github.com/widmogrod/mkunion/x/workflow", + Fields: []*shape.FieldLike{ + { + Name: "Result", + Type: &shape.RefName{ + Name: "Schema", + PkgName: "schema", + PkgImportName: "github.com/widmogrod/mkunion/x/schema", + }, + }, + }, + Tags: map[string]shape.Tag{ + "serde": { + Value: "json", + }, + }, + } +}