diff --git a/examples/chat/room_commands.go b/examples/chat/room_commands.go index ed0d8c4..36feca5 100644 --- a/examples/chat/room_commands.go +++ b/examples/chat/room_commands.go @@ -1,5 +1,7 @@ package chat +//go:generate go run ../../gen/commandgenerator/main.go -id RoomID -aggregateType room + type OnBoardRoom struct { RoomID string `json:"roomID"` UserID string `json:"userID"` @@ -35,29 +37,3 @@ type BanUserFromRoom struct { Reason string `json:"reason"` Timeout uint `json:"timeout"` } - -// TODO: Generate code below - -func (c OnBoardRoom) AggregateID() string { return c.RoomID } -func (c OnBoardRoom) AggregateType() string { return "room" } -func (c OnBoardRoom) CommandType() string { return "OnBoardRoom" } - -func (c JoinRoom) AggregateID() string { return c.RoomID } -func (c JoinRoom) AggregateType() string { return "room" } -func (c JoinRoom) CommandType() string { return "JoinRoom" } - -func (c SendMessageToRoom) AggregateID() string { return c.RoomID } -func (c SendMessageToRoom) AggregateType() string { return "room" } -func (c SendMessageToRoom) CommandType() string { return "SendMessageToRoom" } - -func (c SendPrivateMessageToRoom) AggregateID() string { return c.RoomID } -func (c SendPrivateMessageToRoom) AggregateType() string { return "room" } -func (c SendPrivateMessageToRoom) CommandType() string { return "SendPrivateMessageToRoom" } - -func (c RemoveUserFromRoom) AggregateID() string { return c.RoomID } -func (c RemoveUserFromRoom) AggregateType() string { return "room" } -func (c RemoveUserFromRoom) CommandType() string { return "RemoveUserFromRoom" } - -func (c BanUserFromRoom) AggregateID() string { return c.RoomID } -func (c BanUserFromRoom) AggregateType() string { return "room" } -func (c BanUserFromRoom) CommandType() string { return "BanUserFromRoom" } diff --git a/examples/chat/room_commands_gen.go b/examples/chat/room_commands_gen.go new file mode 100644 index 0000000..40b085d --- /dev/null +++ b/examples/chat/room_commands_gen.go @@ -0,0 +1,28 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated at +// 2021-01-30 11:27:48.039104 -0800 PST m=+0.001821984 +package chat + +func (c OnBoardRoom) AggregateID() string { return c.RoomID } +func (c OnBoardRoom) AggregateType() string { return "room" } +func (c OnBoardRoom) CommandType() string { return "OnBoardRoom" } + +func (c JoinRoom) AggregateID() string { return c.RoomID } +func (c JoinRoom) AggregateType() string { return "room" } +func (c JoinRoom) CommandType() string { return "JoinRoom" } + +func (c SendMessageToRoom) AggregateID() string { return c.RoomID } +func (c SendMessageToRoom) AggregateType() string { return "room" } +func (c SendMessageToRoom) CommandType() string { return "SendMessageToRoom" } + +func (c SendPrivateMessageToRoom) AggregateID() string { return c.RoomID } +func (c SendPrivateMessageToRoom) AggregateType() string { return "room" } +func (c SendPrivateMessageToRoom) CommandType() string { return "SendPrivateMessageToRoom" } + +func (c RemoveUserFromRoom) AggregateID() string { return c.RoomID } +func (c RemoveUserFromRoom) AggregateType() string { return "room" } +func (c RemoveUserFromRoom) CommandType() string { return "RemoveUserFromRoom" } + +func (c BanUserFromRoom) AggregateID() string { return c.RoomID } +func (c BanUserFromRoom) AggregateType() string { return "room" } +func (c BanUserFromRoom) CommandType() string { return "BanUserFromRoom" } diff --git a/examples/chat/user_commands.go b/examples/chat/user_commands.go index 770ea75..913ba16 100644 --- a/examples/chat/user_commands.go +++ b/examples/chat/user_commands.go @@ -1,5 +1,7 @@ package chat +//go:generate go run ../../gen/commandgenerator/main.go -id UserID -aggregateType user + type OnBoardUser struct { UserID string `json:"userID"` Name string `json:"name"` @@ -9,13 +11,3 @@ type WarnUser struct { UserID string `json:"userID"` Reason string `json:"reason"` } - -// TODO: Generate code below - -func (c OnBoardUser) AggregateID() string { return c.UserID } -func (c OnBoardUser) AggregateType() string { return "user" } -func (c OnBoardUser) CommandType() string { return "OnBoardUser" } - -func (c WarnUser) AggregateID() string { return c.UserID } -func (c WarnUser) AggregateType() string { return "user" } -func (c WarnUser) CommandType() string { return "WarnUser" } diff --git a/examples/chat/user_commands_gen.go b/examples/chat/user_commands_gen.go new file mode 100644 index 0000000..04534ed --- /dev/null +++ b/examples/chat/user_commands_gen.go @@ -0,0 +1,12 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated at +// 2021-01-30 11:29:08.177616 -0800 PST m=+0.001769886 +package chat + +func (c OnBoardUser) AggregateID() string { return c.UserID } +func (c OnBoardUser) AggregateType() string { return "user" } +func (c OnBoardUser) CommandType() string { return "OnBoardUser" } + +func (c WarnUser) AggregateID() string { return c.UserID } +func (c WarnUser) AggregateType() string { return "user" } +func (c WarnUser) CommandType() string { return "WarnUser" } diff --git a/gen/commandgenerator/main.go b/gen/commandgenerator/main.go new file mode 100644 index 0000000..d60df4f --- /dev/null +++ b/gen/commandgenerator/main.go @@ -0,0 +1,55 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "path" + "strings" + + "github.com/inklabs/rangedb/pkg/commandgenerator" + "github.com/inklabs/rangedb/pkg/structparser" +) + +func main() { + pkg := flag.String("package", os.Getenv("GOPACKAGE"), "package") + id := flag.String("id", "", "id") + aggregateType := flag.String("aggregateType", "", "aggregate name") + inFilePath := flag.String("inFile", os.Getenv("GOFILE"), "input filename containing commands") + outFilePath := flag.String("outFile", "", "output file name") + flag.Parse() + + if *outFilePath == "" { + if *outFilePath == "" { + fileName := strings.TrimSuffix(*inFilePath, path.Ext(*inFilePath)) + *outFilePath = fmt.Sprintf("%s_gen.go", fileName) + } + } + + commandsFile, err := os.Open(*inFilePath) + if err != nil { + log.Fatalf("unable to open (%s): %v", *inFilePath, err) + } + defer func() { + _ = commandsFile.Close() + }() + + commands, err := structparser.GetStructNames(commandsFile) + if err != nil { + log.Fatalf("unable to extract commands: %v", err) + } + + outFile, err := os.Create(*outFilePath) + if err != nil { + log.Fatalf("unable to create aggreate file: %v", err) + } + defer func() { + _ = outFile.Close() + }() + + err = commandgenerator.Write(outFile, commands, *pkg, *id, *aggregateType) + if err != nil { + log.Fatalf("unable to write to aggregates file: %v", err) + } +} diff --git a/pkg/aggregategenerator/write_aggregate_test.go b/pkg/aggregategenerator/write_aggregate_test.go index ef05d21..d4d0e2c 100644 --- a/pkg/aggregategenerator/write_aggregate_test.go +++ b/pkg/aggregategenerator/write_aggregate_test.go @@ -156,5 +156,4 @@ func (a *thing) raise(events ...rangedb.Event) { ` assert.Equal(t, expectedOut, out.String()) }) - } diff --git a/pkg/commandgenerator/write_command.go b/pkg/commandgenerator/write_command.go new file mode 100644 index 0000000..3cca7d2 --- /dev/null +++ b/pkg/commandgenerator/write_command.go @@ -0,0 +1,45 @@ +package commandgenerator + +import ( + "fmt" + "io" + "text/template" + "time" +) + +var NowFunc = time.Now + +func Write(out io.Writer, commands []string, pkg, id, aggregateType string) error { + if len(commands) < 1 { + return fmt.Errorf("no commands found") + } + + return fileTemplate.Execute(out, templateData{ + Timestamp: NowFunc(), + Commands: commands, + AggregateType: aggregateType, + ID: id, + Package: pkg, + }) +} + +type templateData struct { + Timestamp time.Time + Commands []string + AggregateType string + ID string + Package string +} + +var fileTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT. +// This file was generated at +// {{ .Timestamp }} +package {{ $.Package }} + +{{- range .Commands }} + +func (c {{ . }}) AggregateID() string { return c.{{ $.ID }} } +func (c {{ . }}) AggregateType() string { return "{{ $.AggregateType }}" } +func (c {{ . }}) CommandType() string { return "{{ . }}" } +{{- end }} +`)) diff --git a/pkg/commandgenerator/write_command_test.go b/pkg/commandgenerator/write_command_test.go new file mode 100644 index 0000000..4e5dfc8 --- /dev/null +++ b/pkg/commandgenerator/write_command_test.go @@ -0,0 +1,88 @@ +package commandgenerator_test + +import ( + "bytes" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/inklabs/rangedb/pkg/commandgenerator" +) + +func TestWrite(t *testing.T) { + const ( + pkg = "mypkg" + id = "ID" + aggregateType = "thing" + ) + commandgenerator.NowFunc = func() time.Time { + return time.Unix(1611080667, 25600800).UTC() + } + + t.Run("no commands found", func(t *testing.T) { + // Given + var commands []string + var out bytes.Buffer + + // When + err := commandgenerator.Write(&out, commands, pkg, id, aggregateType) + + // Then + require.EqualError(t, err, "no commands found") + }) + + t.Run("single command", func(t *testing.T) { + // Given + commands := []string{ + "DoThing", + } + var out bytes.Buffer + + // When + err := commandgenerator.Write(&out, commands, pkg, id, aggregateType) + + // Then + require.NoError(t, err) + expectedOut := `// Code generated by go generate; DO NOT EDIT. +// This file was generated at +// 2021-01-19 18:24:27.0256008 +0000 UTC +package mypkg + +func (c DoThing) AggregateID() string { return c.ID } +func (c DoThing) AggregateType() string { return "thing" } +func (c DoThing) CommandType() string { return "DoThing" } +` + assert.Equal(t, expectedOut, out.String()) + }) + + t.Run("two commands", func(t *testing.T) { + // Given + commands := []string{ + "DoThing", + "DoAnother", + } + var out bytes.Buffer + + // When + err := commandgenerator.Write(&out, commands, pkg, id, aggregateType) + + // Then + require.NoError(t, err) + expectedOut := `// Code generated by go generate; DO NOT EDIT. +// This file was generated at +// 2021-01-19 18:24:27.0256008 +0000 UTC +package mypkg + +func (c DoThing) AggregateID() string { return c.ID } +func (c DoThing) AggregateType() string { return "thing" } +func (c DoThing) CommandType() string { return "DoThing" } + +func (c DoAnother) AggregateID() string { return c.ID } +func (c DoAnother) AggregateType() string { return "thing" } +func (c DoAnother) CommandType() string { return "DoAnother" } +` + assert.Equal(t, expectedOut, out.String()) + }) +}