From 958fd787187c2e6b17b4ad2133c3b4168e8f753c Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:51:20 +0200 Subject: [PATCH 01/19] feat(examples): scaffold todolist proto contracts Ten proto files following the 1-1-1 best practice (one service per file, one message per file): - domain messages: todo_list, todo_item - command requests: create_todo_list_request, add_todo_item_request, mark_todo_item_as_done_request, mark_todo_item_as_pending_request, delete_todo_item_request - query request: get_todo_list_request - query response: get_todo_list_response - service: todo_list_service Design choices: - Connect-only. No google.api.http annotations, no googleapis dep. - Commands return google.protobuf.Empty; clients generate IDs. - Queries return dedicated response messages. Lint config allows empty RPC responses (the rest of the rules match internal/user/proto/buf.yaml). --- examples/todolist/buf.gen.yaml | 13 ++++++++ examples/todolist/proto/buf.yaml | 11 +++++++ .../todolist/v1/add_todo_item_request.proto | 21 +++++++++++++ .../v1/create_todo_list_request.proto | 17 ++++++++++ .../v1/delete_todo_item_request.proto | 11 +++++++ .../todolist/v1/get_todo_list_request.proto | 9 ++++++ .../todolist/v1/get_todo_list_response.proto | 11 +++++++ .../v1/mark_todo_item_as_done_request.proto | 11 +++++++ .../mark_todo_item_as_pending_request.proto | 12 +++++++ .../proto/todolist/v1/todo_item.proto | 21 +++++++++++++ .../proto/todolist/v1/todo_list.proto | 20 ++++++++++++ .../proto/todolist/v1/todo_list_service.proto | 31 +++++++++++++++++++ 12 files changed, 188 insertions(+) create mode 100644 examples/todolist/buf.gen.yaml create mode 100644 examples/todolist/proto/buf.yaml create mode 100644 examples/todolist/proto/todolist/v1/add_todo_item_request.proto create mode 100644 examples/todolist/proto/todolist/v1/create_todo_list_request.proto create mode 100644 examples/todolist/proto/todolist/v1/delete_todo_item_request.proto create mode 100644 examples/todolist/proto/todolist/v1/get_todo_list_request.proto create mode 100644 examples/todolist/proto/todolist/v1/get_todo_list_response.proto create mode 100644 examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto create mode 100644 examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto create mode 100644 examples/todolist/proto/todolist/v1/todo_item.proto create mode 100644 examples/todolist/proto/todolist/v1/todo_list.proto create mode 100644 examples/todolist/proto/todolist/v1/todo_list_service.proto diff --git a/examples/todolist/buf.gen.yaml b/examples/todolist/buf.gen.yaml new file mode 100644 index 00000000..c7a58099 --- /dev/null +++ b/examples/todolist/buf.gen.yaml @@ -0,0 +1,13 @@ +--- +version: v1 +managed: + enabled: true + go_package_prefix: + default: github.com/get-eventually/go-eventually/examples/todolist/gen +plugins: + - plugin: buf.build/protocolbuffers/go:v1.31.0 + out: gen + opt: paths=source_relative + - plugin: buf.build/connectrpc/go:v1.12.0 + out: gen + opt: paths=source_relative diff --git a/examples/todolist/proto/buf.yaml b/examples/todolist/proto/buf.yaml new file mode 100644 index 00000000..7af4845e --- /dev/null +++ b/examples/todolist/proto/buf.yaml @@ -0,0 +1,11 @@ +version: v1 +breaking: + use: + - FILE +lint: + rpc_allow_google_protobuf_empty_responses: true + use: + - DEFAULT + - COMMENTS + - UNARY_RPC + - PACKAGE_NO_IMPORT_CYCLE diff --git a/examples/todolist/proto/todolist/v1/add_todo_item_request.proto b/examples/todolist/proto/todolist/v1/add_todo_item_request.proto new file mode 100644 index 00000000..28643617 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/add_todo_item_request.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package todolist.v1; + +import "google/protobuf/timestamp.proto"; + +// AddTodoItemRequest adds a new TodoItem to an existing TodoList. +// +// The todo_item_id is client-generated, same as in CreateTodoListRequest. +message AddTodoItemRequest { + // UUID of the target list. + string todo_list_id = 1; + // Client-generated UUID for the new item. + string todo_item_id = 2; + // Short title of the item. + string title = 3; + // Free-form description of the item. + string description = 4; + // Optional due date; omit for no due date. + google.protobuf.Timestamp due_date = 5; +} diff --git a/examples/todolist/proto/todolist/v1/create_todo_list_request.proto b/examples/todolist/proto/todolist/v1/create_todo_list_request.proto new file mode 100644 index 00000000..1a57efd6 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/create_todo_list_request.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package todolist.v1; + +// CreateTodoListRequest creates a new TodoList with the specified ID. +// +// The todo_list_id is client-generated: clients are expected to generate a +// UUID and pass it in the request. This keeps the command idempotent and +// frees the response of a payload. +message CreateTodoListRequest { + // Client-generated UUID for the new list. + string todo_list_id = 1; + // Display title of the list. + string title = 2; + // Owner identifier. + string owner = 3; +} diff --git a/examples/todolist/proto/todolist/v1/delete_todo_item_request.proto b/examples/todolist/proto/todolist/v1/delete_todo_item_request.proto new file mode 100644 index 00000000..6b3586bf --- /dev/null +++ b/examples/todolist/proto/todolist/v1/delete_todo_item_request.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package todolist.v1; + +// DeleteTodoItemRequest removes an item from a TodoList. +message DeleteTodoItemRequest { + // UUID of the list that owns the item. + string todo_list_id = 1; + // UUID of the item to delete. + string todo_item_id = 2; +} diff --git a/examples/todolist/proto/todolist/v1/get_todo_list_request.proto b/examples/todolist/proto/todolist/v1/get_todo_list_request.proto new file mode 100644 index 00000000..f0b38303 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/get_todo_list_request.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package todolist.v1; + +// GetTodoListRequest fetches a TodoList by its ID. +message GetTodoListRequest { + // UUID of the list to fetch. + string todo_list_id = 1; +} diff --git a/examples/todolist/proto/todolist/v1/get_todo_list_response.proto b/examples/todolist/proto/todolist/v1/get_todo_list_response.proto new file mode 100644 index 00000000..73f94a59 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/get_todo_list_response.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package todolist.v1; + +import "todolist/v1/todo_list.proto"; + +// GetTodoListResponse contains the requested TodoList. +message GetTodoListResponse { + // The requested list. + TodoList todo_list = 1; +} diff --git a/examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto b/examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto new file mode 100644 index 00000000..effc89c3 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package todolist.v1; + +// MarkTodoItemAsDoneRequest marks an item in a TodoList as completed. +message MarkTodoItemAsDoneRequest { + // UUID of the list that owns the item. + string todo_list_id = 1; + // UUID of the item to mark as done. + string todo_item_id = 2; +} diff --git a/examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto b/examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto new file mode 100644 index 00000000..9074db88 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package todolist.v1; + +// MarkTodoItemAsPendingRequest marks an item in a TodoList as pending +// (i.e., undoes a previous "mark as done"). +message MarkTodoItemAsPendingRequest { + // UUID of the list that owns the item. + string todo_list_id = 1; + // UUID of the item to mark as pending. + string todo_item_id = 2; +} diff --git a/examples/todolist/proto/todolist/v1/todo_item.proto b/examples/todolist/proto/todolist/v1/todo_item.proto new file mode 100644 index 00000000..cf596213 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/todo_item.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package todolist.v1; + +import "google/protobuf/timestamp.proto"; + +// TodoItem is a single entry in a TodoList. +message TodoItem { + // Unique identifier (UUID) for this item. + string id = 1; + // Short title of the item. + string title = 2; + // Free-form description of the item. + string description = 3; + // Whether the item is completed. + bool completed = 4; + // Optional due date; zero-valued if not set. + google.protobuf.Timestamp due_date = 5; + // When the item was added to its list. + google.protobuf.Timestamp creation_time = 6; +} diff --git a/examples/todolist/proto/todolist/v1/todo_list.proto b/examples/todolist/proto/todolist/v1/todo_list.proto new file mode 100644 index 00000000..42180627 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/todo_list.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package todolist.v1; + +import "google/protobuf/timestamp.proto"; +import "todolist/v1/todo_item.proto"; + +// TodoList is a list of TodoItems belonging to an owner. +message TodoList { + // Unique identifier (UUID) for this list. + string id = 1; + // Display title of the list. + string title = 2; + // Owner identifier (application-defined, typically a username). + string owner = 3; + // When the list was created. + google.protobuf.Timestamp creation_time = 4; + // Items currently in the list, in insertion order. + repeated TodoItem items = 5; +} diff --git a/examples/todolist/proto/todolist/v1/todo_list_service.proto b/examples/todolist/proto/todolist/v1/todo_list_service.proto new file mode 100644 index 00000000..03f6eb09 --- /dev/null +++ b/examples/todolist/proto/todolist/v1/todo_list_service.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package todolist.v1; + +import "google/protobuf/empty.proto"; +import "todolist/v1/add_todo_item_request.proto"; +import "todolist/v1/create_todo_list_request.proto"; +import "todolist/v1/delete_todo_item_request.proto"; +import "todolist/v1/get_todo_list_request.proto"; +import "todolist/v1/get_todo_list_response.proto"; +import "todolist/v1/mark_todo_item_as_done_request.proto"; +import "todolist/v1/mark_todo_item_as_pending_request.proto"; + +// TodoListService exposes TodoList operations over Connect. +// +// Commands return google.protobuf.Empty; they never produce response +// payloads. Queries return a dedicated response message. +service TodoListService { + // CreateTodoList creates a new TodoList with a client-generated ID. + rpc CreateTodoList(CreateTodoListRequest) returns (google.protobuf.Empty); + // GetTodoList fetches an existing TodoList by ID. + rpc GetTodoList(GetTodoListRequest) returns (GetTodoListResponse); + // AddTodoItem appends a new item to an existing TodoList. + rpc AddTodoItem(AddTodoItemRequest) returns (google.protobuf.Empty); + // MarkTodoItemAsDone marks an existing item as completed. + rpc MarkTodoItemAsDone(MarkTodoItemAsDoneRequest) returns (google.protobuf.Empty); + // MarkTodoItemAsPending reverts a previous "mark as done". + rpc MarkTodoItemAsPending(MarkTodoItemAsPendingRequest) returns (google.protobuf.Empty); + // DeleteTodoItem removes an item from a TodoList. + rpc DeleteTodoItem(DeleteTodoItemRequest) returns (google.protobuf.Empty); +} From e4f02b5badcacf42b4185768769d81dc2c3efa96 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:51:54 +0200 Subject: [PATCH 02/19] feat(examples): generate connect stubs for todolist Vendored output of `buf generate` against the proto contracts. Stubs use the connectrpc.com/connect codegen (pinned in buf.gen.yaml): - one .pb.go per proto message file - one .connect.go for the full service Committing generated code keeps `go run ./examples/todolist` usable with just a Go toolchain, no buf dependency. Regenerate by running `buf generate proto` from the example root. --- .../todolist/v1/add_todo_item_request.pb.go | 211 +++++++++++++++ .../v1/create_todo_list_request.pb.go | 184 +++++++++++++ .../v1/delete_todo_item_request.pb.go | 171 ++++++++++++ .../todolist/v1/get_todo_list_request.pb.go | 159 +++++++++++ .../todolist/v1/get_todo_list_response.pb.go | 165 ++++++++++++ .../v1/mark_todo_item_as_done_request.pb.go | 171 ++++++++++++ .../mark_todo_item_as_pending_request.pb.go | 173 ++++++++++++ .../todolist/gen/todolist/v1/todo_item.pb.go | 220 +++++++++++++++ .../todolist/gen/todolist/v1/todo_list.pb.go | 211 +++++++++++++++ .../gen/todolist/v1/todo_list_service.pb.go | 157 +++++++++++ .../todo_list_service.connect.go | 253 ++++++++++++++++++ 11 files changed, 2075 insertions(+) create mode 100644 examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go create mode 100644 examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go create mode 100644 examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go create mode 100644 examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go create mode 100644 examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go create mode 100644 examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go create mode 100644 examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go create mode 100644 examples/todolist/gen/todolist/v1/todo_item.pb.go create mode 100644 examples/todolist/gen/todolist/v1/todo_list.pb.go create mode 100644 examples/todolist/gen/todolist/v1/todo_list_service.pb.go create mode 100644 examples/todolist/gen/todolist/v1/todolistv1connect/todo_list_service.connect.go diff --git a/examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go b/examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go new file mode 100644 index 00000000..8760dab5 --- /dev/null +++ b/examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go @@ -0,0 +1,211 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/add_todo_item_request.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// AddTodoItemRequest adds a new TodoItem to an existing TodoList. +// +// The todo_item_id is client-generated, same as in CreateTodoListRequest. +type AddTodoItemRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the target list. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // Client-generated UUID for the new item. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` + // Short title of the item. + Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"` + // Free-form description of the item. + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + // Optional due date; omit for no due date. + DueDate *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=due_date,json=dueDate,proto3" json:"due_date,omitempty"` +} + +func (x *AddTodoItemRequest) Reset() { + *x = AddTodoItemRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_add_todo_item_request_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddTodoItemRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddTodoItemRequest) ProtoMessage() {} + +func (x *AddTodoItemRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_add_todo_item_request_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddTodoItemRequest.ProtoReflect.Descriptor instead. +func (*AddTodoItemRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_add_todo_item_request_proto_rawDescGZIP(), []int{0} +} + +func (x *AddTodoItemRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *AddTodoItemRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +func (x *AddTodoItemRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *AddTodoItemRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *AddTodoItemRequest) GetDueDate() *timestamppb.Timestamp { + if x != nil { + return x.DueDate + } + return nil +} + +var File_todolist_v1_add_todo_item_request_proto protoreflect.FileDescriptor + +var file_todolist_v1_add_todo_item_request_proto_rawDesc = []byte{ + 0x0a, 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, + 0x64, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x54, + 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, + 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, + 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x75, 0x65, 0x44, 0x61, 0x74, + 0x65, 0x42, 0xcd, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x17, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, + 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, + 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, + 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_add_todo_item_request_proto_rawDescOnce sync.Once + file_todolist_v1_add_todo_item_request_proto_rawDescData = file_todolist_v1_add_todo_item_request_proto_rawDesc +) + +func file_todolist_v1_add_todo_item_request_proto_rawDescGZIP() []byte { + file_todolist_v1_add_todo_item_request_proto_rawDescOnce.Do(func() { + file_todolist_v1_add_todo_item_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_add_todo_item_request_proto_rawDescData) + }) + return file_todolist_v1_add_todo_item_request_proto_rawDescData +} + +var file_todolist_v1_add_todo_item_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_add_todo_item_request_proto_goTypes = []interface{}{ + (*AddTodoItemRequest)(nil), // 0: todolist.v1.AddTodoItemRequest + (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp +} +var file_todolist_v1_add_todo_item_request_proto_depIdxs = []int32{ + 1, // 0: todolist.v1.AddTodoItemRequest.due_date:type_name -> google.protobuf.Timestamp + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_todolist_v1_add_todo_item_request_proto_init() } +func file_todolist_v1_add_todo_item_request_proto_init() { + if File_todolist_v1_add_todo_item_request_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_add_todo_item_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddTodoItemRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_add_todo_item_request_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_add_todo_item_request_proto_goTypes, + DependencyIndexes: file_todolist_v1_add_todo_item_request_proto_depIdxs, + MessageInfos: file_todolist_v1_add_todo_item_request_proto_msgTypes, + }.Build() + File_todolist_v1_add_todo_item_request_proto = out.File + file_todolist_v1_add_todo_item_request_proto_rawDesc = nil + file_todolist_v1_add_todo_item_request_proto_goTypes = nil + file_todolist_v1_add_todo_item_request_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go b/examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go new file mode 100644 index 00000000..cf1283c2 --- /dev/null +++ b/examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go @@ -0,0 +1,184 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/create_todo_list_request.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// CreateTodoListRequest creates a new TodoList with the specified ID. +// +// The todo_list_id is client-generated: clients are expected to generate a +// UUID and pass it in the request. This keeps the command idempotent and +// frees the response of a payload. +type CreateTodoListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Client-generated UUID for the new list. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // Display title of the list. + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + // Owner identifier. + Owner string `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` +} + +func (x *CreateTodoListRequest) Reset() { + *x = CreateTodoListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_create_todo_list_request_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateTodoListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTodoListRequest) ProtoMessage() {} + +func (x *CreateTodoListRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_create_todo_list_request_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateTodoListRequest.ProtoReflect.Descriptor instead. +func (*CreateTodoListRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_create_todo_list_request_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateTodoListRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *CreateTodoListRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *CreateTodoListRequest) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +var File_todolist_v1_create_todo_list_request_proto protoreflect.FileDescriptor + +var file_todolist_v1_create_todo_list_request_proto_rawDesc = []byte{ + 0x0a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x65, 0x0a, 0x15, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, + 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x42, 0xd0, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x42, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, + 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, + 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, + 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_create_todo_list_request_proto_rawDescOnce sync.Once + file_todolist_v1_create_todo_list_request_proto_rawDescData = file_todolist_v1_create_todo_list_request_proto_rawDesc +) + +func file_todolist_v1_create_todo_list_request_proto_rawDescGZIP() []byte { + file_todolist_v1_create_todo_list_request_proto_rawDescOnce.Do(func() { + file_todolist_v1_create_todo_list_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_create_todo_list_request_proto_rawDescData) + }) + return file_todolist_v1_create_todo_list_request_proto_rawDescData +} + +var file_todolist_v1_create_todo_list_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_create_todo_list_request_proto_goTypes = []interface{}{ + (*CreateTodoListRequest)(nil), // 0: todolist.v1.CreateTodoListRequest +} +var file_todolist_v1_create_todo_list_request_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_todolist_v1_create_todo_list_request_proto_init() } +func file_todolist_v1_create_todo_list_request_proto_init() { + if File_todolist_v1_create_todo_list_request_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_create_todo_list_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTodoListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_create_todo_list_request_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_create_todo_list_request_proto_goTypes, + DependencyIndexes: file_todolist_v1_create_todo_list_request_proto_depIdxs, + MessageInfos: file_todolist_v1_create_todo_list_request_proto_msgTypes, + }.Build() + File_todolist_v1_create_todo_list_request_proto = out.File + file_todolist_v1_create_todo_list_request_proto_rawDesc = nil + file_todolist_v1_create_todo_list_request_proto_goTypes = nil + file_todolist_v1_create_todo_list_request_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go b/examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go new file mode 100644 index 00000000..76b3ea27 --- /dev/null +++ b/examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/delete_todo_item_request.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// DeleteTodoItemRequest removes an item from a TodoList. +type DeleteTodoItemRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list that owns the item. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // UUID of the item to delete. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` +} + +func (x *DeleteTodoItemRequest) Reset() { + *x = DeleteTodoItemRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_delete_todo_item_request_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteTodoItemRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteTodoItemRequest) ProtoMessage() {} + +func (x *DeleteTodoItemRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_delete_todo_item_request_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteTodoItemRequest.ProtoReflect.Descriptor instead. +func (*DeleteTodoItemRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_delete_todo_item_request_proto_rawDescGZIP(), []int{0} +} + +func (x *DeleteTodoItemRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *DeleteTodoItemRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +var File_todolist_v1_delete_todo_item_request_proto protoreflect.FileDescriptor + +var file_todolist_v1_delete_todo_item_request_proto_rawDesc = []byte{ + 0x0a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x5b, 0x0a, 0x15, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, + 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, + 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x42, 0xd0, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x1a, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, + 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, + 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, + 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, + 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_todolist_v1_delete_todo_item_request_proto_rawDescOnce sync.Once + file_todolist_v1_delete_todo_item_request_proto_rawDescData = file_todolist_v1_delete_todo_item_request_proto_rawDesc +) + +func file_todolist_v1_delete_todo_item_request_proto_rawDescGZIP() []byte { + file_todolist_v1_delete_todo_item_request_proto_rawDescOnce.Do(func() { + file_todolist_v1_delete_todo_item_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_delete_todo_item_request_proto_rawDescData) + }) + return file_todolist_v1_delete_todo_item_request_proto_rawDescData +} + +var file_todolist_v1_delete_todo_item_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_delete_todo_item_request_proto_goTypes = []interface{}{ + (*DeleteTodoItemRequest)(nil), // 0: todolist.v1.DeleteTodoItemRequest +} +var file_todolist_v1_delete_todo_item_request_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_todolist_v1_delete_todo_item_request_proto_init() } +func file_todolist_v1_delete_todo_item_request_proto_init() { + if File_todolist_v1_delete_todo_item_request_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_delete_todo_item_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteTodoItemRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_delete_todo_item_request_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_delete_todo_item_request_proto_goTypes, + DependencyIndexes: file_todolist_v1_delete_todo_item_request_proto_depIdxs, + MessageInfos: file_todolist_v1_delete_todo_item_request_proto_msgTypes, + }.Build() + File_todolist_v1_delete_todo_item_request_proto = out.File + file_todolist_v1_delete_todo_item_request_proto_rawDesc = nil + file_todolist_v1_delete_todo_item_request_proto_goTypes = nil + file_todolist_v1_delete_todo_item_request_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go b/examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go new file mode 100644 index 00000000..ae17c8f0 --- /dev/null +++ b/examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go @@ -0,0 +1,159 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/get_todo_list_request.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// GetTodoListRequest fetches a TodoList by its ID. +type GetTodoListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list to fetch. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` +} + +func (x *GetTodoListRequest) Reset() { + *x = GetTodoListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_get_todo_list_request_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTodoListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTodoListRequest) ProtoMessage() {} + +func (x *GetTodoListRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_get_todo_list_request_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTodoListRequest.ProtoReflect.Descriptor instead. +func (*GetTodoListRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_get_todo_list_request_proto_rawDescGZIP(), []int{0} +} + +func (x *GetTodoListRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +var File_todolist_v1_get_todo_list_request_proto protoreflect.FileDescriptor + +var file_todolist_v1_get_todo_list_request_proto_rawDesc = []byte{ + 0x0a, 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, + 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x36, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, + 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, + 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x42, 0xcd, + 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x42, 0x17, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, + 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, + 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_get_todo_list_request_proto_rawDescOnce sync.Once + file_todolist_v1_get_todo_list_request_proto_rawDescData = file_todolist_v1_get_todo_list_request_proto_rawDesc +) + +func file_todolist_v1_get_todo_list_request_proto_rawDescGZIP() []byte { + file_todolist_v1_get_todo_list_request_proto_rawDescOnce.Do(func() { + file_todolist_v1_get_todo_list_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_get_todo_list_request_proto_rawDescData) + }) + return file_todolist_v1_get_todo_list_request_proto_rawDescData +} + +var file_todolist_v1_get_todo_list_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_get_todo_list_request_proto_goTypes = []interface{}{ + (*GetTodoListRequest)(nil), // 0: todolist.v1.GetTodoListRequest +} +var file_todolist_v1_get_todo_list_request_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_todolist_v1_get_todo_list_request_proto_init() } +func file_todolist_v1_get_todo_list_request_proto_init() { + if File_todolist_v1_get_todo_list_request_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_get_todo_list_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTodoListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_get_todo_list_request_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_get_todo_list_request_proto_goTypes, + DependencyIndexes: file_todolist_v1_get_todo_list_request_proto_depIdxs, + MessageInfos: file_todolist_v1_get_todo_list_request_proto_msgTypes, + }.Build() + File_todolist_v1_get_todo_list_request_proto = out.File + file_todolist_v1_get_todo_list_request_proto_rawDesc = nil + file_todolist_v1_get_todo_list_request_proto_goTypes = nil + file_todolist_v1_get_todo_list_request_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go b/examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go new file mode 100644 index 00000000..14e5fd82 --- /dev/null +++ b/examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go @@ -0,0 +1,165 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/get_todo_list_response.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// GetTodoListResponse contains the requested TodoList. +type GetTodoListResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The requested list. + TodoList *TodoList `protobuf:"bytes,1,opt,name=todo_list,json=todoList,proto3" json:"todo_list,omitempty"` +} + +func (x *GetTodoListResponse) Reset() { + *x = GetTodoListResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_get_todo_list_response_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTodoListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTodoListResponse) ProtoMessage() {} + +func (x *GetTodoListResponse) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_get_todo_list_response_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTodoListResponse.ProtoReflect.Descriptor instead. +func (*GetTodoListResponse) Descriptor() ([]byte, []int) { + return file_todolist_v1_get_todo_list_response_proto_rawDescGZIP(), []int{0} +} + +func (x *GetTodoListResponse) GetTodoList() *TodoList { + if x != nil { + return x.TodoList + } + return nil +} + +var File_todolist_v1_get_todo_list_response_proto protoreflect.FileDescriptor + +var file_todolist_v1_get_todo_list_response_proto_rawDesc = []byte{ + 0x0a, 0x28, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, + 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, + 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x49, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x74, + 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x64, + 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x42, + 0xce, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x42, 0x18, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, + 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_get_todo_list_response_proto_rawDescOnce sync.Once + file_todolist_v1_get_todo_list_response_proto_rawDescData = file_todolist_v1_get_todo_list_response_proto_rawDesc +) + +func file_todolist_v1_get_todo_list_response_proto_rawDescGZIP() []byte { + file_todolist_v1_get_todo_list_response_proto_rawDescOnce.Do(func() { + file_todolist_v1_get_todo_list_response_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_get_todo_list_response_proto_rawDescData) + }) + return file_todolist_v1_get_todo_list_response_proto_rawDescData +} + +var file_todolist_v1_get_todo_list_response_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_get_todo_list_response_proto_goTypes = []interface{}{ + (*GetTodoListResponse)(nil), // 0: todolist.v1.GetTodoListResponse + (*TodoList)(nil), // 1: todolist.v1.TodoList +} +var file_todolist_v1_get_todo_list_response_proto_depIdxs = []int32{ + 1, // 0: todolist.v1.GetTodoListResponse.todo_list:type_name -> todolist.v1.TodoList + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_todolist_v1_get_todo_list_response_proto_init() } +func file_todolist_v1_get_todo_list_response_proto_init() { + if File_todolist_v1_get_todo_list_response_proto != nil { + return + } + file_todolist_v1_todo_list_proto_init() + if !protoimpl.UnsafeEnabled { + file_todolist_v1_get_todo_list_response_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTodoListResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_get_todo_list_response_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_get_todo_list_response_proto_goTypes, + DependencyIndexes: file_todolist_v1_get_todo_list_response_proto_depIdxs, + MessageInfos: file_todolist_v1_get_todo_list_response_proto_msgTypes, + }.Build() + File_todolist_v1_get_todo_list_response_proto = out.File + file_todolist_v1_get_todo_list_response_proto_rawDesc = nil + file_todolist_v1_get_todo_list_response_proto_goTypes = nil + file_todolist_v1_get_todo_list_response_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go b/examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go new file mode 100644 index 00000000..a5e5a73e --- /dev/null +++ b/examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/mark_todo_item_as_done_request.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// MarkTodoItemAsDoneRequest marks an item in a TodoList as completed. +type MarkTodoItemAsDoneRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list that owns the item. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // UUID of the item to mark as done. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` +} + +func (x *MarkTodoItemAsDoneRequest) Reset() { + *x = MarkTodoItemAsDoneRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MarkTodoItemAsDoneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkTodoItemAsDoneRequest) ProtoMessage() {} + +func (x *MarkTodoItemAsDoneRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MarkTodoItemAsDoneRequest.ProtoReflect.Descriptor instead. +func (*MarkTodoItemAsDoneRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescGZIP(), []int{0} +} + +func (x *MarkTodoItemAsDoneRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *MarkTodoItemAsDoneRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +var File_todolist_v1_mark_todo_item_as_done_request_proto protoreflect.FileDescriptor + +var file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc = []byte{ + 0x0a, 0x30, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, + 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x73, 0x5f, + 0x64, 0x6f, 0x6e, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, + 0x5f, 0x0a, 0x19, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, + 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, + 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, + 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, + 0x42, 0xd4, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x42, 0x1e, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, + 0x65, 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, + 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, + 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, + 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, + 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, + 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescOnce sync.Once + file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData = file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc +) + +func file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescGZIP() []byte { + file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescOnce.Do(func() { + file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData) + }) + return file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData +} + +var file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_mark_todo_item_as_done_request_proto_goTypes = []interface{}{ + (*MarkTodoItemAsDoneRequest)(nil), // 0: todolist.v1.MarkTodoItemAsDoneRequest +} +var file_todolist_v1_mark_todo_item_as_done_request_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_todolist_v1_mark_todo_item_as_done_request_proto_init() } +func file_todolist_v1_mark_todo_item_as_done_request_proto_init() { + if File_todolist_v1_mark_todo_item_as_done_request_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MarkTodoItemAsDoneRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_mark_todo_item_as_done_request_proto_goTypes, + DependencyIndexes: file_todolist_v1_mark_todo_item_as_done_request_proto_depIdxs, + MessageInfos: file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes, + }.Build() + File_todolist_v1_mark_todo_item_as_done_request_proto = out.File + file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc = nil + file_todolist_v1_mark_todo_item_as_done_request_proto_goTypes = nil + file_todolist_v1_mark_todo_item_as_done_request_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go b/examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go new file mode 100644 index 00000000..b2600e9d --- /dev/null +++ b/examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go @@ -0,0 +1,173 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/mark_todo_item_as_pending_request.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// MarkTodoItemAsPendingRequest marks an item in a TodoList as pending +// (i.e., undoes a previous "mark as done"). +type MarkTodoItemAsPendingRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list that owns the item. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // UUID of the item to mark as pending. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` +} + +func (x *MarkTodoItemAsPendingRequest) Reset() { + *x = MarkTodoItemAsPendingRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MarkTodoItemAsPendingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkTodoItemAsPendingRequest) ProtoMessage() {} + +func (x *MarkTodoItemAsPendingRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MarkTodoItemAsPendingRequest.ProtoReflect.Descriptor instead. +func (*MarkTodoItemAsPendingRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescGZIP(), []int{0} +} + +func (x *MarkTodoItemAsPendingRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *MarkTodoItemAsPendingRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +var File_todolist_v1_mark_todo_item_as_pending_request_proto protoreflect.FileDescriptor + +var file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc = []byte{ + 0x0a, 0x33, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, + 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x73, 0x5f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x22, 0x62, 0x0a, 0x1c, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, + 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, + 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, + 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x42, 0xd7, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x21, 0x4d, 0x61, 0x72, 0x6b, + 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, + 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, + 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescOnce sync.Once + file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData = file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc +) + +func file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescGZIP() []byte { + file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescOnce.Do(func() { + file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData) + }) + return file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData +} + +var file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_mark_todo_item_as_pending_request_proto_goTypes = []interface{}{ + (*MarkTodoItemAsPendingRequest)(nil), // 0: todolist.v1.MarkTodoItemAsPendingRequest +} +var file_todolist_v1_mark_todo_item_as_pending_request_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_todolist_v1_mark_todo_item_as_pending_request_proto_init() } +func file_todolist_v1_mark_todo_item_as_pending_request_proto_init() { + if File_todolist_v1_mark_todo_item_as_pending_request_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MarkTodoItemAsPendingRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_mark_todo_item_as_pending_request_proto_goTypes, + DependencyIndexes: file_todolist_v1_mark_todo_item_as_pending_request_proto_depIdxs, + MessageInfos: file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes, + }.Build() + File_todolist_v1_mark_todo_item_as_pending_request_proto = out.File + file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc = nil + file_todolist_v1_mark_todo_item_as_pending_request_proto_goTypes = nil + file_todolist_v1_mark_todo_item_as_pending_request_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/todo_item.pb.go b/examples/todolist/gen/todolist/v1/todo_item.pb.go new file mode 100644 index 00000000..87641f1e --- /dev/null +++ b/examples/todolist/gen/todolist/v1/todo_item.pb.go @@ -0,0 +1,220 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/todo_item.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// TodoItem is a single entry in a TodoList. +type TodoItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Unique identifier (UUID) for this item. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Short title of the item. + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + // Free-form description of the item. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // Whether the item is completed. + Completed bool `protobuf:"varint,4,opt,name=completed,proto3" json:"completed,omitempty"` + // Optional due date; zero-valued if not set. + DueDate *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=due_date,json=dueDate,proto3" json:"due_date,omitempty"` + // When the item was added to its list. + CreationTime *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` +} + +func (x *TodoItem) Reset() { + *x = TodoItem{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_item_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TodoItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TodoItem) ProtoMessage() {} + +func (x *TodoItem) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_item_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TodoItem.ProtoReflect.Descriptor instead. +func (*TodoItem) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_item_proto_rawDescGZIP(), []int{0} +} + +func (x *TodoItem) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *TodoItem) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *TodoItem) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *TodoItem) GetCompleted() bool { + if x != nil { + return x.Completed + } + return false +} + +func (x *TodoItem) GetDueDate() *timestamppb.Timestamp { + if x != nil { + return x.DueDate + } + return nil +} + +func (x *TodoItem) GetCreationTime() *timestamppb.Timestamp { + if x != nil { + return x.CreationTime + } + return nil +} + +var File_todolist_v1_todo_item_proto protoreflect.FileDescriptor + +var file_todolist_v1_todo_item_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, + 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe8, 0x01, 0x0a, 0x08, + 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x35, + 0x0a, 0x08, 0x64, 0x75, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x75, + 0x65, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x42, 0xc3, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x54, 0x6f, 0x64, 0x6f, + 0x49, 0x74, 0x65, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, + 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, + 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, + 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_todo_item_proto_rawDescOnce sync.Once + file_todolist_v1_todo_item_proto_rawDescData = file_todolist_v1_todo_item_proto_rawDesc +) + +func file_todolist_v1_todo_item_proto_rawDescGZIP() []byte { + file_todolist_v1_todo_item_proto_rawDescOnce.Do(func() { + file_todolist_v1_todo_item_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_todo_item_proto_rawDescData) + }) + return file_todolist_v1_todo_item_proto_rawDescData +} + +var file_todolist_v1_todo_item_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_todo_item_proto_goTypes = []interface{}{ + (*TodoItem)(nil), // 0: todolist.v1.TodoItem + (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp +} +var file_todolist_v1_todo_item_proto_depIdxs = []int32{ + 1, // 0: todolist.v1.TodoItem.due_date:type_name -> google.protobuf.Timestamp + 1, // 1: todolist.v1.TodoItem.creation_time:type_name -> google.protobuf.Timestamp + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_todolist_v1_todo_item_proto_init() } +func file_todolist_v1_todo_item_proto_init() { + if File_todolist_v1_todo_item_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_todolist_v1_todo_item_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TodoItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_todo_item_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_todo_item_proto_goTypes, + DependencyIndexes: file_todolist_v1_todo_item_proto_depIdxs, + MessageInfos: file_todolist_v1_todo_item_proto_msgTypes, + }.Build() + File_todolist_v1_todo_item_proto = out.File + file_todolist_v1_todo_item_proto_rawDesc = nil + file_todolist_v1_todo_item_proto_goTypes = nil + file_todolist_v1_todo_item_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/todo_list.pb.go b/examples/todolist/gen/todolist/v1/todo_list.pb.go new file mode 100644 index 00000000..593b5597 --- /dev/null +++ b/examples/todolist/gen/todolist/v1/todo_list.pb.go @@ -0,0 +1,211 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/todo_list.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// TodoList is a list of TodoItems belonging to an owner. +type TodoList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Unique identifier (UUID) for this list. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // Display title of the list. + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + // Owner identifier (application-defined, typically a username). + Owner string `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` + // When the list was created. + CreationTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` + // Items currently in the list, in insertion order. + Items []*TodoItem `protobuf:"bytes,5,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *TodoList) Reset() { + *x = TodoList{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TodoList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TodoList) ProtoMessage() {} + +func (x *TodoList) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TodoList.ProtoReflect.Descriptor instead. +func (*TodoList) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_proto_rawDescGZIP(), []int{0} +} + +func (x *TodoList) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *TodoList) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *TodoList) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +func (x *TodoList) GetCreationTime() *timestamppb.Timestamp { + if x != nil { + return x.CreationTime + } + return nil +} + +func (x *TodoList) GetItems() []*TodoItem { + if x != nil { + return x.Items + } + return nil +} + +var File_todolist_v1_todo_list_proto protoreflect.FileDescriptor + +var file_todolist_v1_todo_list_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, + 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x74, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, + 0x65, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb4, 0x01, 0x0a, 0x08, 0x54, 0x6f, 0x64, + 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, + 0x72, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x42, + 0xc3, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, + 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, + 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, + 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, + 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, + 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_todolist_v1_todo_list_proto_rawDescOnce sync.Once + file_todolist_v1_todo_list_proto_rawDescData = file_todolist_v1_todo_list_proto_rawDesc +) + +func file_todolist_v1_todo_list_proto_rawDescGZIP() []byte { + file_todolist_v1_todo_list_proto_rawDescOnce.Do(func() { + file_todolist_v1_todo_list_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_todo_list_proto_rawDescData) + }) + return file_todolist_v1_todo_list_proto_rawDescData +} + +var file_todolist_v1_todo_list_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_todolist_v1_todo_list_proto_goTypes = []interface{}{ + (*TodoList)(nil), // 0: todolist.v1.TodoList + (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp + (*TodoItem)(nil), // 2: todolist.v1.TodoItem +} +var file_todolist_v1_todo_list_proto_depIdxs = []int32{ + 1, // 0: todolist.v1.TodoList.creation_time:type_name -> google.protobuf.Timestamp + 2, // 1: todolist.v1.TodoList.items:type_name -> todolist.v1.TodoItem + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_todolist_v1_todo_list_proto_init() } +func file_todolist_v1_todo_list_proto_init() { + if File_todolist_v1_todo_list_proto != nil { + return + } + file_todolist_v1_todo_item_proto_init() + if !protoimpl.UnsafeEnabled { + file_todolist_v1_todo_list_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TodoList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_todo_list_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_todolist_v1_todo_list_proto_goTypes, + DependencyIndexes: file_todolist_v1_todo_list_proto_depIdxs, + MessageInfos: file_todolist_v1_todo_list_proto_msgTypes, + }.Build() + File_todolist_v1_todo_list_proto = out.File + file_todolist_v1_todo_list_proto_rawDesc = nil + file_todolist_v1_todo_list_proto_goTypes = nil + file_todolist_v1_todo_list_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/todo_list_service.pb.go b/examples/todolist/gen/todolist/v1/todo_list_service.pb.go new file mode 100644 index 00000000..018cf8ae --- /dev/null +++ b/examples/todolist/gen/todolist/v1/todo_list_service.pb.go @@ -0,0 +1,157 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: todolist/v1/todo_list_service.proto + +package todolistv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var File_todolist_v1_todo_list_service_proto protoreflect.FileDescriptor + +var file_todolist_v1_todo_list_service_proto_rawDesc = []byte{ + 0x0a, 0x23, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, + 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, + 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, + 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, + 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, + 0x65, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, + 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, + 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, + 0x2f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, + 0x61, 0x73, 0x5f, 0x64, 0x6f, 0x6e, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x33, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, + 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, + 0x6d, 0x5f, 0x61, 0x73, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xf9, 0x03, 0x0a, 0x0f, 0x54, + 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, + 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x22, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x0b, + 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, + 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, + 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, + 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x2e, + 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, + 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x54, 0x0a, 0x12, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, + 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x12, 0x26, 0x2e, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x54, + 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5a, 0x0a, 0x15, + 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, + 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x22, 0x2e, 0x74, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, + 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0xca, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x54, 0x6f, 0x64, 0x6f, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, + 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, + 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, + 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, + 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, + 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, + 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_todolist_v1_todo_list_service_proto_goTypes = []interface{}{ + (*CreateTodoListRequest)(nil), // 0: todolist.v1.CreateTodoListRequest + (*GetTodoListRequest)(nil), // 1: todolist.v1.GetTodoListRequest + (*AddTodoItemRequest)(nil), // 2: todolist.v1.AddTodoItemRequest + (*MarkTodoItemAsDoneRequest)(nil), // 3: todolist.v1.MarkTodoItemAsDoneRequest + (*MarkTodoItemAsPendingRequest)(nil), // 4: todolist.v1.MarkTodoItemAsPendingRequest + (*DeleteTodoItemRequest)(nil), // 5: todolist.v1.DeleteTodoItemRequest + (*emptypb.Empty)(nil), // 6: google.protobuf.Empty + (*GetTodoListResponse)(nil), // 7: todolist.v1.GetTodoListResponse +} +var file_todolist_v1_todo_list_service_proto_depIdxs = []int32{ + 0, // 0: todolist.v1.TodoListService.CreateTodoList:input_type -> todolist.v1.CreateTodoListRequest + 1, // 1: todolist.v1.TodoListService.GetTodoList:input_type -> todolist.v1.GetTodoListRequest + 2, // 2: todolist.v1.TodoListService.AddTodoItem:input_type -> todolist.v1.AddTodoItemRequest + 3, // 3: todolist.v1.TodoListService.MarkTodoItemAsDone:input_type -> todolist.v1.MarkTodoItemAsDoneRequest + 4, // 4: todolist.v1.TodoListService.MarkTodoItemAsPending:input_type -> todolist.v1.MarkTodoItemAsPendingRequest + 5, // 5: todolist.v1.TodoListService.DeleteTodoItem:input_type -> todolist.v1.DeleteTodoItemRequest + 6, // 6: todolist.v1.TodoListService.CreateTodoList:output_type -> google.protobuf.Empty + 7, // 7: todolist.v1.TodoListService.GetTodoList:output_type -> todolist.v1.GetTodoListResponse + 6, // 8: todolist.v1.TodoListService.AddTodoItem:output_type -> google.protobuf.Empty + 6, // 9: todolist.v1.TodoListService.MarkTodoItemAsDone:output_type -> google.protobuf.Empty + 6, // 10: todolist.v1.TodoListService.MarkTodoItemAsPending:output_type -> google.protobuf.Empty + 6, // 11: todolist.v1.TodoListService.DeleteTodoItem:output_type -> google.protobuf.Empty + 6, // [6:12] is the sub-list for method output_type + 0, // [0:6] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_todolist_v1_todo_list_service_proto_init() } +func file_todolist_v1_todo_list_service_proto_init() { + if File_todolist_v1_todo_list_service_proto != nil { + return + } + file_todolist_v1_add_todo_item_request_proto_init() + file_todolist_v1_create_todo_list_request_proto_init() + file_todolist_v1_delete_todo_item_request_proto_init() + file_todolist_v1_get_todo_list_request_proto_init() + file_todolist_v1_get_todo_list_response_proto_init() + file_todolist_v1_mark_todo_item_as_done_request_proto_init() + file_todolist_v1_mark_todo_item_as_pending_request_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_todolist_v1_todo_list_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_todolist_v1_todo_list_service_proto_goTypes, + DependencyIndexes: file_todolist_v1_todo_list_service_proto_depIdxs, + }.Build() + File_todolist_v1_todo_list_service_proto = out.File + file_todolist_v1_todo_list_service_proto_rawDesc = nil + file_todolist_v1_todo_list_service_proto_goTypes = nil + file_todolist_v1_todo_list_service_proto_depIdxs = nil +} diff --git a/examples/todolist/gen/todolist/v1/todolistv1connect/todo_list_service.connect.go b/examples/todolist/gen/todolist/v1/todolistv1connect/todo_list_service.connect.go new file mode 100644 index 00000000..9dd71bfb --- /dev/null +++ b/examples/todolist/gen/todolist/v1/todolistv1connect/todo_list_service.connect.go @@ -0,0 +1,253 @@ +// Code generated by protoc-gen-connect-go. DO NOT EDIT. +// +// Source: todolist/v1/todo_list_service.proto + +package todolistv1connect + +import ( + connect "connectrpc.com/connect" + context "context" + errors "errors" + v1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" + emptypb "google.golang.org/protobuf/types/known/emptypb" + http "net/http" + strings "strings" +) + +// This is a compile-time assertion to ensure that this generated file and the connect package are +// compatible. If you get a compiler error that this constant is not defined, this code was +// generated with a version of connect newer than the one compiled into your binary. You can fix the +// problem by either regenerating this code with an older version of connect or updating the connect +// version compiled into your binary. +const _ = connect.IsAtLeastVersion0_1_0 + +const ( + // TodoListServiceName is the fully-qualified name of the TodoListService service. + TodoListServiceName = "todolist.v1.TodoListService" +) + +// These constants are the fully-qualified names of the RPCs defined in this package. They're +// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route. +// +// Note that these are different from the fully-qualified method names used by +// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to +// reflection-formatted method names, remove the leading slash and convert the remaining slash to a +// period. +const ( + // TodoListServiceCreateTodoListProcedure is the fully-qualified name of the TodoListService's + // CreateTodoList RPC. + TodoListServiceCreateTodoListProcedure = "/todolist.v1.TodoListService/CreateTodoList" + // TodoListServiceGetTodoListProcedure is the fully-qualified name of the TodoListService's + // GetTodoList RPC. + TodoListServiceGetTodoListProcedure = "/todolist.v1.TodoListService/GetTodoList" + // TodoListServiceAddTodoItemProcedure is the fully-qualified name of the TodoListService's + // AddTodoItem RPC. + TodoListServiceAddTodoItemProcedure = "/todolist.v1.TodoListService/AddTodoItem" + // TodoListServiceMarkTodoItemAsDoneProcedure is the fully-qualified name of the TodoListService's + // MarkTodoItemAsDone RPC. + TodoListServiceMarkTodoItemAsDoneProcedure = "/todolist.v1.TodoListService/MarkTodoItemAsDone" + // TodoListServiceMarkTodoItemAsPendingProcedure is the fully-qualified name of the + // TodoListService's MarkTodoItemAsPending RPC. + TodoListServiceMarkTodoItemAsPendingProcedure = "/todolist.v1.TodoListService/MarkTodoItemAsPending" + // TodoListServiceDeleteTodoItemProcedure is the fully-qualified name of the TodoListService's + // DeleteTodoItem RPC. + TodoListServiceDeleteTodoItemProcedure = "/todolist.v1.TodoListService/DeleteTodoItem" +) + +// TodoListServiceClient is a client for the todolist.v1.TodoListService service. +type TodoListServiceClient interface { + // CreateTodoList creates a new TodoList with a client-generated ID. + CreateTodoList(context.Context, *connect.Request[v1.CreateTodoListRequest]) (*connect.Response[emptypb.Empty], error) + // GetTodoList fetches an existing TodoList by ID. + GetTodoList(context.Context, *connect.Request[v1.GetTodoListRequest]) (*connect.Response[v1.GetTodoListResponse], error) + // AddTodoItem appends a new item to an existing TodoList. + AddTodoItem(context.Context, *connect.Request[v1.AddTodoItemRequest]) (*connect.Response[emptypb.Empty], error) + // MarkTodoItemAsDone marks an existing item as completed. + MarkTodoItemAsDone(context.Context, *connect.Request[v1.MarkTodoItemAsDoneRequest]) (*connect.Response[emptypb.Empty], error) + // MarkTodoItemAsPending reverts a previous "mark as done". + MarkTodoItemAsPending(context.Context, *connect.Request[v1.MarkTodoItemAsPendingRequest]) (*connect.Response[emptypb.Empty], error) + // DeleteTodoItem removes an item from a TodoList. + DeleteTodoItem(context.Context, *connect.Request[v1.DeleteTodoItemRequest]) (*connect.Response[emptypb.Empty], error) +} + +// NewTodoListServiceClient constructs a client for the todolist.v1.TodoListService service. By +// default, it uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, +// and sends uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the +// connect.WithGRPC() or connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewTodoListServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) TodoListServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + return &todoListServiceClient{ + createTodoList: connect.NewClient[v1.CreateTodoListRequest, emptypb.Empty]( + httpClient, + baseURL+TodoListServiceCreateTodoListProcedure, + opts..., + ), + getTodoList: connect.NewClient[v1.GetTodoListRequest, v1.GetTodoListResponse]( + httpClient, + baseURL+TodoListServiceGetTodoListProcedure, + opts..., + ), + addTodoItem: connect.NewClient[v1.AddTodoItemRequest, emptypb.Empty]( + httpClient, + baseURL+TodoListServiceAddTodoItemProcedure, + opts..., + ), + markTodoItemAsDone: connect.NewClient[v1.MarkTodoItemAsDoneRequest, emptypb.Empty]( + httpClient, + baseURL+TodoListServiceMarkTodoItemAsDoneProcedure, + opts..., + ), + markTodoItemAsPending: connect.NewClient[v1.MarkTodoItemAsPendingRequest, emptypb.Empty]( + httpClient, + baseURL+TodoListServiceMarkTodoItemAsPendingProcedure, + opts..., + ), + deleteTodoItem: connect.NewClient[v1.DeleteTodoItemRequest, emptypb.Empty]( + httpClient, + baseURL+TodoListServiceDeleteTodoItemProcedure, + opts..., + ), + } +} + +// todoListServiceClient implements TodoListServiceClient. +type todoListServiceClient struct { + createTodoList *connect.Client[v1.CreateTodoListRequest, emptypb.Empty] + getTodoList *connect.Client[v1.GetTodoListRequest, v1.GetTodoListResponse] + addTodoItem *connect.Client[v1.AddTodoItemRequest, emptypb.Empty] + markTodoItemAsDone *connect.Client[v1.MarkTodoItemAsDoneRequest, emptypb.Empty] + markTodoItemAsPending *connect.Client[v1.MarkTodoItemAsPendingRequest, emptypb.Empty] + deleteTodoItem *connect.Client[v1.DeleteTodoItemRequest, emptypb.Empty] +} + +// CreateTodoList calls todolist.v1.TodoListService.CreateTodoList. +func (c *todoListServiceClient) CreateTodoList(ctx context.Context, req *connect.Request[v1.CreateTodoListRequest]) (*connect.Response[emptypb.Empty], error) { + return c.createTodoList.CallUnary(ctx, req) +} + +// GetTodoList calls todolist.v1.TodoListService.GetTodoList. +func (c *todoListServiceClient) GetTodoList(ctx context.Context, req *connect.Request[v1.GetTodoListRequest]) (*connect.Response[v1.GetTodoListResponse], error) { + return c.getTodoList.CallUnary(ctx, req) +} + +// AddTodoItem calls todolist.v1.TodoListService.AddTodoItem. +func (c *todoListServiceClient) AddTodoItem(ctx context.Context, req *connect.Request[v1.AddTodoItemRequest]) (*connect.Response[emptypb.Empty], error) { + return c.addTodoItem.CallUnary(ctx, req) +} + +// MarkTodoItemAsDone calls todolist.v1.TodoListService.MarkTodoItemAsDone. +func (c *todoListServiceClient) MarkTodoItemAsDone(ctx context.Context, req *connect.Request[v1.MarkTodoItemAsDoneRequest]) (*connect.Response[emptypb.Empty], error) { + return c.markTodoItemAsDone.CallUnary(ctx, req) +} + +// MarkTodoItemAsPending calls todolist.v1.TodoListService.MarkTodoItemAsPending. +func (c *todoListServiceClient) MarkTodoItemAsPending(ctx context.Context, req *connect.Request[v1.MarkTodoItemAsPendingRequest]) (*connect.Response[emptypb.Empty], error) { + return c.markTodoItemAsPending.CallUnary(ctx, req) +} + +// DeleteTodoItem calls todolist.v1.TodoListService.DeleteTodoItem. +func (c *todoListServiceClient) DeleteTodoItem(ctx context.Context, req *connect.Request[v1.DeleteTodoItemRequest]) (*connect.Response[emptypb.Empty], error) { + return c.deleteTodoItem.CallUnary(ctx, req) +} + +// TodoListServiceHandler is an implementation of the todolist.v1.TodoListService service. +type TodoListServiceHandler interface { + // CreateTodoList creates a new TodoList with a client-generated ID. + CreateTodoList(context.Context, *connect.Request[v1.CreateTodoListRequest]) (*connect.Response[emptypb.Empty], error) + // GetTodoList fetches an existing TodoList by ID. + GetTodoList(context.Context, *connect.Request[v1.GetTodoListRequest]) (*connect.Response[v1.GetTodoListResponse], error) + // AddTodoItem appends a new item to an existing TodoList. + AddTodoItem(context.Context, *connect.Request[v1.AddTodoItemRequest]) (*connect.Response[emptypb.Empty], error) + // MarkTodoItemAsDone marks an existing item as completed. + MarkTodoItemAsDone(context.Context, *connect.Request[v1.MarkTodoItemAsDoneRequest]) (*connect.Response[emptypb.Empty], error) + // MarkTodoItemAsPending reverts a previous "mark as done". + MarkTodoItemAsPending(context.Context, *connect.Request[v1.MarkTodoItemAsPendingRequest]) (*connect.Response[emptypb.Empty], error) + // DeleteTodoItem removes an item from a TodoList. + DeleteTodoItem(context.Context, *connect.Request[v1.DeleteTodoItemRequest]) (*connect.Response[emptypb.Empty], error) +} + +// NewTodoListServiceHandler builds an HTTP handler from the service implementation. It returns the +// path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewTodoListServiceHandler(svc TodoListServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + todoListServiceCreateTodoListHandler := connect.NewUnaryHandler( + TodoListServiceCreateTodoListProcedure, + svc.CreateTodoList, + opts..., + ) + todoListServiceGetTodoListHandler := connect.NewUnaryHandler( + TodoListServiceGetTodoListProcedure, + svc.GetTodoList, + opts..., + ) + todoListServiceAddTodoItemHandler := connect.NewUnaryHandler( + TodoListServiceAddTodoItemProcedure, + svc.AddTodoItem, + opts..., + ) + todoListServiceMarkTodoItemAsDoneHandler := connect.NewUnaryHandler( + TodoListServiceMarkTodoItemAsDoneProcedure, + svc.MarkTodoItemAsDone, + opts..., + ) + todoListServiceMarkTodoItemAsPendingHandler := connect.NewUnaryHandler( + TodoListServiceMarkTodoItemAsPendingProcedure, + svc.MarkTodoItemAsPending, + opts..., + ) + todoListServiceDeleteTodoItemHandler := connect.NewUnaryHandler( + TodoListServiceDeleteTodoItemProcedure, + svc.DeleteTodoItem, + opts..., + ) + return "/todolist.v1.TodoListService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case TodoListServiceCreateTodoListProcedure: + todoListServiceCreateTodoListHandler.ServeHTTP(w, r) + case TodoListServiceGetTodoListProcedure: + todoListServiceGetTodoListHandler.ServeHTTP(w, r) + case TodoListServiceAddTodoItemProcedure: + todoListServiceAddTodoItemHandler.ServeHTTP(w, r) + case TodoListServiceMarkTodoItemAsDoneProcedure: + todoListServiceMarkTodoItemAsDoneHandler.ServeHTTP(w, r) + case TodoListServiceMarkTodoItemAsPendingProcedure: + todoListServiceMarkTodoItemAsPendingHandler.ServeHTTP(w, r) + case TodoListServiceDeleteTodoItemProcedure: + todoListServiceDeleteTodoItemHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedTodoListServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedTodoListServiceHandler struct{} + +func (UnimplementedTodoListServiceHandler) CreateTodoList(context.Context, *connect.Request[v1.CreateTodoListRequest]) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("todolist.v1.TodoListService.CreateTodoList is not implemented")) +} + +func (UnimplementedTodoListServiceHandler) GetTodoList(context.Context, *connect.Request[v1.GetTodoListRequest]) (*connect.Response[v1.GetTodoListResponse], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("todolist.v1.TodoListService.GetTodoList is not implemented")) +} + +func (UnimplementedTodoListServiceHandler) AddTodoItem(context.Context, *connect.Request[v1.AddTodoItemRequest]) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("todolist.v1.TodoListService.AddTodoItem is not implemented")) +} + +func (UnimplementedTodoListServiceHandler) MarkTodoItemAsDone(context.Context, *connect.Request[v1.MarkTodoItemAsDoneRequest]) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("todolist.v1.TodoListService.MarkTodoItemAsDone is not implemented")) +} + +func (UnimplementedTodoListServiceHandler) MarkTodoItemAsPending(context.Context, *connect.Request[v1.MarkTodoItemAsPendingRequest]) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("todolist.v1.TodoListService.MarkTodoItemAsPending is not implemented")) +} + +func (UnimplementedTodoListServiceHandler) DeleteTodoItem(context.Context, *connect.Request[v1.DeleteTodoItemRequest]) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("todolist.v1.TodoListService.DeleteTodoItem is not implemented")) +} From 719c9d4cc58cd2655322ce4fb7c4b6898806654c Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:53:09 +0200 Subject: [PATCH 03/19] feat(examples): port todolist domain aggregate TodoList aggregate root with: - domain events (WasCreated, ItemWasAdded, ItemMarkedAsDone, ItemMarkedAsPending, ItemWasDeleted); - Item child entity rehydrated via nested Apply; - Create factory + AddItem / MarkItemAsDone / MarkItemAsPending / DeleteItem methods, each emitting the corresponding event via aggregate.RecordThat; - repository.go with type aliases for aggregate.{Getter,Saver,Repository}. Imports use the library's current layout (aggregate, event, version), not the legacy core/ prefix. Test uses aggregate.Scenario(typ) to cover the happy path end-to-end (create list -> add item -> mark done -> delete). --- .../internal/domain/todolist/event.go | 54 ++++ .../todolist/internal/domain/todolist/item.go | 54 ++++ .../internal/domain/todolist/repository.go | 14 + .../internal/domain/todolist/todolist.go | 245 ++++++++++++++++++ .../internal/domain/todolist/todolist_test.go | 59 +++++ 5 files changed, 426 insertions(+) create mode 100644 examples/todolist/internal/domain/todolist/event.go create mode 100644 examples/todolist/internal/domain/todolist/item.go create mode 100644 examples/todolist/internal/domain/todolist/repository.go create mode 100644 examples/todolist/internal/domain/todolist/todolist.go create mode 100644 examples/todolist/internal/domain/todolist/todolist_test.go diff --git a/examples/todolist/internal/domain/todolist/event.go b/examples/todolist/internal/domain/todolist/event.go new file mode 100644 index 00000000..59d5e70a --- /dev/null +++ b/examples/todolist/internal/domain/todolist/event.go @@ -0,0 +1,54 @@ +package todolist + +import "time" + +// WasCreated is the Domain Event issued when a new TodoList gets created. +type WasCreated struct { + ID ID + Title string + Owner string + CreationTime time.Time +} + +// Name implements message.Message. +func (WasCreated) Name() string { return "TodoListWasCreated" } + +// ItemWasAdded is the Domain Event issued when a new Item gets added +// to an existing TodoList. +type ItemWasAdded struct { + ID ItemID + Title string + Description string + DueDate time.Time + CreationTime time.Time +} + +// Name implements message.Message. +func (ItemWasAdded) Name() string { return "TodoListItemWasAdded" } + +// ItemMarkedAsDone is the Domain Event issued when an existing Item +// in a TodoList gets marked as "done". +type ItemMarkedAsDone struct { + ID ItemID +} + +// Name implements message.Message. +func (ItemMarkedAsDone) Name() string { return "TodoListItemMarkedAsDone" } + +// ItemMarkedAsPending is the Domain Event issued when an existing Item +// in a TodoList gets marked as "pending". +type ItemMarkedAsPending struct { + ID ItemID +} + +// Name implements message.Message. +func (ItemMarkedAsPending) Name() string { return "TodoListItemMarkedAsPending" } + +// ItemWasDeleted is the Domain Event issued when an existing Item +// gets deleted from a TodoList. +type ItemWasDeleted struct { + ID ItemID +} + +// Name implements message.Message. +func (ItemWasDeleted) Name() string { return "TodoListItemWasDeleted" } diff --git a/examples/todolist/internal/domain/todolist/item.go b/examples/todolist/internal/domain/todolist/item.go new file mode 100644 index 00000000..d531bd63 --- /dev/null +++ b/examples/todolist/internal/domain/todolist/item.go @@ -0,0 +1,54 @@ +package todolist + +import ( + "fmt" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/event" +) + +// ItemID is the unique identifier type for a Todo Item. +type ItemID uuid.UUID + +// String returns the canonical UUID string representation of the ItemID. +func (id ItemID) String() string { return uuid.UUID(id).String() } + +// Item represents a Todo Item. +// Items are managed by a TodoList aggregate root instance. +type Item struct { + aggregate.BaseRoot + + ID ItemID + Title string + Description string + Completed bool + DueDate time.Time + CreationTime time.Time +} + +// Apply implements aggregate.Aggregate. +func (item *Item) Apply(evt event.Event) error { + switch evt := evt.(type) { + case ItemWasAdded: + item.ID = evt.ID + item.Title = evt.Title + item.Description = evt.Description + item.Completed = false + item.DueDate = evt.DueDate + item.CreationTime = evt.CreationTime + + case ItemMarkedAsDone: + item.Completed = true + + case ItemMarkedAsPending: + item.Completed = false + + default: + return fmt.Errorf("todolist.Item.Apply: unsupported event, %T", evt) + } + + return nil +} diff --git a/examples/todolist/internal/domain/todolist/repository.go b/examples/todolist/internal/domain/todolist/repository.go new file mode 100644 index 00000000..5fd33645 --- /dev/null +++ b/examples/todolist/internal/domain/todolist/repository.go @@ -0,0 +1,14 @@ +package todolist + +import "github.com/get-eventually/go-eventually/aggregate" + +type ( + // Getter is a helper type for an aggregate.Getter interface for a TodoList. + Getter = aggregate.Getter[ID, *TodoList] + + // Saver is a helper type for an aggregate.Saver interface for a TodoList. + Saver = aggregate.Saver[ID, *TodoList] + + // Repository is a helper type for an aggregate.Repository interface for a TodoList. + Repository = aggregate.Repository[ID, *TodoList] +) diff --git a/examples/todolist/internal/domain/todolist/todolist.go b/examples/todolist/internal/domain/todolist/todolist.go new file mode 100644 index 00000000..18188e6f --- /dev/null +++ b/examples/todolist/internal/domain/todolist/todolist.go @@ -0,0 +1,245 @@ +// Package todolist contains the domain types and implementations +// for the TodoList Aggregate Root. +package todolist + +import ( + "errors" + "fmt" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/event" +) + +// ID is the unique identifier for a TodoList. +type ID uuid.UUID + +// String returns the canonical UUID string representation of the ID. +func (id ID) String() string { return uuid.UUID(id).String() } + +// Type represents the Aggregate Root type for usage with go-eventually utilities. +var Type = aggregate.Type[ID, *TodoList]{ + Name: "TodoList", + Factory: func() *TodoList { return new(TodoList) }, +} + +// TodoList is a list of different Todo items, that belongs to a specific owner. +type TodoList struct { + aggregate.BaseRoot + + ID ID + Title string + Owner string + CreationTime time.Time + Items []*Item +} + +// AggregateID implements aggregate.Root. +func (tl *TodoList) AggregateID() ID { return tl.ID } + +func (tl *TodoList) itemByID(id ItemID) (*Item, bool) { + for _, item := range tl.Items { + if item.ID == id { + return item, true + } + } + + return nil, false +} + +func (tl *TodoList) applyItemEvent(id ItemID, evt event.Event) error { + item, ok := tl.itemByID(id) + if !ok { + return errors.New("todolist.TodoList.Apply: item not found") + } + + if err := item.Apply(evt); err != nil { + return fmt.Errorf("todolist.TodoList.Apply: failed to apply item event, %w", err) + } + + return nil +} + +// Apply implements aggregate.Aggregate. +func (tl *TodoList) Apply(evt event.Event) error { + switch evt := evt.(type) { + case WasCreated: + tl.ID = evt.ID + tl.Title = evt.Title + tl.Owner = evt.Owner + tl.CreationTime = evt.CreationTime + + case ItemWasAdded: + item := &Item{} //nolint:exhaustruct // Applied below. + if err := item.Apply(evt); err != nil { + return fmt.Errorf("todolist.TodoList.Apply: failed to apply item event, %w", err) + } + + tl.Items = append(tl.Items, item) + + case ItemMarkedAsDone: + return tl.applyItemEvent(evt.ID, evt) + + case ItemMarkedAsPending: + return tl.applyItemEvent(evt.ID, evt) + + case ItemWasDeleted: + items := make([]*Item, 0, len(tl.Items)) + + for _, item := range tl.Items { + if item.ID == evt.ID { + continue + } + + items = append(items, item) + } + + tl.Items = items + + default: + return fmt.Errorf("todolist.TodoList.Apply: invalid event, %T", evt) + } + + return nil +} + +// Errors that can be returned by domain commands on a TodoList instance. +var ( + ErrEmptyID = errors.New("todolist.TodoList: empty id provided") + ErrEmptyTitle = errors.New("todolist.TodoList: empty title provided") + ErrNoOwnerSpecified = errors.New("todolist.TodoList: no owner specified") + ErrEmptyItemID = errors.New("todolist.TodoList: empty item id provided") + ErrEmptyItemTitle = errors.New("todolist.TodoList: empty item title provided") + ErrItemAlreadyExists = errors.New("todolist.TodoList: item already exists") + ErrItemNotFound = errors.New("todolist.TodoList: item was not found in list") +) + +// Create creates a new TodoList. +// +// Both id, title and owner are required parameters: when empty, the function +// will return an error. +func Create(id ID, title, owner string, now time.Time) (*TodoList, error) { + wrapErr := func(err error) error { + return fmt.Errorf("todolist.Create: failed to create new TodoList, %w", err) + } + + if uuid.UUID(id) == uuid.Nil { + return nil, wrapErr(ErrEmptyID) + } + + if title == "" { + return nil, wrapErr(ErrEmptyTitle) + } + + if owner == "" { + return nil, wrapErr(ErrNoOwnerSpecified) + } + + var todoList TodoList //nolint:exhaustruct // Fields are populated by WasCreated apply. + + if err := aggregate.RecordThat[ID](&todoList, event.ToEnvelope(WasCreated{ + ID: id, + Title: title, + Owner: owner, + CreationTime: now, + })); err != nil { + return nil, fmt.Errorf("todolist.Create: failed to apply domain event, %w", err) + } + + return &todoList, nil +} + +// AddItem adds a new Todo item to an existing list. +// +// Both id and title cannot be empty: if so, the method will return an error. +// +// Moreover, if the specified id is already being used by another Todo item, +// the method will return ErrItemAlreadyExists. +func (tl *TodoList) AddItem(id ItemID, title, description string, dueDate, now time.Time) error { + wrapErr := func(err error) error { + return fmt.Errorf("todolist.AddItem: failed to add new TodoItem to list, %w", err) + } + + if uuid.UUID(id) == uuid.Nil { + return wrapErr(ErrEmptyItemID) + } + + if title == "" { + return wrapErr(ErrEmptyItemTitle) + } + + if _, ok := tl.itemByID(id); ok { + return wrapErr(ErrItemAlreadyExists) + } + + if err := aggregate.RecordThat[ID](tl, event.ToEnvelope(ItemWasAdded{ + ID: id, + Title: title, + Description: description, + DueDate: dueDate, + CreationTime: now, + })); err != nil { + return fmt.Errorf("todolist.AddItem: failed to apply domain event, %w", err) + } + + return nil +} + +func (tl *TodoList) recordItemEvent(id ItemID, eventFactory func() event.Envelope) error { + if uuid.UUID(id) == uuid.Nil { + return ErrEmptyItemID + } + + if _, ok := tl.itemByID(id); !ok { + return ErrItemNotFound + } + + return aggregate.RecordThat[ID](tl, eventFactory()) +} + +// MarkItemAsDone marks the Todo item with the specified id as "done". +// +// The method returns an error when the id is empty, or it doesn't point +// to an existing Todo item. +func (tl *TodoList) MarkItemAsDone(id ItemID) error { + err := tl.recordItemEvent(id, func() event.Envelope { + return event.ToEnvelope(ItemMarkedAsDone{ID: id}) + }) + if err != nil { + return fmt.Errorf("todolist.MarkItemAsDone: failed to mark item as done, %w", err) + } + + return nil +} + +// MarkItemAsPending marks the Todo item with the specified id as "pending". +// +// The method returns an error when the id is empty, or it doesn't point +// to an existing Todo item. +func (tl *TodoList) MarkItemAsPending(id ItemID) error { + err := tl.recordItemEvent(id, func() event.Envelope { + return event.ToEnvelope(ItemMarkedAsPending{ID: id}) + }) + if err != nil { + return fmt.Errorf("todolist.MarkItemAsPending: failed to mark item as pending, %w", err) + } + + return nil +} + +// DeleteItem deletes the Todo item with the specified id from the TodoList. +// +// The method returns an error when the id is empty, or it doesn't point +// to an existing Todo item. +func (tl *TodoList) DeleteItem(id ItemID) error { + err := tl.recordItemEvent(id, func() event.Envelope { + return event.ToEnvelope(ItemWasDeleted{ID: id}) + }) + if err != nil { + return fmt.Errorf("todolist.DeleteItem: failed to delete item, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/domain/todolist/todolist_test.go b/examples/todolist/internal/domain/todolist/todolist_test.go new file mode 100644 index 00000000..ff466614 --- /dev/null +++ b/examples/todolist/internal/domain/todolist/todolist_test.go @@ -0,0 +1,59 @@ +package todolist_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/event" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" +) + +func TestTodoList(t *testing.T) { + t.Run("it works", func(t *testing.T) { + now := time.Now() + todoListID := todolist.ID(uuid.New()) + todoItemID := todolist.ItemID(uuid.New()) + + aggregate.Scenario(todolist.Type). + When(func() (*todolist.TodoList, error) { + tl, err := todolist.Create(todoListID, "test list", "me", now) + if err != nil { + return nil, err + } + + if err := tl.AddItem(todoItemID, "do something", "", time.Time{}, now); err != nil { + return nil, err + } + + if err := tl.MarkItemAsDone(todoItemID); err != nil { + return nil, err + } + + if err := tl.DeleteItem(todoItemID); err != nil { + return nil, err + } + + return tl, nil + }). + Then(4, event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: "test list", + Owner: "me", + CreationTime: now, + }), event.ToEnvelope(todolist.ItemWasAdded{ + ID: todoItemID, + Title: "do something", + Description: "", + DueDate: time.Time{}, + CreationTime: now, + }), event.ToEnvelope(todolist.ItemMarkedAsDone{ + ID: todoItemID, + }), event.ToEnvelope(todolist.ItemWasDeleted{ + ID: todoItemID, + })). + AssertOn(t) + }) +} From c7bad3db0bdf16c4833f2249d04cd6cd645cdf68 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:54:03 +0200 Subject: [PATCH 04/19] feat(examples): port todolist command handlers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two command handlers: - CreateTodoListHandler — creates a new TodoList via todolist.Create and persists it through the repository. - AddTodoListItemHandler — fetches an existing TodoList, calls AddItem, saves the new version. Both are struct-shaped handlers with a clock function and a repository dependency. Unit tests use command.Scenario[Cmd, Handler] to cover: - create: empty ID / empty title / empty owner / happy path; - add item: list not found / duplicate item / empty title / happy path. Imports target the library's current package layout; no core/ prefix. --- .../internal/command/add_todo_list_item.go | 56 ++++++++ .../command/add_todo_list_item_test.go | 131 ++++++++++++++++++ .../internal/command/create_todolist.go | 44 ++++++ .../internal/command/create_todolist_test.go | 80 +++++++++++ examples/todolist/internal/command/doc.go | 2 + 5 files changed, 313 insertions(+) create mode 100644 examples/todolist/internal/command/add_todo_list_item.go create mode 100644 examples/todolist/internal/command/add_todo_list_item_test.go create mode 100644 examples/todolist/internal/command/create_todolist.go create mode 100644 examples/todolist/internal/command/create_todolist_test.go create mode 100644 examples/todolist/internal/command/doc.go diff --git a/examples/todolist/internal/command/add_todo_list_item.go b/examples/todolist/internal/command/add_todo_list_item.go new file mode 100644 index 00000000..35af8ee5 --- /dev/null +++ b/examples/todolist/internal/command/add_todo_list_item.go @@ -0,0 +1,56 @@ +package command + +import ( + "context" + "fmt" + "time" + + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" +) + +// AddTodoListItem is the Command used to add a new Item to an existing TodoList. +type AddTodoListItem struct { + TodoListID todolist.ID + TodoItemID todolist.ItemID + Title string + Description string + DueDate time.Time +} + +// Name implements message.Message. +func (AddTodoListItem) Name() string { return "AddTodoListItem" } + +var _ command.Handler[AddTodoListItem] = AddTodoListItemHandler{} + +// AddTodoListItemHandler is the command.Handler for AddTodoListItem commands. +type AddTodoListItemHandler struct { + Clock func() time.Time + Repository todolist.Repository +} + +// Handle implements command.Handler. +func (h AddTodoListItemHandler) Handle(ctx context.Context, cmd command.Envelope[AddTodoListItem]) error { + todoList, err := h.Repository.Get(ctx, cmd.Message.TodoListID) + if err != nil { + return fmt.Errorf("command.AddTodoListItem: failed to get TodoList from repository, %w", err) + } + + now := h.Clock() + + if err := todoList.AddItem( + cmd.Message.TodoItemID, + cmd.Message.Title, + cmd.Message.Description, + cmd.Message.DueDate, + now, + ); err != nil { + return fmt.Errorf("command.AddTodoListItem: failed to add item to TodoList, %w", err) + } + + if err := h.Repository.Save(ctx, todoList); err != nil { + return fmt.Errorf("command.AddTodoListItem: failed to save new TodoList version, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/command/add_todo_list_item_test.go b/examples/todolist/internal/command/add_todo_list_item_test.go new file mode 100644 index 00000000..e570b6b1 --- /dev/null +++ b/examples/todolist/internal/command/add_todo_list_item_test.go @@ -0,0 +1,131 @@ +package command_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/event" + appcommand "github.com/get-eventually/go-eventually/examples/todolist/internal/command" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" +) + +func TestAddTodoListItem(t *testing.T) { + now := time.Now() + commandHandlerFactory := func(es event.Store) appcommand.AddTodoListItemHandler { + return appcommand.AddTodoListItemHandler{ + Clock: func() time.Time { return now }, + Repository: aggregate.NewEventSourcedRepository(es, todolist.Type), + } + } + + todoListID := todolist.ID(uuid.New()) + todoItemID := todolist.ItemID(uuid.New()) + listTitle := "my list" + listOwner := "me" + + t.Run("it fails when the target TodoList does not exist", func(t *testing.T) { + command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + When(command.ToEnvelope(appcommand.AddTodoListItem{ + TodoListID: todoListID, + TodoItemID: todoItemID, + Title: "a todo item that should fail", + Description: "", + DueDate: time.Time{}, + })). + ThenError(aggregate.ErrRootNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the same item has already been added", func(t *testing.T) { + command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + Given(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: listTitle, + Owner: listOwner, + CreationTime: now.Add(-2 * time.Minute), + }), + }, event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 2, + Envelope: event.ToEnvelope(todolist.ItemWasAdded{ + ID: todoItemID, + Title: "a todo item that should succeed", + Description: "", + DueDate: time.Time{}, + CreationTime: now, + }), + }). + When(command.ToEnvelope(appcommand.AddTodoListItem{ + TodoListID: todoListID, + TodoItemID: todoItemID, + Title: "uh oh, this is gonna fail", + Description: "", + DueDate: time.Time{}, + })). + ThenError(todolist.ErrItemAlreadyExists). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item title is empty", func(t *testing.T) { + command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + Given(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: listTitle, + Owner: listOwner, + CreationTime: now.Add(-2 * time.Minute), + }), + }). + When(command.ToEnvelope(appcommand.AddTodoListItem{ + TodoListID: todoListID, + TodoItemID: todoItemID, + Title: "", + Description: "", + DueDate: time.Time{}, + })). + ThenError(todolist.ErrEmptyItemTitle). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it works", func(t *testing.T) { + command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + Given(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: listTitle, + Owner: listOwner, + CreationTime: now.Add(-2 * time.Minute), + }), + }). + When(command.ToEnvelope(appcommand.AddTodoListItem{ + TodoListID: todoListID, + TodoItemID: todoItemID, + Title: "a todo item that should succeed", + Description: "", + DueDate: time.Time{}, + })). + Then(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 2, + Envelope: event.ToEnvelope(todolist.ItemWasAdded{ + ID: todoItemID, + Title: "a todo item that should succeed", + Description: "", + DueDate: time.Time{}, + CreationTime: now, + }), + }). + AssertOn(t, commandHandlerFactory) + }) +} diff --git a/examples/todolist/internal/command/create_todolist.go b/examples/todolist/internal/command/create_todolist.go new file mode 100644 index 00000000..a1c09460 --- /dev/null +++ b/examples/todolist/internal/command/create_todolist.go @@ -0,0 +1,44 @@ +package command + +import ( + "context" + "fmt" + "time" + + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" +) + +// CreateTodoList is the Command used to create a new TodoList. +type CreateTodoList struct { + ID todolist.ID + Title string + Owner string +} + +// Name implements message.Message. +func (CreateTodoList) Name() string { return "CreateTodoList" } + +var _ command.Handler[CreateTodoList] = CreateTodoListHandler{} + +// CreateTodoListHandler is the Command Handler for CreateTodoList commands. +type CreateTodoListHandler struct { + Clock func() time.Time + Repository todolist.Saver +} + +// Handle implements command.Handler. +func (h CreateTodoListHandler) Handle(ctx context.Context, cmd command.Envelope[CreateTodoList]) error { + now := h.Clock() + + todoList, err := todolist.Create(cmd.Message.ID, cmd.Message.Title, cmd.Message.Owner, now) + if err != nil { + return fmt.Errorf("command.CreateTodoListHandler: failed to create new todolist, %w", err) + } + + if err := h.Repository.Save(ctx, todoList); err != nil { + return fmt.Errorf("command.CreateTodoListHandler: failed to save todolist to repository, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/command/create_todolist_test.go b/examples/todolist/internal/command/create_todolist_test.go new file mode 100644 index 00000000..2593b048 --- /dev/null +++ b/examples/todolist/internal/command/create_todolist_test.go @@ -0,0 +1,80 @@ +package command_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/event" + appcommand "github.com/get-eventually/go-eventually/examples/todolist/internal/command" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" +) + +func TestCreateTodoListHandler(t *testing.T) { + id := uuid.New() + now := time.Now() + clock := func() time.Time { return now } + + commandHandlerFactory := func(s event.Store) appcommand.CreateTodoListHandler { + return appcommand.CreateTodoListHandler{ + Clock: clock, + Repository: aggregate.NewEventSourcedRepository(s, todolist.Type), + } + } + + t.Run("it fails when an invalid id has been provided", func(t *testing.T) { + command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). + When(command.ToEnvelope(appcommand.CreateTodoList{ + ID: todolist.ID(uuid.Nil), + Title: "my-title", + Owner: "owner", + })). + ThenError(todolist.ErrEmptyID). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when a title has not been provided", func(t *testing.T) { + command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). + When(command.ToEnvelope(appcommand.CreateTodoList{ + ID: todolist.ID(id), + Title: "", + Owner: "owner", + })). + ThenError(todolist.ErrEmptyTitle). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when an owner has not been provided", func(t *testing.T) { + command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). + When(command.ToEnvelope(appcommand.CreateTodoList{ + ID: todolist.ID(id), + Title: "my-title", + Owner: "", + })). + ThenError(todolist.ErrNoOwnerSpecified). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it works", func(t *testing.T) { + command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). + When(command.ToEnvelope(appcommand.CreateTodoList{ + ID: todolist.ID(id), + Title: "my-title", + Owner: "owner", + })). + Then(event.Persisted{ + StreamID: event.StreamID(todolist.ID(id).String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todolist.ID(id), + Title: "my-title", + Owner: "owner", + CreationTime: now, + }), + }). + AssertOn(t, commandHandlerFactory) + }) +} diff --git a/examples/todolist/internal/command/doc.go b/examples/todolist/internal/command/doc.go new file mode 100644 index 00000000..df9457ac --- /dev/null +++ b/examples/todolist/internal/command/doc.go @@ -0,0 +1,2 @@ +// Package command contains TodoList command definitions and handlers. +package command From 912405e5c73678c6dff0d9a781966455ccc84396 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:54:22 +0200 Subject: [PATCH 05/19] feat(examples): port todolist query handler GetTodoListHandler returns a TodoList by ID via an aggregate.Getter. Empty IDs short-circuit with todolist.ErrEmptyID, matching the domain's validation contract so the Connect layer can map it to InvalidArgument. --- examples/todolist/internal/query/doc.go | 2 + .../todolist/internal/query/get_todo_list.go | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 examples/todolist/internal/query/doc.go create mode 100644 examples/todolist/internal/query/get_todo_list.go diff --git a/examples/todolist/internal/query/doc.go b/examples/todolist/internal/query/doc.go new file mode 100644 index 00000000..c23d5a56 --- /dev/null +++ b/examples/todolist/internal/query/doc.go @@ -0,0 +1,2 @@ +// Package query contains TodoList query definitions and handlers. +package query diff --git a/examples/todolist/internal/query/get_todo_list.go b/examples/todolist/internal/query/get_todo_list.go new file mode 100644 index 00000000..f653f489 --- /dev/null +++ b/examples/todolist/internal/query/get_todo_list.go @@ -0,0 +1,44 @@ +package query + +import ( + "context" + "fmt" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/query" +) + +// GetTodoList is a Domain Query used to return a TodoList view. +type GetTodoList struct { + ID todolist.ID +} + +// Name implements message.Message. +func (GetTodoList) Name() string { return "GetTodoList" } + +var _ query.Handler[GetTodoList, *todolist.TodoList] = GetTodoListHandler{} + +// GetTodoListHandler handles a GetTodoList query, returning the TodoList +// aggregate root specified by the query. +type GetTodoListHandler struct { + Getter todolist.Getter +} + +// Handle implements query.Handler. +func (h GetTodoListHandler) Handle( + ctx context.Context, + q query.Envelope[GetTodoList], +) (*todolist.TodoList, error) { + if q.Message.ID == todolist.ID(uuid.Nil) { + return nil, fmt.Errorf("query.GetTodoList: invalid query provided, %w", todolist.ErrEmptyID) + } + + tl, err := h.Getter.Get(ctx, q.Message.ID) + if err != nil { + return nil, fmt.Errorf("query.GetTodoList: failed to get TodoList from repository, %w", err) + } + + return tl, nil +} From 2c34ae269f82bb5bf0cd834f4c2a8d10600fe63f Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:55:15 +0200 Subject: [PATCH 06/19] feat(examples): add connect server implementation internal/protoconv: convert TodoList domain objects to their Protobuf counterparts (one-way for now: proto <- domain). internal/connect: Connect server implementation for TodoListService. - CreateTodoList and AddTodoItem wired to their command handlers; - GetTodoList wired to its query handler; - MarkAsDone / MarkAsPending / Delete return CodeUnimplemented (domain methods exist and are covered by the aggregate test; adding command handlers for them is out of scope for this litmus test and belongs in a follow-up). Domain errors are mapped to Connect codes: empty-field errors -> InvalidArgument item already exists -> AlreadyExists item/aggregate missing -> NotFound everything else -> Internal Error chains are propagated verbatim via fmt.Errorf(%w). Fine for an example; a production service would sanitize. --- .../todolist/internal/connect/todolist.go | 193 ++++++++++++++++++ .../todolist/internal/protoconv/todolist.go | 40 ++++ 2 files changed, 233 insertions(+) create mode 100644 examples/todolist/internal/connect/todolist.go create mode 100644 examples/todolist/internal/protoconv/todolist.go diff --git a/examples/todolist/internal/connect/todolist.go b/examples/todolist/internal/connect/todolist.go new file mode 100644 index 00000000..105ee188 --- /dev/null +++ b/examples/todolist/internal/connect/todolist.go @@ -0,0 +1,193 @@ +// Package connect contains the Connect server implementation for the TodoList +// service. +// +// This package deliberately uses the import alias "connect" for +// connectrpc.com/connect to match the framework's own naming; the package +// name is kept short because it exclusively hosts the Connect transport. +package connect + +import ( + "context" + "errors" + "fmt" + + connect "connectrpc.com/connect" + "github.com/google/uuid" + emptypb "google.golang.org/protobuf/types/known/emptypb" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/command" + todolistv1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" + "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1/todolistv1connect" + appcommand "github.com/get-eventually/go-eventually/examples/todolist/internal/command" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/examples/todolist/internal/protoconv" + appquery "github.com/get-eventually/go-eventually/examples/todolist/internal/query" + "github.com/get-eventually/go-eventually/query" +) + +var _ todolistv1connect.TodoListServiceHandler = TodoListServiceServer{} + +// TodoListServiceServer is the Connect server implementation for the TodoList +// service. +// +// Clients generate IDs for new resources and pass them in the request; the +// server responds to commands with google.protobuf.Empty. This keeps +// commands idempotent and free of response-payload coupling. +type TodoListServiceServer struct { + todolistv1connect.UnimplementedTodoListServiceHandler + + GetTodoListHandler appquery.GetTodoListHandler + CreateTodoListHandler appcommand.CreateTodoListHandler + AddTodoListHandler appcommand.AddTodoListItemHandler +} + +// parseUUID converts a string field into a uuid.UUID, returning an +// InvalidArgument Connect error on failure. +func parseUUID(field, value string) (uuid.UUID, error) { + id, err := uuid.Parse(value) + if err != nil { + return uuid.Nil, connect.NewError( + connect.CodeInvalidArgument, + fmt.Errorf("connect: failed to parse %s as uuid, %w", field, err), + ) + } + + return id, nil +} + +// mapCommandError classifies command-handler errors into Connect codes. +// +// The error is included verbatim (via %w) so clients can see the full chain. +// This is example-appropriate; production code would typically surface only +// a stable, sanitized message per code. +func mapCommandError(op string, err error) *connect.Error { + code := connect.CodeInternal + + switch { + case errors.Is(err, todolist.ErrEmptyID), + errors.Is(err, todolist.ErrEmptyTitle), + errors.Is(err, todolist.ErrNoOwnerSpecified), + errors.Is(err, todolist.ErrEmptyItemID), + errors.Is(err, todolist.ErrEmptyItemTitle): + code = connect.CodeInvalidArgument + + case errors.Is(err, todolist.ErrItemAlreadyExists): + code = connect.CodeAlreadyExists + + case errors.Is(err, todolist.ErrItemNotFound), + errors.Is(err, aggregate.ErrRootNotFound): + code = connect.CodeNotFound + } + + return connect.NewError(code, fmt.Errorf("%s: %w", op, err)) +} + +// CreateTodoList implements the Connect service handler. +func (srv TodoListServiceServer) CreateTodoList( + ctx context.Context, + req *connect.Request[todolistv1.CreateTodoListRequest], +) (*connect.Response[emptypb.Empty], error) { + id, err := parseUUID("todo_list_id", req.Msg.TodoListId) + if err != nil { + return nil, err + } + + cmd := command.ToEnvelope(appcommand.CreateTodoList{ + ID: todolist.ID(id), + Title: req.Msg.Title, + Owner: req.Msg.Owner, + }) + + if err := srv.CreateTodoListHandler.Handle(ctx, cmd); err != nil { + return nil, mapCommandError("connect.CreateTodoList", err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +// GetTodoList implements the Connect service handler. +func (srv TodoListServiceServer) GetTodoList( + ctx context.Context, + req *connect.Request[todolistv1.GetTodoListRequest], +) (*connect.Response[todolistv1.GetTodoListResponse], error) { + id, err := parseUUID("todo_list_id", req.Msg.TodoListId) + if err != nil { + return nil, err + } + + q := query.ToEnvelope(appquery.GetTodoList{ID: todolist.ID(id)}) + + tl, err := srv.GetTodoListHandler.Handle(ctx, q) + if err != nil { + return nil, mapCommandError("connect.GetTodoList", err) + } + + return connect.NewResponse(&todolistv1.GetTodoListResponse{ + TodoList: protoconv.FromTodoList(tl), + }), nil +} + +// AddTodoItem implements the Connect service handler. +func (srv TodoListServiceServer) AddTodoItem( + ctx context.Context, + req *connect.Request[todolistv1.AddTodoItemRequest], +) (*connect.Response[emptypb.Empty], error) { + listID, err := parseUUID("todo_list_id", req.Msg.TodoListId) + if err != nil { + return nil, err + } + + itemID, err := parseUUID("todo_item_id", req.Msg.TodoItemId) + if err != nil { + return nil, err + } + + cmd := command.ToEnvelope(appcommand.AddTodoListItem{ + TodoListID: todolist.ID(listID), + TodoItemID: todolist.ItemID(itemID), + Title: req.Msg.Title, + Description: req.Msg.Description, + }) + + if req.Msg.DueDate != nil { + cmd.Message.DueDate = req.Msg.DueDate.AsTime() + } + + if err := srv.AddTodoListHandler.Handle(ctx, cmd); err != nil { + return nil, mapCommandError("connect.AddTodoItem", err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil +} + +// MarkTodoItemAsDone implements the Connect service handler. +// +// Not wired up yet in the example: the corresponding command handler is not +// yet defined, so this returns Unimplemented to be explicit about it. +func (srv TodoListServiceServer) MarkTodoItemAsDone( + _ context.Context, + _ *connect.Request[todolistv1.MarkTodoItemAsDoneRequest], +) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("mark-as-done not implemented")) +} + +// MarkTodoItemAsPending implements the Connect service handler. +// +// Not wired up yet in the example: see MarkTodoItemAsDone. +func (srv TodoListServiceServer) MarkTodoItemAsPending( + _ context.Context, + _ *connect.Request[todolistv1.MarkTodoItemAsPendingRequest], +) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("mark-as-pending not implemented")) +} + +// DeleteTodoItem implements the Connect service handler. +// +// Not wired up yet in the example: see MarkTodoItemAsDone. +func (srv TodoListServiceServer) DeleteTodoItem( + _ context.Context, + _ *connect.Request[todolistv1.DeleteTodoItemRequest], +) (*connect.Response[emptypb.Empty], error) { + return nil, connect.NewError(connect.CodeUnimplemented, errors.New("delete not implemented")) +} diff --git a/examples/todolist/internal/protoconv/todolist.go b/examples/todolist/internal/protoconv/todolist.go new file mode 100644 index 00000000..30f59238 --- /dev/null +++ b/examples/todolist/internal/protoconv/todolist.go @@ -0,0 +1,40 @@ +// Package protoconv contains conversions between domain types and their +// generated Protobuf counterparts. +package protoconv + +import ( + "google.golang.org/protobuf/types/known/timestamppb" + + todolistv1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" +) + +// FromTodoList converts a TodoList aggregate root into its Protobuf counterpart. +func FromTodoList(tl *todolist.TodoList) *todolistv1.TodoList { + result := &todolistv1.TodoList{ + Id: tl.ID.String(), + Title: tl.Title, + Owner: tl.Owner, + CreationTime: timestamppb.New(tl.CreationTime), + Items: make([]*todolistv1.TodoItem, 0, len(tl.Items)), + } + + for _, item := range tl.Items { + pbItem := &todolistv1.TodoItem{ + Id: item.ID.String(), + Title: item.Title, + Description: item.Description, + Completed: item.Completed, + DueDate: nil, + CreationTime: timestamppb.New(item.CreationTime), + } + + if !item.DueDate.IsZero() { + pbItem.DueDate = timestamppb.New(item.DueDate) + } + + result.Items = append(result.Items, pbItem) + } + + return result +} From 51f44608bc987b8ed98bb6e1855b2c96737b4c7d Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:56:17 +0200 Subject: [PATCH 07/19] feat(examples): wire todolist main binary Starts a Connect HTTP server backed by an in-memory event.Store. Wires one query handler and two command handlers through an EventSourcedRepository. Notes: - gRPC health + gRPC reflection (v1 and v1alpha) are registered alongside the service handler. - h2c transport is used so the plain-HTTP example still speaks HTTP/2, which Connect over gRPC requires. - SIGINT / SIGTERM trigger graceful shutdown with a configurable ShutdownTimeout; misconfiguration is surfaced via envconfig errors. go.mod is a nested module with `replace` pointing at the repo root, so the example tracks the library's in-progress changes without waiting for a release. --- examples/todolist/go.mod | 26 +++++++ examples/todolist/go.sum | 36 ++++++++++ examples/todolist/main.go | 142 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 examples/todolist/go.mod create mode 100644 examples/todolist/go.sum create mode 100644 examples/todolist/main.go diff --git a/examples/todolist/go.mod b/examples/todolist/go.mod new file mode 100644 index 00000000..b0425e36 --- /dev/null +++ b/examples/todolist/go.mod @@ -0,0 +1,26 @@ +module github.com/get-eventually/go-eventually/examples/todolist + +go 1.26.0 + +require ( + connectrpc.com/connect v1.19.2 + connectrpc.com/grpchealth v1.4.0 + connectrpc.com/grpcreflect v1.3.0 + github.com/get-eventually/go-eventually v0.0.0 + github.com/google/uuid v1.6.0 + github.com/kelseyhightower/envconfig v1.4.0 + go.uber.org/zap v1.27.0 + golang.org/x/net v0.50.0 + google.golang.org/protobuf v1.36.11 +) + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/stretchr/testify v1.11.1 // indirect + go.uber.org/multierr v1.10.0 // indirect + golang.org/x/text v0.36.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/get-eventually/go-eventually => ../.. diff --git a/examples/todolist/go.sum b/examples/todolist/go.sum new file mode 100644 index 00000000..b9191dee --- /dev/null +++ b/examples/todolist/go.sum @@ -0,0 +1,36 @@ +connectrpc.com/connect v1.19.2 h1:McQ83FGdzL+t60peksi0gXC7MQ/iLKgLduAnThbM0mo= +connectrpc.com/connect v1.19.2/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= +connectrpc.com/grpchealth v1.4.0 h1:MJC96JLelARPgZTiRF9KRfY/2N9OcoQvF2EWX07v2IE= +connectrpc.com/grpchealth v1.4.0/go.mod h1:WhW6m1EzTmq3Ky1FE8EfkIpSDc6TfUx2M2KqZO3ts/Q= +connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc= +connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529 h1:QoMBg0moLIlB/eucPzc+ID5SgPZWuirtjAn3l8nW2Dg= +google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529/go.mod h1:EjLmDZ8liSLBrCTK5vP+bGIxRQHE3ovGvOI0CzGk1PI= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/todolist/main.go b/examples/todolist/main.go new file mode 100644 index 00000000..00d37515 --- /dev/null +++ b/examples/todolist/main.go @@ -0,0 +1,142 @@ +// Package main is the entrypoint for the TodoList Connect service example. +// +// The service is backed by an in-memory event.Store: state is lost on +// restart. This example is about showcasing how to wire the +// go-eventually building blocks together, not about persistence. +package main + +import ( + "context" + "errors" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + connectgrpchealth "connectrpc.com/grpchealth" + connectgrpcreflect "connectrpc.com/grpcreflect" + "github.com/kelseyhightower/envconfig" + "go.uber.org/zap" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/event" + "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1/todolistv1connect" + "github.com/get-eventually/go-eventually/examples/todolist/internal/command" + appconnect "github.com/get-eventually/go-eventually/examples/todolist/internal/connect" + "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/examples/todolist/internal/query" +) + +type serverConfig struct { + Address string `default:":8080" envconfig:"ADDRESS"` + ReadTimeout time.Duration `default:"10s" envconfig:"READ_TIMEOUT"` + WriteTimeout time.Duration `default:"10s" envconfig:"WRITE_TIMEOUT"` + ShutdownTimeout time.Duration `default:"15s" envconfig:"SHUTDOWN_TIMEOUT"` +} + +type config struct { + Server serverConfig +} + +func parseConfig() (config, error) { + var cfg config + if err := envconfig.Process("", &cfg); err != nil { + return config{}, fmt.Errorf("failed to parse config from env, %w", err) + } + + return cfg, nil +} + +func run() error { + cfg, err := parseConfig() + if err != nil { + return err + } + + logger, err := zap.NewDevelopment() + if err != nil { + return fmt.Errorf("failed to initialize logger, %w", err) + } + defer func() { _ = logger.Sync() }() + + // In-memory plumbing: a single Store feeds both the command and query + // sides through an EventSourcedRepository. + eventStore := event.NewInMemoryStore() + todoListRepository := aggregate.NewEventSourcedRepository(eventStore, todolist.Type) + + server := appconnect.TodoListServiceServer{ + UnimplementedTodoListServiceHandler: todolistv1connect.UnimplementedTodoListServiceHandler{}, + GetTodoListHandler: query.GetTodoListHandler{ + Getter: todoListRepository, + }, + CreateTodoListHandler: command.CreateTodoListHandler{ + Clock: time.Now, + Repository: todoListRepository, + }, + AddTodoListHandler: command.AddTodoListItemHandler{ + Clock: time.Now, + Repository: todoListRepository, + }, + } + + mux := http.NewServeMux() + mux.Handle(todolistv1connect.NewTodoListServiceHandler(server)) + mux.Handle(connectgrpchealth.NewHandler( + connectgrpchealth.NewStaticChecker(todolistv1connect.TodoListServiceName), + )) + mux.Handle(connectgrpcreflect.NewHandlerV1( + connectgrpcreflect.NewStaticReflector(todolistv1connect.TodoListServiceName), + )) + mux.Handle(connectgrpcreflect.NewHandlerV1Alpha( + connectgrpcreflect.NewStaticReflector(todolistv1connect.TodoListServiceName), + )) + + srv := &http.Server{ + Addr: cfg.Server.Address, + Handler: h2c.NewHandler(mux, &http2.Server{}), //nolint:exhaustruct // h2c.Server defaults are fine. + ReadTimeout: cfg.Server.ReadTimeout, + WriteTimeout: cfg.Server.WriteTimeout, + ReadHeaderTimeout: cfg.Server.ReadTimeout, + } + + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + serverErrs := make(chan error, 1) + + go func() { + logger.Sugar().Infow("connect server started", "address", cfg.Server.Address) + if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + serverErrs <- fmt.Errorf("connect server exited unexpectedly, %w", err) + return + } + serverErrs <- nil + }() + + select { + case <-ctx.Done(): + logger.Info("shutdown signal received") + case err := <-serverErrs: + return err + } + + shutdownCtx, cancel := context.WithTimeout(context.Background(), cfg.Server.ShutdownTimeout) + defer cancel() + + if err := srv.Shutdown(shutdownCtx); err != nil { + return fmt.Errorf("graceful shutdown failed, %w", err) + } + + return nil +} + +func main() { + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, "todolist:", err) + os.Exit(1) + } +} From d351e06d2d2841d8436ac488b74560ed9e2d3b23 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:58:14 +0200 Subject: [PATCH 08/19] chore(lint): remove examples$ exclusion, lint the todolist example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drops the `examples$` path exclusion from both linter and formatter blocks in .golangci.yaml so examples get the same lint treatment as the library itself. Generated code under examples/todolist/gen/ stays excluded by virtue of the `generated: lax` setting recognising the "Code generated by ... DO NOT EDIT" header. Small fixes needed to pass the full lint gate in the new example: - interface-implementation assertions marked //nolint:exhaustruct (they intentionally use zero values; same convention as the library's own event.Store and postgres.EventStore assertions); - http.Server zero-value fields marked //nolint:exhaustruct (stdlib struct with many optional fields); - run() in main.go marked //nolint:funlen — linear wire-up is easier to read as one function; - whitespace tweaks to satisfy wsl_v5 inside the goroutine. Note: golangci-lint run from repo root does not descend into examples/todolist/ because it is a nested module. Lint for the example is run with --config ../../.golangci.yaml from its root. --- .golangci.yaml | 2 -- .../internal/command/add_todo_list_item.go | 1 + .../todolist/internal/command/create_todolist.go | 1 + examples/todolist/internal/connect/todolist.go | 12 ++++++++---- .../todolist/internal/domain/todolist/todolist.go | 2 +- examples/todolist/internal/query/get_todo_list.go | 1 + examples/todolist/main.go | 14 +++++++++++--- 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index e7968876..83aa24f8 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -128,7 +128,6 @@ linters: paths: - third_party$ - builtin$ - - examples$ issues: max-issues-per-linter: 0 @@ -153,4 +152,3 @@ formatters: paths: - third_party$ - builtin$ - - examples$ diff --git a/examples/todolist/internal/command/add_todo_list_item.go b/examples/todolist/internal/command/add_todo_list_item.go index 35af8ee5..aa692114 100644 --- a/examples/todolist/internal/command/add_todo_list_item.go +++ b/examples/todolist/internal/command/add_todo_list_item.go @@ -21,6 +21,7 @@ type AddTodoListItem struct { // Name implements message.Message. func (AddTodoListItem) Name() string { return "AddTodoListItem" } +//nolint:exhaustruct // Interface implementation assertion. var _ command.Handler[AddTodoListItem] = AddTodoListItemHandler{} // AddTodoListItemHandler is the command.Handler for AddTodoListItem commands. diff --git a/examples/todolist/internal/command/create_todolist.go b/examples/todolist/internal/command/create_todolist.go index a1c09460..5e6881eb 100644 --- a/examples/todolist/internal/command/create_todolist.go +++ b/examples/todolist/internal/command/create_todolist.go @@ -19,6 +19,7 @@ type CreateTodoList struct { // Name implements message.Message. func (CreateTodoList) Name() string { return "CreateTodoList" } +//nolint:exhaustruct // Interface implementation assertion. var _ command.Handler[CreateTodoList] = CreateTodoListHandler{} // CreateTodoListHandler is the Command Handler for CreateTodoList commands. diff --git a/examples/todolist/internal/connect/todolist.go b/examples/todolist/internal/connect/todolist.go index 105ee188..b912ff3a 100644 --- a/examples/todolist/internal/connect/todolist.go +++ b/examples/todolist/internal/connect/todolist.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" connect "connectrpc.com/connect" "github.com/google/uuid" @@ -26,6 +27,7 @@ import ( "github.com/get-eventually/go-eventually/query" ) +//nolint:exhaustruct // Interface implementation assertion. var _ todolistv1connect.TodoListServiceHandler = TodoListServiceServer{} // TodoListServiceServer is the Connect server implementation for the TodoList @@ -143,17 +145,19 @@ func (srv TodoListServiceServer) AddTodoItem( return nil, err } + var dueDate time.Time + if req.Msg.DueDate != nil { + dueDate = req.Msg.DueDate.AsTime() + } + cmd := command.ToEnvelope(appcommand.AddTodoListItem{ TodoListID: todolist.ID(listID), TodoItemID: todolist.ItemID(itemID), Title: req.Msg.Title, Description: req.Msg.Description, + DueDate: dueDate, }) - if req.Msg.DueDate != nil { - cmd.Message.DueDate = req.Msg.DueDate.AsTime() - } - if err := srv.AddTodoListHandler.Handle(ctx, cmd); err != nil { return nil, mapCommandError("connect.AddTodoItem", err) } diff --git a/examples/todolist/internal/domain/todolist/todolist.go b/examples/todolist/internal/domain/todolist/todolist.go index 18188e6f..92a0b06c 100644 --- a/examples/todolist/internal/domain/todolist/todolist.go +++ b/examples/todolist/internal/domain/todolist/todolist.go @@ -137,7 +137,7 @@ func Create(id ID, title, owner string, now time.Time) (*TodoList, error) { return nil, wrapErr(ErrNoOwnerSpecified) } - var todoList TodoList //nolint:exhaustruct // Fields are populated by WasCreated apply. + var todoList TodoList if err := aggregate.RecordThat[ID](&todoList, event.ToEnvelope(WasCreated{ ID: id, diff --git a/examples/todolist/internal/query/get_todo_list.go b/examples/todolist/internal/query/get_todo_list.go index f653f489..ad73cf1b 100644 --- a/examples/todolist/internal/query/get_todo_list.go +++ b/examples/todolist/internal/query/get_todo_list.go @@ -18,6 +18,7 @@ type GetTodoList struct { // Name implements message.Message. func (GetTodoList) Name() string { return "GetTodoList" } +//nolint:exhaustruct // Interface implementation assertion. var _ query.Handler[GetTodoList, *todolist.TodoList] = GetTodoListHandler{} // GetTodoListHandler handles a GetTodoList query, returning the TodoList diff --git a/examples/todolist/main.go b/examples/todolist/main.go index 00d37515..4b616ea6 100644 --- a/examples/todolist/main.go +++ b/examples/todolist/main.go @@ -51,7 +51,7 @@ func parseConfig() (config, error) { return cfg, nil } -func run() error { +func run() error { //nolint:funlen // Single linear wire-up of the service; splitting hurts readability. cfg, err := parseConfig() if err != nil { return err @@ -61,7 +61,12 @@ func run() error { if err != nil { return fmt.Errorf("failed to initialize logger, %w", err) } - defer func() { _ = logger.Sync() }() + + defer func() { + // Sync can fail on stderr with "invalid argument" on some + // platforms; it's safe to ignore at shutdown. + _ = logger.Sync() //nolint:errcheck // See comment above. + }() // In-memory plumbing: a single Store feeds both the command and query // sides through an EventSourcedRepository. @@ -95,7 +100,7 @@ func run() error { connectgrpcreflect.NewStaticReflector(todolistv1connect.TodoListServiceName), )) - srv := &http.Server{ + srv := &http.Server{ //nolint:exhaustruct // Stdlib struct with many optional fields; defaults are fine. Addr: cfg.Server.Address, Handler: h2c.NewHandler(mux, &http2.Server{}), //nolint:exhaustruct // h2c.Server defaults are fine. ReadTimeout: cfg.Server.ReadTimeout, @@ -110,10 +115,13 @@ func run() error { go func() { logger.Sugar().Infow("connect server started", "address", cfg.Server.Address) + if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { serverErrs <- fmt.Errorf("connect server exited unexpectedly, %w", err) + return } + serverErrs <- nil }() From 25803e5631addf9ef968a5a2f1ac1d2e54ce9a3f Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 20:59:24 +0200 Subject: [PATCH 09/19] docs(examples): add todolist README and link from root examples/todolist/README.md walks through what the example demonstrates, how to run it, and the deliberate design choices (Connect-only, commands return Empty, one-message-per-proto, in-memory store). Root README.md gains a small 'Examples' section pointing at the todolist example. Linking the example from the root helps discoverability for anyone landing on the library's pkg.go.dev page or GitHub landing. --- README.md | 8 ++++ examples/todolist/README.md | 73 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 examples/todolist/README.md diff --git a/README.md b/README.md index a285c465..774074f3 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,14 @@ You can add this library to your project by running: go get -u github.com/get-eventually/go-eventually ``` +## Examples + +End-to-end examples live under [`examples/`](./examples): + +* [`examples/todolist`](./examples/todolist) — a Connect-based TodoList + service demonstrating aggregates, commands, queries, and BDD-style + scenario tests, backed by the in-memory event store. + ## Contributing Thank you for your consideration ❤️ You can head over our [CONTRIBUTING](./CONTRIBUTING.md) page to get started. diff --git a/examples/todolist/README.md b/examples/todolist/README.md new file mode 100644 index 00000000..cbab6f75 --- /dev/null +++ b/examples/todolist/README.md @@ -0,0 +1,73 @@ +# TodoList example + +A small Connect-based service that exercises `go-eventually`'s DDD / Event +Sourcing primitives end-to-end. It serves as a real-world litmus test for +the library's API: if something feels awkward in this example, it probably +needs rethinking in the library. + +## What this example demonstrates + +- An aggregate root (`TodoList`) with a child entity (`Item`), built on + `aggregate.BaseRoot` and `aggregate.RecordThat`. +- Commands (`CreateTodoList`, `AddTodoListItem`) implementing + `command.Handler[Cmd]`, persisted through an + `aggregate.EventSourcedRepository` backed by `event.NewInMemoryStore`. +- A query (`GetTodoList`) implementing `query.Handler[Q, R]`, reusing the + same repository's `Get`. +- BDD-style test scenarios using `aggregate.Scenario`, `command.Scenario`, + and (implicitly through the command scenarios) the event streaming + plumbing. +- A Connect service exposing the above over HTTP/2 (h2c), with gRPC + health + gRPC reflection wired up. + +Because the repository internally streams events through the new +`message.Stream[event.Persisted]` iterator, any request that triggers +`AddTodoItem` (which loads the existing aggregate) exercises the iterator +end-to-end. + +## Running + +```sh +cd examples/todolist +go run . +# Server listens on :8080 by default +``` + +Hit it with a Connect client, `grpcurl`, or the built-in reflection: + +```sh +grpcurl -plaintext localhost:8080 list +grpcurl -plaintext -d '{"todo_list_id":"...","title":"chores","owner":"me"}' \ + localhost:8080 todolist.v1.TodoListService/CreateTodoList +``` + +## Design choices worth noting + +- **Commands return `google.protobuf.Empty`.** Clients generate IDs and + pass them in; the server acknowledges. Idempotent on retries with the + same ID. +- **One proto file per message** (the "1-1-1" Buf convention). Keeps each + RPC contract isolated and easy to evolve. +- **Connect only.** No HTTP/REST gateway, no `google.api.http` + annotations. The Connect protocol itself already speaks gRPC, gRPC-Web, + and Connect-over-HTTP; that's enough surface for an example. +- **In-memory store.** State is lost on restart. The example is about + wiring, not persistence; swap `event.NewInMemoryStore()` in `main.go` + for a `postgres.NewEventStore(...)` to get durability. +- **Error handling is example-grade.** Domain errors are mapped to Connect + codes (`InvalidArgument`, `AlreadyExists`, `NotFound`, `Internal`) and + the full error chain is propagated to the client. A real service would + sanitize messages before they cross the wire. +- **`MarkTodoItemAsDone` / `MarkTodoItemAsPending` / `DeleteTodoItem`** + exist in the domain but don't yet have command handlers nor wired + Connect handlers. Adding them follows the same pattern as + `AddTodoListItem`; left as an exercise / follow-up PR. + +## Regenerating the protos + +```sh +cd examples/todolist +buf generate proto +``` + +Committed output lives under `gen/`; regenerate after any proto change. From bd632f0008548e30d46bb9287e3988c914ed4a35 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:04:12 +0200 Subject: [PATCH 10/19] refactor(examples): colocate request/response messages with service Folds the seven request/response protos back into todo_list_service.proto alongside the service definition. Domain messages (todo_list, todo_item) stay in their own files, preserving the boundary between transport contracts and reusable domain types. Rationale: for a service of this size (6 RPCs, all unary), colocating requests and responses with the RPC that uses them reads better than strict one-message-per-file splitting. A reader opening todo_list_service.proto sees the full API contract without having to cross-reference eight files. Regenerated gen/ stubs accordingly; the connect stub is unchanged. --- examples/todolist/README.md | 10 +- .../todolist/v1/add_todo_item_request.pb.go | 211 ----- .../v1/create_todo_list_request.pb.go | 184 ----- .../v1/delete_todo_item_request.pb.go | 171 ---- .../todolist/v1/get_todo_list_request.pb.go | 159 ---- .../todolist/v1/get_todo_list_response.pb.go | 165 ---- .../v1/mark_todo_item_as_done_request.pb.go | 171 ---- .../mark_todo_item_as_pending_request.pb.go | 173 ---- .../gen/todolist/v1/todo_list_service.pb.go | 751 +++++++++++++++--- .../todolist/v1/add_todo_item_request.proto | 21 - .../v1/create_todo_list_request.proto | 17 - .../v1/delete_todo_item_request.proto | 11 - .../todolist/v1/get_todo_list_request.proto | 9 - .../todolist/v1/get_todo_list_response.proto | 11 - .../v1/mark_todo_item_as_done_request.proto | 11 - .../mark_todo_item_as_pending_request.proto | 12 - .../proto/todolist/v1/todo_list_service.proto | 76 +- 17 files changed, 732 insertions(+), 1431 deletions(-) delete mode 100644 examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go delete mode 100644 examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go delete mode 100644 examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go delete mode 100644 examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go delete mode 100644 examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go delete mode 100644 examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go delete mode 100644 examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go delete mode 100644 examples/todolist/proto/todolist/v1/add_todo_item_request.proto delete mode 100644 examples/todolist/proto/todolist/v1/create_todo_list_request.proto delete mode 100644 examples/todolist/proto/todolist/v1/delete_todo_item_request.proto delete mode 100644 examples/todolist/proto/todolist/v1/get_todo_list_request.proto delete mode 100644 examples/todolist/proto/todolist/v1/get_todo_list_response.proto delete mode 100644 examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto delete mode 100644 examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto diff --git a/examples/todolist/README.md b/examples/todolist/README.md index cbab6f75..ba7ec295 100644 --- a/examples/todolist/README.md +++ b/examples/todolist/README.md @@ -46,8 +46,10 @@ grpcurl -plaintext -d '{"todo_list_id":"...","title":"chores","owner":"me"}' \ - **Commands return `google.protobuf.Empty`.** Clients generate IDs and pass them in; the server acknowledges. Idempotent on retries with the same ID. -- **One proto file per message** (the "1-1-1" Buf convention). Keeps each - RPC contract isolated and easy to evolve. +- **Request/response messages colocated with the service** in + `todo_list_service.proto`; domain messages live in their own files. + Small service surface benefits more from colocation than from strict + one-message-per-file splitting. - **Connect only.** No HTTP/REST gateway, no `google.api.http` annotations. The Connect protocol itself already speaks gRPC, gRPC-Web, and Connect-over-HTTP; that's enough surface for an example. @@ -67,7 +69,9 @@ grpcurl -plaintext -d '{"todo_list_id":"...","title":"chores","owner":"me"}' \ ```sh cd examples/todolist -buf generate proto +buf generate ``` Committed output lives under `gen/`; regenerate after any proto change. +The buf configuration uses the v2 schema (see `buf.yaml` + `buf.gen.yaml` +at the module root). diff --git a/examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go b/examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go deleted file mode 100644 index 8760dab5..00000000 --- a/examples/todolist/gen/todolist/v1/add_todo_item_request.pb.go +++ /dev/null @@ -1,211 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/add_todo_item_request.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - timestamppb "google.golang.org/protobuf/types/known/timestamppb" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// AddTodoItemRequest adds a new TodoItem to an existing TodoList. -// -// The todo_item_id is client-generated, same as in CreateTodoListRequest. -type AddTodoItemRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // UUID of the target list. - TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` - // Client-generated UUID for the new item. - TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` - // Short title of the item. - Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"` - // Free-form description of the item. - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` - // Optional due date; omit for no due date. - DueDate *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=due_date,json=dueDate,proto3" json:"due_date,omitempty"` -} - -func (x *AddTodoItemRequest) Reset() { - *x = AddTodoItemRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_add_todo_item_request_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *AddTodoItemRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*AddTodoItemRequest) ProtoMessage() {} - -func (x *AddTodoItemRequest) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_add_todo_item_request_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use AddTodoItemRequest.ProtoReflect.Descriptor instead. -func (*AddTodoItemRequest) Descriptor() ([]byte, []int) { - return file_todolist_v1_add_todo_item_request_proto_rawDescGZIP(), []int{0} -} - -func (x *AddTodoItemRequest) GetTodoListId() string { - if x != nil { - return x.TodoListId - } - return "" -} - -func (x *AddTodoItemRequest) GetTodoItemId() string { - if x != nil { - return x.TodoItemId - } - return "" -} - -func (x *AddTodoItemRequest) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *AddTodoItemRequest) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *AddTodoItemRequest) GetDueDate() *timestamppb.Timestamp { - if x != nil { - return x.DueDate - } - return nil -} - -var File_todolist_v1_add_todo_item_request_proto protoreflect.FileDescriptor - -var file_todolist_v1_add_todo_item_request_proto_rawDesc = []byte{ - 0x0a, 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, - 0x64, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x54, - 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, - 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, - 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, - 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x75, 0x65, 0x44, 0x61, 0x74, - 0x65, 0x42, 0xcd, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, - 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x17, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, - 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, - 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, - 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, - 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, - 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_todolist_v1_add_todo_item_request_proto_rawDescOnce sync.Once - file_todolist_v1_add_todo_item_request_proto_rawDescData = file_todolist_v1_add_todo_item_request_proto_rawDesc -) - -func file_todolist_v1_add_todo_item_request_proto_rawDescGZIP() []byte { - file_todolist_v1_add_todo_item_request_proto_rawDescOnce.Do(func() { - file_todolist_v1_add_todo_item_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_add_todo_item_request_proto_rawDescData) - }) - return file_todolist_v1_add_todo_item_request_proto_rawDescData -} - -var file_todolist_v1_add_todo_item_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_add_todo_item_request_proto_goTypes = []interface{}{ - (*AddTodoItemRequest)(nil), // 0: todolist.v1.AddTodoItemRequest - (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp -} -var file_todolist_v1_add_todo_item_request_proto_depIdxs = []int32{ - 1, // 0: todolist.v1.AddTodoItemRequest.due_date:type_name -> google.protobuf.Timestamp - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_todolist_v1_add_todo_item_request_proto_init() } -func file_todolist_v1_add_todo_item_request_proto_init() { - if File_todolist_v1_add_todo_item_request_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_todolist_v1_add_todo_item_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AddTodoItemRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_add_todo_item_request_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_add_todo_item_request_proto_goTypes, - DependencyIndexes: file_todolist_v1_add_todo_item_request_proto_depIdxs, - MessageInfos: file_todolist_v1_add_todo_item_request_proto_msgTypes, - }.Build() - File_todolist_v1_add_todo_item_request_proto = out.File - file_todolist_v1_add_todo_item_request_proto_rawDesc = nil - file_todolist_v1_add_todo_item_request_proto_goTypes = nil - file_todolist_v1_add_todo_item_request_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go b/examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go deleted file mode 100644 index cf1283c2..00000000 --- a/examples/todolist/gen/todolist/v1/create_todo_list_request.pb.go +++ /dev/null @@ -1,184 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/create_todo_list_request.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// CreateTodoListRequest creates a new TodoList with the specified ID. -// -// The todo_list_id is client-generated: clients are expected to generate a -// UUID and pass it in the request. This keeps the command idempotent and -// frees the response of a payload. -type CreateTodoListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Client-generated UUID for the new list. - TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` - // Display title of the list. - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - // Owner identifier. - Owner string `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` -} - -func (x *CreateTodoListRequest) Reset() { - *x = CreateTodoListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_create_todo_list_request_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CreateTodoListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CreateTodoListRequest) ProtoMessage() {} - -func (x *CreateTodoListRequest) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_create_todo_list_request_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CreateTodoListRequest.ProtoReflect.Descriptor instead. -func (*CreateTodoListRequest) Descriptor() ([]byte, []int) { - return file_todolist_v1_create_todo_list_request_proto_rawDescGZIP(), []int{0} -} - -func (x *CreateTodoListRequest) GetTodoListId() string { - if x != nil { - return x.TodoListId - } - return "" -} - -func (x *CreateTodoListRequest) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *CreateTodoListRequest) GetOwner() string { - if x != nil { - return x.Owner - } - return "" -} - -var File_todolist_v1_create_todo_list_request_proto protoreflect.FileDescriptor - -var file_todolist_v1_create_todo_list_request_proto_rawDesc = []byte{ - 0x0a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x65, 0x0a, 0x15, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, - 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, - 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, - 0x42, 0xd0, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, - 0x74, 0x2e, 0x76, 0x31, 0x42, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, - 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, - 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, - 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, - 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, - 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_todolist_v1_create_todo_list_request_proto_rawDescOnce sync.Once - file_todolist_v1_create_todo_list_request_proto_rawDescData = file_todolist_v1_create_todo_list_request_proto_rawDesc -) - -func file_todolist_v1_create_todo_list_request_proto_rawDescGZIP() []byte { - file_todolist_v1_create_todo_list_request_proto_rawDescOnce.Do(func() { - file_todolist_v1_create_todo_list_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_create_todo_list_request_proto_rawDescData) - }) - return file_todolist_v1_create_todo_list_request_proto_rawDescData -} - -var file_todolist_v1_create_todo_list_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_create_todo_list_request_proto_goTypes = []interface{}{ - (*CreateTodoListRequest)(nil), // 0: todolist.v1.CreateTodoListRequest -} -var file_todolist_v1_create_todo_list_request_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_todolist_v1_create_todo_list_request_proto_init() } -func file_todolist_v1_create_todo_list_request_proto_init() { - if File_todolist_v1_create_todo_list_request_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_todolist_v1_create_todo_list_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateTodoListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_create_todo_list_request_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_create_todo_list_request_proto_goTypes, - DependencyIndexes: file_todolist_v1_create_todo_list_request_proto_depIdxs, - MessageInfos: file_todolist_v1_create_todo_list_request_proto_msgTypes, - }.Build() - File_todolist_v1_create_todo_list_request_proto = out.File - file_todolist_v1_create_todo_list_request_proto_rawDesc = nil - file_todolist_v1_create_todo_list_request_proto_goTypes = nil - file_todolist_v1_create_todo_list_request_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go b/examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go deleted file mode 100644 index 76b3ea27..00000000 --- a/examples/todolist/gen/todolist/v1/delete_todo_item_request.pb.go +++ /dev/null @@ -1,171 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/delete_todo_item_request.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// DeleteTodoItemRequest removes an item from a TodoList. -type DeleteTodoItemRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // UUID of the list that owns the item. - TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` - // UUID of the item to delete. - TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` -} - -func (x *DeleteTodoItemRequest) Reset() { - *x = DeleteTodoItemRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_delete_todo_item_request_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DeleteTodoItemRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DeleteTodoItemRequest) ProtoMessage() {} - -func (x *DeleteTodoItemRequest) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_delete_todo_item_request_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DeleteTodoItemRequest.ProtoReflect.Descriptor instead. -func (*DeleteTodoItemRequest) Descriptor() ([]byte, []int) { - return file_todolist_v1_delete_todo_item_request_proto_rawDescGZIP(), []int{0} -} - -func (x *DeleteTodoItemRequest) GetTodoListId() string { - if x != nil { - return x.TodoListId - } - return "" -} - -func (x *DeleteTodoItemRequest) GetTodoItemId() string { - if x != nil { - return x.TodoItemId - } - return "" -} - -var File_todolist_v1_delete_todo_item_request_proto protoreflect.FileDescriptor - -var file_todolist_v1_delete_todo_item_request_proto_rawDesc = []byte{ - 0x0a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x5b, 0x0a, 0x15, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, - 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, - 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, - 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x42, 0xd0, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x1a, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, - 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, - 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, - 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, - 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, - 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, - 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, - 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, - 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var ( - file_todolist_v1_delete_todo_item_request_proto_rawDescOnce sync.Once - file_todolist_v1_delete_todo_item_request_proto_rawDescData = file_todolist_v1_delete_todo_item_request_proto_rawDesc -) - -func file_todolist_v1_delete_todo_item_request_proto_rawDescGZIP() []byte { - file_todolist_v1_delete_todo_item_request_proto_rawDescOnce.Do(func() { - file_todolist_v1_delete_todo_item_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_delete_todo_item_request_proto_rawDescData) - }) - return file_todolist_v1_delete_todo_item_request_proto_rawDescData -} - -var file_todolist_v1_delete_todo_item_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_delete_todo_item_request_proto_goTypes = []interface{}{ - (*DeleteTodoItemRequest)(nil), // 0: todolist.v1.DeleteTodoItemRequest -} -var file_todolist_v1_delete_todo_item_request_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_todolist_v1_delete_todo_item_request_proto_init() } -func file_todolist_v1_delete_todo_item_request_proto_init() { - if File_todolist_v1_delete_todo_item_request_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_todolist_v1_delete_todo_item_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteTodoItemRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_delete_todo_item_request_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_delete_todo_item_request_proto_goTypes, - DependencyIndexes: file_todolist_v1_delete_todo_item_request_proto_depIdxs, - MessageInfos: file_todolist_v1_delete_todo_item_request_proto_msgTypes, - }.Build() - File_todolist_v1_delete_todo_item_request_proto = out.File - file_todolist_v1_delete_todo_item_request_proto_rawDesc = nil - file_todolist_v1_delete_todo_item_request_proto_goTypes = nil - file_todolist_v1_delete_todo_item_request_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go b/examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go deleted file mode 100644 index ae17c8f0..00000000 --- a/examples/todolist/gen/todolist/v1/get_todo_list_request.pb.go +++ /dev/null @@ -1,159 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/get_todo_list_request.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// GetTodoListRequest fetches a TodoList by its ID. -type GetTodoListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // UUID of the list to fetch. - TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` -} - -func (x *GetTodoListRequest) Reset() { - *x = GetTodoListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_get_todo_list_request_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetTodoListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetTodoListRequest) ProtoMessage() {} - -func (x *GetTodoListRequest) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_get_todo_list_request_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetTodoListRequest.ProtoReflect.Descriptor instead. -func (*GetTodoListRequest) Descriptor() ([]byte, []int) { - return file_todolist_v1_get_todo_list_request_proto_rawDescGZIP(), []int{0} -} - -func (x *GetTodoListRequest) GetTodoListId() string { - if x != nil { - return x.TodoListId - } - return "" -} - -var File_todolist_v1_get_todo_list_request_proto protoreflect.FileDescriptor - -var file_todolist_v1_get_todo_list_request_proto_rawDesc = []byte{ - 0x0a, 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, - 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, 0x36, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, - 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, - 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x42, 0xcd, - 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, - 0x76, 0x31, 0x42, 0x17, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, - 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, - 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, - 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, - 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, - 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, - 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_todolist_v1_get_todo_list_request_proto_rawDescOnce sync.Once - file_todolist_v1_get_todo_list_request_proto_rawDescData = file_todolist_v1_get_todo_list_request_proto_rawDesc -) - -func file_todolist_v1_get_todo_list_request_proto_rawDescGZIP() []byte { - file_todolist_v1_get_todo_list_request_proto_rawDescOnce.Do(func() { - file_todolist_v1_get_todo_list_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_get_todo_list_request_proto_rawDescData) - }) - return file_todolist_v1_get_todo_list_request_proto_rawDescData -} - -var file_todolist_v1_get_todo_list_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_get_todo_list_request_proto_goTypes = []interface{}{ - (*GetTodoListRequest)(nil), // 0: todolist.v1.GetTodoListRequest -} -var file_todolist_v1_get_todo_list_request_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_todolist_v1_get_todo_list_request_proto_init() } -func file_todolist_v1_get_todo_list_request_proto_init() { - if File_todolist_v1_get_todo_list_request_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_todolist_v1_get_todo_list_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetTodoListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_get_todo_list_request_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_get_todo_list_request_proto_goTypes, - DependencyIndexes: file_todolist_v1_get_todo_list_request_proto_depIdxs, - MessageInfos: file_todolist_v1_get_todo_list_request_proto_msgTypes, - }.Build() - File_todolist_v1_get_todo_list_request_proto = out.File - file_todolist_v1_get_todo_list_request_proto_rawDesc = nil - file_todolist_v1_get_todo_list_request_proto_goTypes = nil - file_todolist_v1_get_todo_list_request_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go b/examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go deleted file mode 100644 index 14e5fd82..00000000 --- a/examples/todolist/gen/todolist/v1/get_todo_list_response.pb.go +++ /dev/null @@ -1,165 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/get_todo_list_response.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// GetTodoListResponse contains the requested TodoList. -type GetTodoListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The requested list. - TodoList *TodoList `protobuf:"bytes,1,opt,name=todo_list,json=todoList,proto3" json:"todo_list,omitempty"` -} - -func (x *GetTodoListResponse) Reset() { - *x = GetTodoListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_get_todo_list_response_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *GetTodoListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*GetTodoListResponse) ProtoMessage() {} - -func (x *GetTodoListResponse) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_get_todo_list_response_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use GetTodoListResponse.ProtoReflect.Descriptor instead. -func (*GetTodoListResponse) Descriptor() ([]byte, []int) { - return file_todolist_v1_get_todo_list_response_proto_rawDescGZIP(), []int{0} -} - -func (x *GetTodoListResponse) GetTodoList() *TodoList { - if x != nil { - return x.TodoList - } - return nil -} - -var File_todolist_v1_get_todo_list_response_proto protoreflect.FileDescriptor - -var file_todolist_v1_get_todo_list_response_proto_rawDesc = []byte{ - 0x0a, 0x28, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, - 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, - 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, - 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x49, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x74, - 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x64, - 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x42, - 0xce, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, - 0x2e, 0x76, 0x31, 0x42, 0x18, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, - 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, - 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_todolist_v1_get_todo_list_response_proto_rawDescOnce sync.Once - file_todolist_v1_get_todo_list_response_proto_rawDescData = file_todolist_v1_get_todo_list_response_proto_rawDesc -) - -func file_todolist_v1_get_todo_list_response_proto_rawDescGZIP() []byte { - file_todolist_v1_get_todo_list_response_proto_rawDescOnce.Do(func() { - file_todolist_v1_get_todo_list_response_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_get_todo_list_response_proto_rawDescData) - }) - return file_todolist_v1_get_todo_list_response_proto_rawDescData -} - -var file_todolist_v1_get_todo_list_response_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_get_todo_list_response_proto_goTypes = []interface{}{ - (*GetTodoListResponse)(nil), // 0: todolist.v1.GetTodoListResponse - (*TodoList)(nil), // 1: todolist.v1.TodoList -} -var file_todolist_v1_get_todo_list_response_proto_depIdxs = []int32{ - 1, // 0: todolist.v1.GetTodoListResponse.todo_list:type_name -> todolist.v1.TodoList - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_todolist_v1_get_todo_list_response_proto_init() } -func file_todolist_v1_get_todo_list_response_proto_init() { - if File_todolist_v1_get_todo_list_response_proto != nil { - return - } - file_todolist_v1_todo_list_proto_init() - if !protoimpl.UnsafeEnabled { - file_todolist_v1_get_todo_list_response_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetTodoListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_get_todo_list_response_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_get_todo_list_response_proto_goTypes, - DependencyIndexes: file_todolist_v1_get_todo_list_response_proto_depIdxs, - MessageInfos: file_todolist_v1_get_todo_list_response_proto_msgTypes, - }.Build() - File_todolist_v1_get_todo_list_response_proto = out.File - file_todolist_v1_get_todo_list_response_proto_rawDesc = nil - file_todolist_v1_get_todo_list_response_proto_goTypes = nil - file_todolist_v1_get_todo_list_response_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go b/examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go deleted file mode 100644 index a5e5a73e..00000000 --- a/examples/todolist/gen/todolist/v1/mark_todo_item_as_done_request.pb.go +++ /dev/null @@ -1,171 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/mark_todo_item_as_done_request.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// MarkTodoItemAsDoneRequest marks an item in a TodoList as completed. -type MarkTodoItemAsDoneRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // UUID of the list that owns the item. - TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` - // UUID of the item to mark as done. - TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` -} - -func (x *MarkTodoItemAsDoneRequest) Reset() { - *x = MarkTodoItemAsDoneRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MarkTodoItemAsDoneRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MarkTodoItemAsDoneRequest) ProtoMessage() {} - -func (x *MarkTodoItemAsDoneRequest) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MarkTodoItemAsDoneRequest.ProtoReflect.Descriptor instead. -func (*MarkTodoItemAsDoneRequest) Descriptor() ([]byte, []int) { - return file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescGZIP(), []int{0} -} - -func (x *MarkTodoItemAsDoneRequest) GetTodoListId() string { - if x != nil { - return x.TodoListId - } - return "" -} - -func (x *MarkTodoItemAsDoneRequest) GetTodoItemId() string { - if x != nil { - return x.TodoItemId - } - return "" -} - -var File_todolist_v1_mark_todo_item_as_done_request_proto protoreflect.FileDescriptor - -var file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc = []byte{ - 0x0a, 0x30, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, - 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x73, 0x5f, - 0x64, 0x6f, 0x6e, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x22, - 0x5f, 0x0a, 0x19, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, - 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, - 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, - 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, - 0x42, 0xd4, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, - 0x74, 0x2e, 0x76, 0x31, 0x42, 0x1e, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, - 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, - 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, - 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, - 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, - 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, - 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, - 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, - 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescOnce sync.Once - file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData = file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc -) - -func file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescGZIP() []byte { - file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescOnce.Do(func() { - file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData) - }) - return file_todolist_v1_mark_todo_item_as_done_request_proto_rawDescData -} - -var file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_mark_todo_item_as_done_request_proto_goTypes = []interface{}{ - (*MarkTodoItemAsDoneRequest)(nil), // 0: todolist.v1.MarkTodoItemAsDoneRequest -} -var file_todolist_v1_mark_todo_item_as_done_request_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_todolist_v1_mark_todo_item_as_done_request_proto_init() } -func file_todolist_v1_mark_todo_item_as_done_request_proto_init() { - if File_todolist_v1_mark_todo_item_as_done_request_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MarkTodoItemAsDoneRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_mark_todo_item_as_done_request_proto_goTypes, - DependencyIndexes: file_todolist_v1_mark_todo_item_as_done_request_proto_depIdxs, - MessageInfos: file_todolist_v1_mark_todo_item_as_done_request_proto_msgTypes, - }.Build() - File_todolist_v1_mark_todo_item_as_done_request_proto = out.File - file_todolist_v1_mark_todo_item_as_done_request_proto_rawDesc = nil - file_todolist_v1_mark_todo_item_as_done_request_proto_goTypes = nil - file_todolist_v1_mark_todo_item_as_done_request_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go b/examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go deleted file mode 100644 index b2600e9d..00000000 --- a/examples/todolist/gen/todolist/v1/mark_todo_item_as_pending_request.pb.go +++ /dev/null @@ -1,173 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.31.0 -// protoc (unknown) -// source: todolist/v1/mark_todo_item_as_pending_request.proto - -package todolistv1 - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// MarkTodoItemAsPendingRequest marks an item in a TodoList as pending -// (i.e., undoes a previous "mark as done"). -type MarkTodoItemAsPendingRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // UUID of the list that owns the item. - TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` - // UUID of the item to mark as pending. - TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` -} - -func (x *MarkTodoItemAsPendingRequest) Reset() { - *x = MarkTodoItemAsPendingRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MarkTodoItemAsPendingRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MarkTodoItemAsPendingRequest) ProtoMessage() {} - -func (x *MarkTodoItemAsPendingRequest) ProtoReflect() protoreflect.Message { - mi := &file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MarkTodoItemAsPendingRequest.ProtoReflect.Descriptor instead. -func (*MarkTodoItemAsPendingRequest) Descriptor() ([]byte, []int) { - return file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescGZIP(), []int{0} -} - -func (x *MarkTodoItemAsPendingRequest) GetTodoListId() string { - if x != nil { - return x.TodoListId - } - return "" -} - -func (x *MarkTodoItemAsPendingRequest) GetTodoItemId() string { - if x != nil { - return x.TodoItemId - } - return "" -} - -var File_todolist_v1_mark_todo_item_as_pending_request_proto protoreflect.FileDescriptor - -var file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc = []byte{ - 0x0a, 0x33, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x61, - 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x61, 0x73, 0x5f, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, - 0x76, 0x31, 0x22, 0x62, 0x0a, 0x1c, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, - 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, - 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, - 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, - 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x42, 0xd7, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x21, 0x4d, 0x61, 0x72, 0x6b, - 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, - 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, - 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, - 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, - 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescOnce sync.Once - file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData = file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc -) - -func file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescGZIP() []byte { - file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescOnce.Do(func() { - file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData) - }) - return file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDescData -} - -var file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_todolist_v1_mark_todo_item_as_pending_request_proto_goTypes = []interface{}{ - (*MarkTodoItemAsPendingRequest)(nil), // 0: todolist.v1.MarkTodoItemAsPendingRequest -} -var file_todolist_v1_mark_todo_item_as_pending_request_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_todolist_v1_mark_todo_item_as_pending_request_proto_init() } -func file_todolist_v1_mark_todo_item_as_pending_request_proto_init() { - if File_todolist_v1_mark_todo_item_as_pending_request_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MarkTodoItemAsPendingRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_todolist_v1_mark_todo_item_as_pending_request_proto_goTypes, - DependencyIndexes: file_todolist_v1_mark_todo_item_as_pending_request_proto_depIdxs, - MessageInfos: file_todolist_v1_mark_todo_item_as_pending_request_proto_msgTypes, - }.Build() - File_todolist_v1_mark_todo_item_as_pending_request_proto = out.File - file_todolist_v1_mark_todo_item_as_pending_request_proto_rawDesc = nil - file_todolist_v1_mark_todo_item_as_pending_request_proto_goTypes = nil - file_todolist_v1_mark_todo_item_as_pending_request_proto_depIdxs = nil -} diff --git a/examples/todolist/gen/todolist/v1/todo_list_service.pb.go b/examples/todolist/gen/todolist/v1/todo_list_service.pb.go index 018cf8ae..d269f8c9 100644 --- a/examples/todolist/gen/todolist/v1/todo_list_service.pb.go +++ b/examples/todolist/gen/todolist/v1/todo_list_service.pb.go @@ -10,7 +10,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" + sync "sync" ) const ( @@ -20,6 +22,437 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// CreateTodoListRequest creates a new TodoList with the specified ID. +// +// The todo_list_id is client-generated: clients are expected to generate a +// UUID and pass it in the request. This keeps the command idempotent and +// frees the response of a payload. +type CreateTodoListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Client-generated UUID for the new list. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // Display title of the list. + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + // Owner identifier. + Owner string `protobuf:"bytes,3,opt,name=owner,proto3" json:"owner,omitempty"` +} + +func (x *CreateTodoListRequest) Reset() { + *x = CreateTodoListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateTodoListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTodoListRequest) ProtoMessage() {} + +func (x *CreateTodoListRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateTodoListRequest.ProtoReflect.Descriptor instead. +func (*CreateTodoListRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{0} +} + +func (x *CreateTodoListRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *CreateTodoListRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *CreateTodoListRequest) GetOwner() string { + if x != nil { + return x.Owner + } + return "" +} + +// GetTodoListRequest fetches a TodoList by its ID. +type GetTodoListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list to fetch. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` +} + +func (x *GetTodoListRequest) Reset() { + *x = GetTodoListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTodoListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTodoListRequest) ProtoMessage() {} + +func (x *GetTodoListRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTodoListRequest.ProtoReflect.Descriptor instead. +func (*GetTodoListRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetTodoListRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +// GetTodoListResponse contains the requested TodoList. +type GetTodoListResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The requested list. + TodoList *TodoList `protobuf:"bytes,1,opt,name=todo_list,json=todoList,proto3" json:"todo_list,omitempty"` +} + +func (x *GetTodoListResponse) Reset() { + *x = GetTodoListResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTodoListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTodoListResponse) ProtoMessage() {} + +func (x *GetTodoListResponse) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTodoListResponse.ProtoReflect.Descriptor instead. +func (*GetTodoListResponse) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{2} +} + +func (x *GetTodoListResponse) GetTodoList() *TodoList { + if x != nil { + return x.TodoList + } + return nil +} + +// AddTodoItemRequest adds a new TodoItem to an existing TodoList. +// +// The todo_item_id is client-generated, same as in CreateTodoListRequest. +type AddTodoItemRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the target list. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // Client-generated UUID for the new item. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` + // Short title of the item. + Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"` + // Free-form description of the item. + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + // Optional due date; omit for no due date. + DueDate *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=due_date,json=dueDate,proto3" json:"due_date,omitempty"` +} + +func (x *AddTodoItemRequest) Reset() { + *x = AddTodoItemRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddTodoItemRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddTodoItemRequest) ProtoMessage() {} + +func (x *AddTodoItemRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddTodoItemRequest.ProtoReflect.Descriptor instead. +func (*AddTodoItemRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{3} +} + +func (x *AddTodoItemRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *AddTodoItemRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +func (x *AddTodoItemRequest) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *AddTodoItemRequest) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *AddTodoItemRequest) GetDueDate() *timestamppb.Timestamp { + if x != nil { + return x.DueDate + } + return nil +} + +// MarkTodoItemAsDoneRequest marks an item in a TodoList as completed. +type MarkTodoItemAsDoneRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list that owns the item. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // UUID of the item to mark as done. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` +} + +func (x *MarkTodoItemAsDoneRequest) Reset() { + *x = MarkTodoItemAsDoneRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MarkTodoItemAsDoneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkTodoItemAsDoneRequest) ProtoMessage() {} + +func (x *MarkTodoItemAsDoneRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MarkTodoItemAsDoneRequest.ProtoReflect.Descriptor instead. +func (*MarkTodoItemAsDoneRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{4} +} + +func (x *MarkTodoItemAsDoneRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *MarkTodoItemAsDoneRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +// MarkTodoItemAsPendingRequest marks an item in a TodoList as pending +// (i.e., undoes a previous "mark as done"). +type MarkTodoItemAsPendingRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list that owns the item. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // UUID of the item to mark as pending. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` +} + +func (x *MarkTodoItemAsPendingRequest) Reset() { + *x = MarkTodoItemAsPendingRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MarkTodoItemAsPendingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MarkTodoItemAsPendingRequest) ProtoMessage() {} + +func (x *MarkTodoItemAsPendingRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MarkTodoItemAsPendingRequest.ProtoReflect.Descriptor instead. +func (*MarkTodoItemAsPendingRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{5} +} + +func (x *MarkTodoItemAsPendingRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *MarkTodoItemAsPendingRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + +// DeleteTodoItemRequest removes an item from a TodoList. +type DeleteTodoItemRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // UUID of the list that owns the item. + TodoListId string `protobuf:"bytes,1,opt,name=todo_list_id,json=todoListId,proto3" json:"todo_list_id,omitempty"` + // UUID of the item to delete. + TodoItemId string `protobuf:"bytes,2,opt,name=todo_item_id,json=todoItemId,proto3" json:"todo_item_id,omitempty"` +} + +func (x *DeleteTodoItemRequest) Reset() { + *x = DeleteTodoItemRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteTodoItemRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteTodoItemRequest) ProtoMessage() {} + +func (x *DeleteTodoItemRequest) ProtoReflect() protoreflect.Message { + mi := &file_todolist_v1_todo_list_service_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteTodoItemRequest.ProtoReflect.Descriptor instead. +func (*DeleteTodoItemRequest) Descriptor() ([]byte, []int) { + return file_todolist_v1_todo_list_service_proto_rawDescGZIP(), []int{6} +} + +func (x *DeleteTodoItemRequest) GetTodoListId() string { + if x != nil { + return x.TodoListId + } + return "" +} + +func (x *DeleteTodoItemRequest) GetTodoItemId() string { + if x != nil { + return x.TodoItemId + } + return "" +} + var File_todolist_v1_todo_list_service_proto protoreflect.FileDescriptor var file_todolist_v1_todo_list_service_proto_rawDesc = []byte{ @@ -28,101 +461,148 @@ var file_todolist_v1_todo_list_service_proto_rawDesc = []byte{ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, - 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x64, 0x64, - 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, - 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, - 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, - 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, - 0x65, 0x6d, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x27, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, - 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x74, 0x6f, 0x64, 0x6f, 0x6c, - 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x30, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, - 0x2f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, - 0x61, 0x73, 0x5f, 0x64, 0x6f, 0x6e, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x33, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, - 0x76, 0x31, 0x2f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, - 0x6d, 0x5f, 0x61, 0x73, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xf9, 0x03, 0x0a, 0x0f, 0x54, - 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, - 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, - 0x12, 0x22, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x0b, - 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x74, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, - 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, - 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, - 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x2e, - 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, - 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x54, 0x0a, 0x12, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, - 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x12, 0x26, 0x2e, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x54, - 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5a, 0x0a, 0x15, - 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x1b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, + 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x65, 0x0a, + 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, + 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, + 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x22, 0x36, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, + 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, 0x22, 0x49, 0x0a, 0x13, + 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x08, 0x74, + 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xc7, 0x01, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x54, + 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, + 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, + 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x08, 0x64, 0x75, + 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x64, 0x75, 0x65, 0x44, 0x61, 0x74, + 0x65, 0x22, 0x5f, 0x0a, 0x19, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, + 0x6d, 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, + 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, + 0x49, 0x64, 0x22, 0x62, 0x0a, 0x1c, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, + 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, + 0x73, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, + 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, + 0x49, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x22, 0x5b, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x64, 0x6f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, + 0x6d, 0x49, 0x64, 0x32, 0xf9, 0x03, 0x0a, 0x0f, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x22, 0x2e, 0x74, 0x6f, 0x64, 0x6f, + 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x6f, + 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x50, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x6f, + 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x64, 0x64, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x54, 0x0a, 0x12, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, + 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x12, 0x26, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, - 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x22, 0x2e, 0x74, 0x6f, 0x64, - 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, - 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0xca, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x42, 0x14, 0x54, 0x6f, 0x64, 0x6f, - 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, - 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, - 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, - 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, - 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, - 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, - 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, - 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, - 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x41, 0x73, 0x44, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5a, 0x0a, 0x15, 0x4d, 0x61, 0x72, 0x6b, 0x54, 0x6f, 0x64, + 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x29, + 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x72, + 0x6b, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x73, 0x50, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x12, 0x4c, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x22, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, + 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x6f, 0x64, 0x6f, 0x49, 0x74, 0x65, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, + 0xca, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x42, 0x14, 0x54, 0x6f, 0x64, 0x6f, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x54, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x74, 0x2d, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x75, + 0x61, 0x6c, 0x6c, 0x79, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x6f, + 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x6c, + 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x76, + 0x31, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, + 0x73, 0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, + 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x5c, 0x56, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, + 0x54, 0x6f, 0x64, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } +var ( + file_todolist_v1_todo_list_service_proto_rawDescOnce sync.Once + file_todolist_v1_todo_list_service_proto_rawDescData = file_todolist_v1_todo_list_service_proto_rawDesc +) + +func file_todolist_v1_todo_list_service_proto_rawDescGZIP() []byte { + file_todolist_v1_todo_list_service_proto_rawDescOnce.Do(func() { + file_todolist_v1_todo_list_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_todolist_v1_todo_list_service_proto_rawDescData) + }) + return file_todolist_v1_todo_list_service_proto_rawDescData +} + +var file_todolist_v1_todo_list_service_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_todolist_v1_todo_list_service_proto_goTypes = []interface{}{ (*CreateTodoListRequest)(nil), // 0: todolist.v1.CreateTodoListRequest (*GetTodoListRequest)(nil), // 1: todolist.v1.GetTodoListRequest - (*AddTodoItemRequest)(nil), // 2: todolist.v1.AddTodoItemRequest - (*MarkTodoItemAsDoneRequest)(nil), // 3: todolist.v1.MarkTodoItemAsDoneRequest - (*MarkTodoItemAsPendingRequest)(nil), // 4: todolist.v1.MarkTodoItemAsPendingRequest - (*DeleteTodoItemRequest)(nil), // 5: todolist.v1.DeleteTodoItemRequest - (*emptypb.Empty)(nil), // 6: google.protobuf.Empty - (*GetTodoListResponse)(nil), // 7: todolist.v1.GetTodoListResponse + (*GetTodoListResponse)(nil), // 2: todolist.v1.GetTodoListResponse + (*AddTodoItemRequest)(nil), // 3: todolist.v1.AddTodoItemRequest + (*MarkTodoItemAsDoneRequest)(nil), // 4: todolist.v1.MarkTodoItemAsDoneRequest + (*MarkTodoItemAsPendingRequest)(nil), // 5: todolist.v1.MarkTodoItemAsPendingRequest + (*DeleteTodoItemRequest)(nil), // 6: todolist.v1.DeleteTodoItemRequest + (*TodoList)(nil), // 7: todolist.v1.TodoList + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 9: google.protobuf.Empty } var file_todolist_v1_todo_list_service_proto_depIdxs = []int32{ - 0, // 0: todolist.v1.TodoListService.CreateTodoList:input_type -> todolist.v1.CreateTodoListRequest - 1, // 1: todolist.v1.TodoListService.GetTodoList:input_type -> todolist.v1.GetTodoListRequest - 2, // 2: todolist.v1.TodoListService.AddTodoItem:input_type -> todolist.v1.AddTodoItemRequest - 3, // 3: todolist.v1.TodoListService.MarkTodoItemAsDone:input_type -> todolist.v1.MarkTodoItemAsDoneRequest - 4, // 4: todolist.v1.TodoListService.MarkTodoItemAsPending:input_type -> todolist.v1.MarkTodoItemAsPendingRequest - 5, // 5: todolist.v1.TodoListService.DeleteTodoItem:input_type -> todolist.v1.DeleteTodoItemRequest - 6, // 6: todolist.v1.TodoListService.CreateTodoList:output_type -> google.protobuf.Empty - 7, // 7: todolist.v1.TodoListService.GetTodoList:output_type -> todolist.v1.GetTodoListResponse - 6, // 8: todolist.v1.TodoListService.AddTodoItem:output_type -> google.protobuf.Empty - 6, // 9: todolist.v1.TodoListService.MarkTodoItemAsDone:output_type -> google.protobuf.Empty - 6, // 10: todolist.v1.TodoListService.MarkTodoItemAsPending:output_type -> google.protobuf.Empty - 6, // 11: todolist.v1.TodoListService.DeleteTodoItem:output_type -> google.protobuf.Empty - 6, // [6:12] is the sub-list for method output_type - 0, // [0:6] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 7, // 0: todolist.v1.GetTodoListResponse.todo_list:type_name -> todolist.v1.TodoList + 8, // 1: todolist.v1.AddTodoItemRequest.due_date:type_name -> google.protobuf.Timestamp + 0, // 2: todolist.v1.TodoListService.CreateTodoList:input_type -> todolist.v1.CreateTodoListRequest + 1, // 3: todolist.v1.TodoListService.GetTodoList:input_type -> todolist.v1.GetTodoListRequest + 3, // 4: todolist.v1.TodoListService.AddTodoItem:input_type -> todolist.v1.AddTodoItemRequest + 4, // 5: todolist.v1.TodoListService.MarkTodoItemAsDone:input_type -> todolist.v1.MarkTodoItemAsDoneRequest + 5, // 6: todolist.v1.TodoListService.MarkTodoItemAsPending:input_type -> todolist.v1.MarkTodoItemAsPendingRequest + 6, // 7: todolist.v1.TodoListService.DeleteTodoItem:input_type -> todolist.v1.DeleteTodoItemRequest + 9, // 8: todolist.v1.TodoListService.CreateTodoList:output_type -> google.protobuf.Empty + 2, // 9: todolist.v1.TodoListService.GetTodoList:output_type -> todolist.v1.GetTodoListResponse + 9, // 10: todolist.v1.TodoListService.AddTodoItem:output_type -> google.protobuf.Empty + 9, // 11: todolist.v1.TodoListService.MarkTodoItemAsDone:output_type -> google.protobuf.Empty + 9, // 12: todolist.v1.TodoListService.MarkTodoItemAsPending:output_type -> google.protobuf.Empty + 9, // 13: todolist.v1.TodoListService.DeleteTodoItem:output_type -> google.protobuf.Empty + 8, // [8:14] is the sub-list for method output_type + 2, // [2:8] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_todolist_v1_todo_list_service_proto_init() } @@ -130,25 +610,106 @@ func file_todolist_v1_todo_list_service_proto_init() { if File_todolist_v1_todo_list_service_proto != nil { return } - file_todolist_v1_add_todo_item_request_proto_init() - file_todolist_v1_create_todo_list_request_proto_init() - file_todolist_v1_delete_todo_item_request_proto_init() - file_todolist_v1_get_todo_list_request_proto_init() - file_todolist_v1_get_todo_list_response_proto_init() - file_todolist_v1_mark_todo_item_as_done_request_proto_init() - file_todolist_v1_mark_todo_item_as_pending_request_proto_init() + file_todolist_v1_todo_list_proto_init() + if !protoimpl.UnsafeEnabled { + file_todolist_v1_todo_list_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateTodoListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_todolist_v1_todo_list_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTodoListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_todolist_v1_todo_list_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTodoListResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_todolist_v1_todo_list_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddTodoItemRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_todolist_v1_todo_list_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MarkTodoItemAsDoneRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_todolist_v1_todo_list_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MarkTodoItemAsPendingRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_todolist_v1_todo_list_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteTodoItemRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_todolist_v1_todo_list_service_proto_rawDesc, NumEnums: 0, - NumMessages: 0, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, GoTypes: file_todolist_v1_todo_list_service_proto_goTypes, DependencyIndexes: file_todolist_v1_todo_list_service_proto_depIdxs, + MessageInfos: file_todolist_v1_todo_list_service_proto_msgTypes, }.Build() File_todolist_v1_todo_list_service_proto = out.File file_todolist_v1_todo_list_service_proto_rawDesc = nil diff --git a/examples/todolist/proto/todolist/v1/add_todo_item_request.proto b/examples/todolist/proto/todolist/v1/add_todo_item_request.proto deleted file mode 100644 index 28643617..00000000 --- a/examples/todolist/proto/todolist/v1/add_todo_item_request.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -import "google/protobuf/timestamp.proto"; - -// AddTodoItemRequest adds a new TodoItem to an existing TodoList. -// -// The todo_item_id is client-generated, same as in CreateTodoListRequest. -message AddTodoItemRequest { - // UUID of the target list. - string todo_list_id = 1; - // Client-generated UUID for the new item. - string todo_item_id = 2; - // Short title of the item. - string title = 3; - // Free-form description of the item. - string description = 4; - // Optional due date; omit for no due date. - google.protobuf.Timestamp due_date = 5; -} diff --git a/examples/todolist/proto/todolist/v1/create_todo_list_request.proto b/examples/todolist/proto/todolist/v1/create_todo_list_request.proto deleted file mode 100644 index 1a57efd6..00000000 --- a/examples/todolist/proto/todolist/v1/create_todo_list_request.proto +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -// CreateTodoListRequest creates a new TodoList with the specified ID. -// -// The todo_list_id is client-generated: clients are expected to generate a -// UUID and pass it in the request. This keeps the command idempotent and -// frees the response of a payload. -message CreateTodoListRequest { - // Client-generated UUID for the new list. - string todo_list_id = 1; - // Display title of the list. - string title = 2; - // Owner identifier. - string owner = 3; -} diff --git a/examples/todolist/proto/todolist/v1/delete_todo_item_request.proto b/examples/todolist/proto/todolist/v1/delete_todo_item_request.proto deleted file mode 100644 index 6b3586bf..00000000 --- a/examples/todolist/proto/todolist/v1/delete_todo_item_request.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -// DeleteTodoItemRequest removes an item from a TodoList. -message DeleteTodoItemRequest { - // UUID of the list that owns the item. - string todo_list_id = 1; - // UUID of the item to delete. - string todo_item_id = 2; -} diff --git a/examples/todolist/proto/todolist/v1/get_todo_list_request.proto b/examples/todolist/proto/todolist/v1/get_todo_list_request.proto deleted file mode 100644 index f0b38303..00000000 --- a/examples/todolist/proto/todolist/v1/get_todo_list_request.proto +++ /dev/null @@ -1,9 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -// GetTodoListRequest fetches a TodoList by its ID. -message GetTodoListRequest { - // UUID of the list to fetch. - string todo_list_id = 1; -} diff --git a/examples/todolist/proto/todolist/v1/get_todo_list_response.proto b/examples/todolist/proto/todolist/v1/get_todo_list_response.proto deleted file mode 100644 index 73f94a59..00000000 --- a/examples/todolist/proto/todolist/v1/get_todo_list_response.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -import "todolist/v1/todo_list.proto"; - -// GetTodoListResponse contains the requested TodoList. -message GetTodoListResponse { - // The requested list. - TodoList todo_list = 1; -} diff --git a/examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto b/examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto deleted file mode 100644 index effc89c3..00000000 --- a/examples/todolist/proto/todolist/v1/mark_todo_item_as_done_request.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -// MarkTodoItemAsDoneRequest marks an item in a TodoList as completed. -message MarkTodoItemAsDoneRequest { - // UUID of the list that owns the item. - string todo_list_id = 1; - // UUID of the item to mark as done. - string todo_item_id = 2; -} diff --git a/examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto b/examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto deleted file mode 100644 index 9074db88..00000000 --- a/examples/todolist/proto/todolist/v1/mark_todo_item_as_pending_request.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; - -package todolist.v1; - -// MarkTodoItemAsPendingRequest marks an item in a TodoList as pending -// (i.e., undoes a previous "mark as done"). -message MarkTodoItemAsPendingRequest { - // UUID of the list that owns the item. - string todo_list_id = 1; - // UUID of the item to mark as pending. - string todo_item_id = 2; -} diff --git a/examples/todolist/proto/todolist/v1/todo_list_service.proto b/examples/todolist/proto/todolist/v1/todo_list_service.proto index 03f6eb09..a57020d9 100644 --- a/examples/todolist/proto/todolist/v1/todo_list_service.proto +++ b/examples/todolist/proto/todolist/v1/todo_list_service.proto @@ -3,13 +3,8 @@ syntax = "proto3"; package todolist.v1; import "google/protobuf/empty.proto"; -import "todolist/v1/add_todo_item_request.proto"; -import "todolist/v1/create_todo_list_request.proto"; -import "todolist/v1/delete_todo_item_request.proto"; -import "todolist/v1/get_todo_list_request.proto"; -import "todolist/v1/get_todo_list_response.proto"; -import "todolist/v1/mark_todo_item_as_done_request.proto"; -import "todolist/v1/mark_todo_item_as_pending_request.proto"; +import "google/protobuf/timestamp.proto"; +import "todolist/v1/todo_list.proto"; // TodoListService exposes TodoList operations over Connect. // @@ -29,3 +24,70 @@ service TodoListService { // DeleteTodoItem removes an item from a TodoList. rpc DeleteTodoItem(DeleteTodoItemRequest) returns (google.protobuf.Empty); } + +// CreateTodoListRequest creates a new TodoList with the specified ID. +// +// The todo_list_id is client-generated: clients are expected to generate a +// UUID and pass it in the request. This keeps the command idempotent and +// frees the response of a payload. +message CreateTodoListRequest { + // Client-generated UUID for the new list. + string todo_list_id = 1; + // Display title of the list. + string title = 2; + // Owner identifier. + string owner = 3; +} + +// GetTodoListRequest fetches a TodoList by its ID. +message GetTodoListRequest { + // UUID of the list to fetch. + string todo_list_id = 1; +} + +// GetTodoListResponse contains the requested TodoList. +message GetTodoListResponse { + // The requested list. + TodoList todo_list = 1; +} + +// AddTodoItemRequest adds a new TodoItem to an existing TodoList. +// +// The todo_item_id is client-generated, same as in CreateTodoListRequest. +message AddTodoItemRequest { + // UUID of the target list. + string todo_list_id = 1; + // Client-generated UUID for the new item. + string todo_item_id = 2; + // Short title of the item. + string title = 3; + // Free-form description of the item. + string description = 4; + // Optional due date; omit for no due date. + google.protobuf.Timestamp due_date = 5; +} + +// MarkTodoItemAsDoneRequest marks an item in a TodoList as completed. +message MarkTodoItemAsDoneRequest { + // UUID of the list that owns the item. + string todo_list_id = 1; + // UUID of the item to mark as done. + string todo_item_id = 2; +} + +// MarkTodoItemAsPendingRequest marks an item in a TodoList as pending +// (i.e., undoes a previous "mark as done"). +message MarkTodoItemAsPendingRequest { + // UUID of the list that owns the item. + string todo_list_id = 1; + // UUID of the item to mark as pending. + string todo_item_id = 2; +} + +// DeleteTodoItemRequest removes an item from a TodoList. +message DeleteTodoItemRequest { + // UUID of the list that owns the item. + string todo_list_id = 1; + // UUID of the item to delete. + string todo_item_id = 2; +} From 823bdb2e08d8599c642a4ce8462cc8ce0d9e597e Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:04:26 +0200 Subject: [PATCH 11/19] chore(examples): migrate buf config to v2 Ran `buf config migrate --module proto --buf-gen-yaml buf.gen.yaml` from the example root, which: - moved proto/buf.yaml up to buf.yaml at the module root and bumped it to v2 schema (modules list now points at proto/); - rewrote buf.gen.yaml to v2 schema (plugin entries moved from `plugin:` to `remote:`; go_package_prefix moved under managed.override); - preserved all lint / breaking rule choices. Also replaced the deprecated DEFAULT lint category with STANDARD per buf's upgrade warning. `buf lint` now runs without any warnings. README.md updated to reference the new `buf generate` command (no longer needs an argument since the v2 config points at proto/). --- examples/todolist/buf.gen.yaml | 12 ++++++------ examples/todolist/buf.yaml | 19 +++++++++++++++++++ examples/todolist/proto/buf.yaml | 11 ----------- 3 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 examples/todolist/buf.yaml delete mode 100644 examples/todolist/proto/buf.yaml diff --git a/examples/todolist/buf.gen.yaml b/examples/todolist/buf.gen.yaml index c7a58099..afbb27c9 100644 --- a/examples/todolist/buf.gen.yaml +++ b/examples/todolist/buf.gen.yaml @@ -1,13 +1,13 @@ ---- -version: v1 +version: v2 managed: enabled: true - go_package_prefix: - default: github.com/get-eventually/go-eventually/examples/todolist/gen + override: + - file_option: go_package_prefix + value: github.com/get-eventually/go-eventually/examples/todolist/gen plugins: - - plugin: buf.build/protocolbuffers/go:v1.31.0 + - remote: buf.build/protocolbuffers/go:v1.31.0 out: gen opt: paths=source_relative - - plugin: buf.build/connectrpc/go:v1.12.0 + - remote: buf.build/connectrpc/go:v1.12.0 out: gen opt: paths=source_relative diff --git a/examples/todolist/buf.yaml b/examples/todolist/buf.yaml new file mode 100644 index 00000000..5381f418 --- /dev/null +++ b/examples/todolist/buf.yaml @@ -0,0 +1,19 @@ +version: v2 +modules: + - path: proto +lint: + use: + - COMMENTS + - PACKAGE_NO_IMPORT_CYCLE + - STANDARD + - UNARY_RPC + except: + - FIELD_NOT_REQUIRED + rpc_allow_google_protobuf_empty_responses: true + disallow_comment_ignores: true +breaking: + use: + - FILE + except: + - EXTENSION_NO_DELETE + - FIELD_SAME_DEFAULT diff --git a/examples/todolist/proto/buf.yaml b/examples/todolist/proto/buf.yaml deleted file mode 100644 index 7af4845e..00000000 --- a/examples/todolist/proto/buf.yaml +++ /dev/null @@ -1,11 +0,0 @@ -version: v1 -breaking: - use: - - FILE -lint: - rpc_allow_google_protobuf_empty_responses: true - use: - - DEFAULT - - COMMENTS - - UNARY_RPC - - PACKAGE_NO_IMPORT_CYCLE From 3e2c0f121b024379f173dabc671eebea79cfa541 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:16:22 +0200 Subject: [PATCH 12/19] refactor(examples): package todolist internals by domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Collapses internal/domain/todolist, internal/command, and internal/query into a single internal/todolist package. All artifacts belonging to the TodoList bounded context now live together; types use the package prefix to stay readable at call sites: old -> new domain.TodoList, .Item, .ID, .ItemID -> todolist.* command.CreateTodoList / Handler -> todolist.CreateCommand todolist.CreateCommandHandler command.AddTodoListItem / Handler -> todolist.AddItemCommand todolist.AddItemCommandHandler query.GetTodoList / Handler -> todolist.GetQuery todolist.GetQueryHandler Command and query test files moved with their code (renames preserved by git; blame stays intact). Transport layers stay separate: - internal/connect keeps the Connect service implementation; - internal/protoconv keeps domain->proto conversions. Both update their imports and references to the new names. Doc.go files from the old command/query packages are gone — the top-level todolist.go now carries the package doc comment. README updated to reflect the 'package by domain' convention. --- examples/todolist/README.md | 22 ++++--- .../internal/command/add_todo_list_item.go | 57 ------------------- .../internal/command/create_todolist.go | 45 --------------- examples/todolist/internal/command/doc.go | 2 - .../todolist/internal/connect/todolist.go | 22 ++++--- .../todolist/internal/protoconv/todolist.go | 2 +- examples/todolist/internal/query/doc.go | 2 - .../todolist/internal/query/get_todo_list.go | 45 --------------- .../internal/todolist/add_item_command.go | 56 ++++++++++++++++++ .../add_item_command_test.go} | 27 +++++---- .../internal/todolist/create_command.go | 44 ++++++++++++++ .../create_command_test.go} | 27 +++++---- .../internal/{domain => }/todolist/event.go | 0 .../todolist/internal/todolist/get_query.go | 44 ++++++++++++++ .../internal/{domain => }/todolist/item.go | 0 .../{domain => }/todolist/repository.go | 0 .../{domain => }/todolist/todolist.go | 12 +++- .../{domain => }/todolist/todolist_test.go | 2 +- 18 files changed, 207 insertions(+), 202 deletions(-) delete mode 100644 examples/todolist/internal/command/add_todo_list_item.go delete mode 100644 examples/todolist/internal/command/create_todolist.go delete mode 100644 examples/todolist/internal/command/doc.go delete mode 100644 examples/todolist/internal/query/doc.go delete mode 100644 examples/todolist/internal/query/get_todo_list.go create mode 100644 examples/todolist/internal/todolist/add_item_command.go rename examples/todolist/internal/{command/add_todo_list_item_test.go => todolist/add_item_command_test.go} (79%) create mode 100644 examples/todolist/internal/todolist/create_command.go rename examples/todolist/internal/{command/create_todolist_test.go => todolist/create_command_test.go} (65%) rename examples/todolist/internal/{domain => }/todolist/event.go (100%) create mode 100644 examples/todolist/internal/todolist/get_query.go rename examples/todolist/internal/{domain => }/todolist/item.go (100%) rename examples/todolist/internal/{domain => }/todolist/repository.go (100%) rename examples/todolist/internal/{domain => }/todolist/todolist.go (92%) rename examples/todolist/internal/{domain => }/todolist/todolist_test.go (98%) diff --git a/examples/todolist/README.md b/examples/todolist/README.md index ba7ec295..563fdb8f 100644 --- a/examples/todolist/README.md +++ b/examples/todolist/README.md @@ -7,13 +7,14 @@ needs rethinking in the library. ## What this example demonstrates -- An aggregate root (`TodoList`) with a child entity (`Item`), built on - `aggregate.BaseRoot` and `aggregate.RecordThat`. -- Commands (`CreateTodoList`, `AddTodoListItem`) implementing - `command.Handler[Cmd]`, persisted through an +- An aggregate root (`todolist.TodoList`) with a child entity + (`todolist.Item`), built on `aggregate.BaseRoot` and + `aggregate.RecordThat`. +- Commands (`todolist.CreateCommand`, `todolist.AddItemCommand`) + implementing `command.Handler[Cmd]`, persisted through an `aggregate.EventSourcedRepository` backed by `event.NewInMemoryStore`. -- A query (`GetTodoList`) implementing `query.Handler[Q, R]`, reusing the - same repository's `Get`. +- A query (`todolist.GetQuery`) implementing `query.Handler[Q, R]`, + reusing the same repository's `Get`. - BDD-style test scenarios using `aggregate.Scenario`, `command.Scenario`, and (implicitly through the command scenarios) the event streaming plumbing. @@ -60,10 +61,17 @@ grpcurl -plaintext -d '{"todo_list_id":"...","title":"chores","owner":"me"}' \ codes (`InvalidArgument`, `AlreadyExists`, `NotFound`, `Internal`) and the full error chain is propagated to the client. A real service would sanitize messages before they cross the wire. +- **Package by domain, not by layer.** All TodoList artifacts (aggregate, + events, commands, queries, handlers) live in a single + `internal/todolist` package. Names like `CreateCommand`, `GetQuery`, + and `AddItemCommandHandler` ride on top of the package prefix to keep + call sites terse and the domain boundary obvious at a glance. Transport + (`internal/connect`) and proto conversion (`internal/protoconv`) stay + in their own packages since they are not domain artifacts. - **`MarkTodoItemAsDone` / `MarkTodoItemAsPending` / `DeleteTodoItem`** exist in the domain but don't yet have command handlers nor wired Connect handlers. Adding them follows the same pattern as - `AddTodoListItem`; left as an exercise / follow-up PR. + `AddItemCommand`; left as an exercise / follow-up PR. ## Regenerating the protos diff --git a/examples/todolist/internal/command/add_todo_list_item.go b/examples/todolist/internal/command/add_todo_list_item.go deleted file mode 100644 index aa692114..00000000 --- a/examples/todolist/internal/command/add_todo_list_item.go +++ /dev/null @@ -1,57 +0,0 @@ -package command - -import ( - "context" - "fmt" - "time" - - "github.com/get-eventually/go-eventually/command" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" -) - -// AddTodoListItem is the Command used to add a new Item to an existing TodoList. -type AddTodoListItem struct { - TodoListID todolist.ID - TodoItemID todolist.ItemID - Title string - Description string - DueDate time.Time -} - -// Name implements message.Message. -func (AddTodoListItem) Name() string { return "AddTodoListItem" } - -//nolint:exhaustruct // Interface implementation assertion. -var _ command.Handler[AddTodoListItem] = AddTodoListItemHandler{} - -// AddTodoListItemHandler is the command.Handler for AddTodoListItem commands. -type AddTodoListItemHandler struct { - Clock func() time.Time - Repository todolist.Repository -} - -// Handle implements command.Handler. -func (h AddTodoListItemHandler) Handle(ctx context.Context, cmd command.Envelope[AddTodoListItem]) error { - todoList, err := h.Repository.Get(ctx, cmd.Message.TodoListID) - if err != nil { - return fmt.Errorf("command.AddTodoListItem: failed to get TodoList from repository, %w", err) - } - - now := h.Clock() - - if err := todoList.AddItem( - cmd.Message.TodoItemID, - cmd.Message.Title, - cmd.Message.Description, - cmd.Message.DueDate, - now, - ); err != nil { - return fmt.Errorf("command.AddTodoListItem: failed to add item to TodoList, %w", err) - } - - if err := h.Repository.Save(ctx, todoList); err != nil { - return fmt.Errorf("command.AddTodoListItem: failed to save new TodoList version, %w", err) - } - - return nil -} diff --git a/examples/todolist/internal/command/create_todolist.go b/examples/todolist/internal/command/create_todolist.go deleted file mode 100644 index 5e6881eb..00000000 --- a/examples/todolist/internal/command/create_todolist.go +++ /dev/null @@ -1,45 +0,0 @@ -package command - -import ( - "context" - "fmt" - "time" - - "github.com/get-eventually/go-eventually/command" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" -) - -// CreateTodoList is the Command used to create a new TodoList. -type CreateTodoList struct { - ID todolist.ID - Title string - Owner string -} - -// Name implements message.Message. -func (CreateTodoList) Name() string { return "CreateTodoList" } - -//nolint:exhaustruct // Interface implementation assertion. -var _ command.Handler[CreateTodoList] = CreateTodoListHandler{} - -// CreateTodoListHandler is the Command Handler for CreateTodoList commands. -type CreateTodoListHandler struct { - Clock func() time.Time - Repository todolist.Saver -} - -// Handle implements command.Handler. -func (h CreateTodoListHandler) Handle(ctx context.Context, cmd command.Envelope[CreateTodoList]) error { - now := h.Clock() - - todoList, err := todolist.Create(cmd.Message.ID, cmd.Message.Title, cmd.Message.Owner, now) - if err != nil { - return fmt.Errorf("command.CreateTodoListHandler: failed to create new todolist, %w", err) - } - - if err := h.Repository.Save(ctx, todoList); err != nil { - return fmt.Errorf("command.CreateTodoListHandler: failed to save todolist to repository, %w", err) - } - - return nil -} diff --git a/examples/todolist/internal/command/doc.go b/examples/todolist/internal/command/doc.go deleted file mode 100644 index df9457ac..00000000 --- a/examples/todolist/internal/command/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package command contains TodoList command definitions and handlers. -package command diff --git a/examples/todolist/internal/connect/todolist.go b/examples/todolist/internal/connect/todolist.go index b912ff3a..f5d73c49 100644 --- a/examples/todolist/internal/connect/todolist.go +++ b/examples/todolist/internal/connect/todolist.go @@ -20,10 +20,8 @@ import ( "github.com/get-eventually/go-eventually/command" todolistv1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1/todolistv1connect" - appcommand "github.com/get-eventually/go-eventually/examples/todolist/internal/command" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" "github.com/get-eventually/go-eventually/examples/todolist/internal/protoconv" - appquery "github.com/get-eventually/go-eventually/examples/todolist/internal/query" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" "github.com/get-eventually/go-eventually/query" ) @@ -39,9 +37,9 @@ var _ todolistv1connect.TodoListServiceHandler = TodoListServiceServer{} type TodoListServiceServer struct { todolistv1connect.UnimplementedTodoListServiceHandler - GetTodoListHandler appquery.GetTodoListHandler - CreateTodoListHandler appcommand.CreateTodoListHandler - AddTodoListHandler appcommand.AddTodoListItemHandler + GetQueryHandler todolist.GetQueryHandler + CreateCommandHandler todolist.CreateCommandHandler + AddItemCommandHandler todolist.AddItemCommandHandler } // parseUUID converts a string field into a uuid.UUID, returning an @@ -95,13 +93,13 @@ func (srv TodoListServiceServer) CreateTodoList( return nil, err } - cmd := command.ToEnvelope(appcommand.CreateTodoList{ + cmd := command.ToEnvelope(todolist.CreateCommand{ ID: todolist.ID(id), Title: req.Msg.Title, Owner: req.Msg.Owner, }) - if err := srv.CreateTodoListHandler.Handle(ctx, cmd); err != nil { + if err := srv.CreateCommandHandler.Handle(ctx, cmd); err != nil { return nil, mapCommandError("connect.CreateTodoList", err) } @@ -118,9 +116,9 @@ func (srv TodoListServiceServer) GetTodoList( return nil, err } - q := query.ToEnvelope(appquery.GetTodoList{ID: todolist.ID(id)}) + q := query.ToEnvelope(todolist.GetQuery{ID: todolist.ID(id)}) - tl, err := srv.GetTodoListHandler.Handle(ctx, q) + tl, err := srv.GetQueryHandler.Handle(ctx, q) if err != nil { return nil, mapCommandError("connect.GetTodoList", err) } @@ -150,7 +148,7 @@ func (srv TodoListServiceServer) AddTodoItem( dueDate = req.Msg.DueDate.AsTime() } - cmd := command.ToEnvelope(appcommand.AddTodoListItem{ + cmd := command.ToEnvelope(todolist.AddItemCommand{ TodoListID: todolist.ID(listID), TodoItemID: todolist.ItemID(itemID), Title: req.Msg.Title, @@ -158,7 +156,7 @@ func (srv TodoListServiceServer) AddTodoItem( DueDate: dueDate, }) - if err := srv.AddTodoListHandler.Handle(ctx, cmd); err != nil { + if err := srv.AddItemCommandHandler.Handle(ctx, cmd); err != nil { return nil, mapCommandError("connect.AddTodoItem", err) } diff --git a/examples/todolist/internal/protoconv/todolist.go b/examples/todolist/internal/protoconv/todolist.go index 30f59238..93953638 100644 --- a/examples/todolist/internal/protoconv/todolist.go +++ b/examples/todolist/internal/protoconv/todolist.go @@ -6,7 +6,7 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" todolistv1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) // FromTodoList converts a TodoList aggregate root into its Protobuf counterpart. diff --git a/examples/todolist/internal/query/doc.go b/examples/todolist/internal/query/doc.go deleted file mode 100644 index c23d5a56..00000000 --- a/examples/todolist/internal/query/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package query contains TodoList query definitions and handlers. -package query diff --git a/examples/todolist/internal/query/get_todo_list.go b/examples/todolist/internal/query/get_todo_list.go deleted file mode 100644 index ad73cf1b..00000000 --- a/examples/todolist/internal/query/get_todo_list.go +++ /dev/null @@ -1,45 +0,0 @@ -package query - -import ( - "context" - "fmt" - - "github.com/google/uuid" - - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" - "github.com/get-eventually/go-eventually/query" -) - -// GetTodoList is a Domain Query used to return a TodoList view. -type GetTodoList struct { - ID todolist.ID -} - -// Name implements message.Message. -func (GetTodoList) Name() string { return "GetTodoList" } - -//nolint:exhaustruct // Interface implementation assertion. -var _ query.Handler[GetTodoList, *todolist.TodoList] = GetTodoListHandler{} - -// GetTodoListHandler handles a GetTodoList query, returning the TodoList -// aggregate root specified by the query. -type GetTodoListHandler struct { - Getter todolist.Getter -} - -// Handle implements query.Handler. -func (h GetTodoListHandler) Handle( - ctx context.Context, - q query.Envelope[GetTodoList], -) (*todolist.TodoList, error) { - if q.Message.ID == todolist.ID(uuid.Nil) { - return nil, fmt.Errorf("query.GetTodoList: invalid query provided, %w", todolist.ErrEmptyID) - } - - tl, err := h.Getter.Get(ctx, q.Message.ID) - if err != nil { - return nil, fmt.Errorf("query.GetTodoList: failed to get TodoList from repository, %w", err) - } - - return tl, nil -} diff --git a/examples/todolist/internal/todolist/add_item_command.go b/examples/todolist/internal/todolist/add_item_command.go new file mode 100644 index 00000000..8fa1dad9 --- /dev/null +++ b/examples/todolist/internal/todolist/add_item_command.go @@ -0,0 +1,56 @@ +package todolist + +import ( + "context" + "fmt" + "time" + + "github.com/get-eventually/go-eventually/command" +) + +// AddItemCommand is the Command used to add a new Item to an existing TodoList. +type AddItemCommand struct { + TodoListID ID + TodoItemID ItemID + Title string + Description string + DueDate time.Time +} + +// Name implements message.Message. +func (AddItemCommand) Name() string { return "AddTodoListItem" } + +//nolint:exhaustruct // Interface implementation assertion. +var _ command.Handler[AddItemCommand] = AddItemCommandHandler{} + +// AddItemCommandHandler is the command.Handler for AddItemCommand commands. +type AddItemCommandHandler struct { + Clock func() time.Time + Repository Repository +} + +// Handle implements command.Handler. +func (h AddItemCommandHandler) Handle(ctx context.Context, cmd command.Envelope[AddItemCommand]) error { + tl, err := h.Repository.Get(ctx, cmd.Message.TodoListID) + if err != nil { + return fmt.Errorf("todolist.AddItemCommandHandler: failed to get TodoList from repository, %w", err) + } + + now := h.Clock() + + if err := tl.AddItem( + cmd.Message.TodoItemID, + cmd.Message.Title, + cmd.Message.Description, + cmd.Message.DueDate, + now, + ); err != nil { + return fmt.Errorf("todolist.AddItemCommandHandler: failed to add item to TodoList, %w", err) + } + + if err := h.Repository.Save(ctx, tl); err != nil { + return fmt.Errorf("todolist.AddItemCommandHandler: failed to save new TodoList version, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/command/add_todo_list_item_test.go b/examples/todolist/internal/todolist/add_item_command_test.go similarity index 79% rename from examples/todolist/internal/command/add_todo_list_item_test.go rename to examples/todolist/internal/todolist/add_item_command_test.go index e570b6b1..9707cdf6 100644 --- a/examples/todolist/internal/command/add_todo_list_item_test.go +++ b/examples/todolist/internal/todolist/add_item_command_test.go @@ -1,4 +1,4 @@ -package command_test +package todolist_test import ( "testing" @@ -9,14 +9,13 @@ import ( "github.com/get-eventually/go-eventually/aggregate" "github.com/get-eventually/go-eventually/command" "github.com/get-eventually/go-eventually/event" - appcommand "github.com/get-eventually/go-eventually/examples/todolist/internal/command" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) -func TestAddTodoListItem(t *testing.T) { +func TestAddItemCommandHandler(t *testing.T) { now := time.Now() - commandHandlerFactory := func(es event.Store) appcommand.AddTodoListItemHandler { - return appcommand.AddTodoListItemHandler{ + commandHandlerFactory := func(es event.Store) todolist.AddItemCommandHandler { + return todolist.AddItemCommandHandler{ Clock: func() time.Time { return now }, Repository: aggregate.NewEventSourcedRepository(es, todolist.Type), } @@ -28,8 +27,8 @@ func TestAddTodoListItem(t *testing.T) { listOwner := "me" t.Run("it fails when the target TodoList does not exist", func(t *testing.T) { - command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). - When(command.ToEnvelope(appcommand.AddTodoListItem{ + command.Scenario[todolist.AddItemCommand, todolist.AddItemCommandHandler](). + When(command.ToEnvelope(todolist.AddItemCommand{ TodoListID: todoListID, TodoItemID: todoItemID, Title: "a todo item that should fail", @@ -41,7 +40,7 @@ func TestAddTodoListItem(t *testing.T) { }) t.Run("it fails when the same item has already been added", func(t *testing.T) { - command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + command.Scenario[todolist.AddItemCommand, todolist.AddItemCommandHandler](). Given(event.Persisted{ StreamID: event.StreamID(todoListID.String()), Version: 1, @@ -62,7 +61,7 @@ func TestAddTodoListItem(t *testing.T) { CreationTime: now, }), }). - When(command.ToEnvelope(appcommand.AddTodoListItem{ + When(command.ToEnvelope(todolist.AddItemCommand{ TodoListID: todoListID, TodoItemID: todoItemID, Title: "uh oh, this is gonna fail", @@ -74,7 +73,7 @@ func TestAddTodoListItem(t *testing.T) { }) t.Run("it fails when the item title is empty", func(t *testing.T) { - command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + command.Scenario[todolist.AddItemCommand, todolist.AddItemCommandHandler](). Given(event.Persisted{ StreamID: event.StreamID(todoListID.String()), Version: 1, @@ -85,7 +84,7 @@ func TestAddTodoListItem(t *testing.T) { CreationTime: now.Add(-2 * time.Minute), }), }). - When(command.ToEnvelope(appcommand.AddTodoListItem{ + When(command.ToEnvelope(todolist.AddItemCommand{ TodoListID: todoListID, TodoItemID: todoItemID, Title: "", @@ -97,7 +96,7 @@ func TestAddTodoListItem(t *testing.T) { }) t.Run("it works", func(t *testing.T) { - command.Scenario[appcommand.AddTodoListItem, appcommand.AddTodoListItemHandler](). + command.Scenario[todolist.AddItemCommand, todolist.AddItemCommandHandler](). Given(event.Persisted{ StreamID: event.StreamID(todoListID.String()), Version: 1, @@ -108,7 +107,7 @@ func TestAddTodoListItem(t *testing.T) { CreationTime: now.Add(-2 * time.Minute), }), }). - When(command.ToEnvelope(appcommand.AddTodoListItem{ + When(command.ToEnvelope(todolist.AddItemCommand{ TodoListID: todoListID, TodoItemID: todoItemID, Title: "a todo item that should succeed", diff --git a/examples/todolist/internal/todolist/create_command.go b/examples/todolist/internal/todolist/create_command.go new file mode 100644 index 00000000..3e8e6ac7 --- /dev/null +++ b/examples/todolist/internal/todolist/create_command.go @@ -0,0 +1,44 @@ +package todolist + +import ( + "context" + "fmt" + "time" + + "github.com/get-eventually/go-eventually/command" +) + +// CreateCommand is the Command used to create a new TodoList. +type CreateCommand struct { + ID ID + Title string + Owner string +} + +// Name implements message.Message. +func (CreateCommand) Name() string { return "CreateTodoList" } + +//nolint:exhaustruct // Interface implementation assertion. +var _ command.Handler[CreateCommand] = CreateCommandHandler{} + +// CreateCommandHandler is the Command Handler for CreateCommand commands. +type CreateCommandHandler struct { + Clock func() time.Time + Repository Saver +} + +// Handle implements command.Handler. +func (h CreateCommandHandler) Handle(ctx context.Context, cmd command.Envelope[CreateCommand]) error { + now := h.Clock() + + tl, err := Create(cmd.Message.ID, cmd.Message.Title, cmd.Message.Owner, now) + if err != nil { + return fmt.Errorf("todolist.CreateCommandHandler: failed to create new todolist, %w", err) + } + + if err := h.Repository.Save(ctx, tl); err != nil { + return fmt.Errorf("todolist.CreateCommandHandler: failed to save todolist to repository, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/command/create_todolist_test.go b/examples/todolist/internal/todolist/create_command_test.go similarity index 65% rename from examples/todolist/internal/command/create_todolist_test.go rename to examples/todolist/internal/todolist/create_command_test.go index 2593b048..3574fb05 100644 --- a/examples/todolist/internal/command/create_todolist_test.go +++ b/examples/todolist/internal/todolist/create_command_test.go @@ -1,4 +1,4 @@ -package command_test +package todolist_test import ( "testing" @@ -9,25 +9,24 @@ import ( "github.com/get-eventually/go-eventually/aggregate" "github.com/get-eventually/go-eventually/command" "github.com/get-eventually/go-eventually/event" - appcommand "github.com/get-eventually/go-eventually/examples/todolist/internal/command" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) -func TestCreateTodoListHandler(t *testing.T) { +func TestCreateCommandHandler(t *testing.T) { id := uuid.New() now := time.Now() clock := func() time.Time { return now } - commandHandlerFactory := func(s event.Store) appcommand.CreateTodoListHandler { - return appcommand.CreateTodoListHandler{ + commandHandlerFactory := func(s event.Store) todolist.CreateCommandHandler { + return todolist.CreateCommandHandler{ Clock: clock, Repository: aggregate.NewEventSourcedRepository(s, todolist.Type), } } t.Run("it fails when an invalid id has been provided", func(t *testing.T) { - command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). - When(command.ToEnvelope(appcommand.CreateTodoList{ + command.Scenario[todolist.CreateCommand, todolist.CreateCommandHandler](). + When(command.ToEnvelope(todolist.CreateCommand{ ID: todolist.ID(uuid.Nil), Title: "my-title", Owner: "owner", @@ -37,8 +36,8 @@ func TestCreateTodoListHandler(t *testing.T) { }) t.Run("it fails when a title has not been provided", func(t *testing.T) { - command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). - When(command.ToEnvelope(appcommand.CreateTodoList{ + command.Scenario[todolist.CreateCommand, todolist.CreateCommandHandler](). + When(command.ToEnvelope(todolist.CreateCommand{ ID: todolist.ID(id), Title: "", Owner: "owner", @@ -48,8 +47,8 @@ func TestCreateTodoListHandler(t *testing.T) { }) t.Run("it fails when an owner has not been provided", func(t *testing.T) { - command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). - When(command.ToEnvelope(appcommand.CreateTodoList{ + command.Scenario[todolist.CreateCommand, todolist.CreateCommandHandler](). + When(command.ToEnvelope(todolist.CreateCommand{ ID: todolist.ID(id), Title: "my-title", Owner: "", @@ -59,8 +58,8 @@ func TestCreateTodoListHandler(t *testing.T) { }) t.Run("it works", func(t *testing.T) { - command.Scenario[appcommand.CreateTodoList, appcommand.CreateTodoListHandler](). - When(command.ToEnvelope(appcommand.CreateTodoList{ + command.Scenario[todolist.CreateCommand, todolist.CreateCommandHandler](). + When(command.ToEnvelope(todolist.CreateCommand{ ID: todolist.ID(id), Title: "my-title", Owner: "owner", diff --git a/examples/todolist/internal/domain/todolist/event.go b/examples/todolist/internal/todolist/event.go similarity index 100% rename from examples/todolist/internal/domain/todolist/event.go rename to examples/todolist/internal/todolist/event.go diff --git a/examples/todolist/internal/todolist/get_query.go b/examples/todolist/internal/todolist/get_query.go new file mode 100644 index 00000000..6ef99982 --- /dev/null +++ b/examples/todolist/internal/todolist/get_query.go @@ -0,0 +1,44 @@ +package todolist + +import ( + "context" + "fmt" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/query" +) + +// GetQuery is the Domain Query used to return a TodoList view. +type GetQuery struct { + ID ID +} + +// Name implements message.Message. +func (GetQuery) Name() string { return "GetTodoList" } + +//nolint:exhaustruct // Interface implementation assertion. +var _ query.Handler[GetQuery, *TodoList] = GetQueryHandler{} + +// GetQueryHandler handles a GetQuery by returning the TodoList specified +// by the query's ID. +type GetQueryHandler struct { + Getter Getter +} + +// Handle implements query.Handler. +func (h GetQueryHandler) Handle( + ctx context.Context, + q query.Envelope[GetQuery], +) (*TodoList, error) { + if q.Message.ID == ID(uuid.Nil) { + return nil, fmt.Errorf("todolist.GetQueryHandler: invalid query provided, %w", ErrEmptyID) + } + + tl, err := h.Getter.Get(ctx, q.Message.ID) + if err != nil { + return nil, fmt.Errorf("todolist.GetQueryHandler: failed to get TodoList from repository, %w", err) + } + + return tl, nil +} diff --git a/examples/todolist/internal/domain/todolist/item.go b/examples/todolist/internal/todolist/item.go similarity index 100% rename from examples/todolist/internal/domain/todolist/item.go rename to examples/todolist/internal/todolist/item.go diff --git a/examples/todolist/internal/domain/todolist/repository.go b/examples/todolist/internal/todolist/repository.go similarity index 100% rename from examples/todolist/internal/domain/todolist/repository.go rename to examples/todolist/internal/todolist/repository.go diff --git a/examples/todolist/internal/domain/todolist/todolist.go b/examples/todolist/internal/todolist/todolist.go similarity index 92% rename from examples/todolist/internal/domain/todolist/todolist.go rename to examples/todolist/internal/todolist/todolist.go index 92a0b06c..dce6d584 100644 --- a/examples/todolist/internal/domain/todolist/todolist.go +++ b/examples/todolist/internal/todolist/todolist.go @@ -1,5 +1,13 @@ -// Package todolist contains the domain types and implementations -// for the TodoList Aggregate Root. +// Package todolist contains everything related to the TodoList bounded +// context: the aggregate root, its domain events, commands, queries, and +// their handlers. +// +// This package follows the "package by domain" convention: all artifacts +// that belong to the TodoList context live together, regardless of whether +// they are conceptually on the command, query, or domain side. Naming is +// used to keep the boundary clear (e.g. CreateCommand / GetQuery), taking +// advantage of the package prefix to avoid repeating "TodoList" in every +// identifier. package todolist import ( diff --git a/examples/todolist/internal/domain/todolist/todolist_test.go b/examples/todolist/internal/todolist/todolist_test.go similarity index 98% rename from examples/todolist/internal/domain/todolist/todolist_test.go rename to examples/todolist/internal/todolist/todolist_test.go index ff466614..aa7997c5 100644 --- a/examples/todolist/internal/domain/todolist/todolist_test.go +++ b/examples/todolist/internal/todolist/todolist_test.go @@ -8,7 +8,7 @@ import ( "github.com/get-eventually/go-eventually/aggregate" "github.com/get-eventually/go-eventually/event" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) func TestTodoList(t *testing.T) { From 1c132dfd52b3606e5d33dd9140a7ed96b52d8f06 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:16:32 +0200 Subject: [PATCH 13/19] refactor(examples): swap zap for slog in the todolist main slog has been in the stdlib since Go 1.21 and is the idiomatic choice for structured logging in Go today. The example has modest logging needs (startup + shutdown messages), so pulling in go.uber.org/zap as a third-party dep no longer earns its keep. Behaviour changes: - logs go to stderr via slog.NewTextHandler at debug level; - slog.SetDefault makes the instance available to any transitive code that calls slog.Info / slog.Debug without wiring; - no more deferred Sync() or platform-specific stderr-sync quirks. go.mod drops go.uber.org/zap and its transitive chain (go.uber.org/multierr). --- examples/todolist/go.mod | 2 -- examples/todolist/go.sum | 6 ------ examples/todolist/main.go | 30 ++++++++++++------------------ 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/examples/todolist/go.mod b/examples/todolist/go.mod index b0425e36..007b39bd 100644 --- a/examples/todolist/go.mod +++ b/examples/todolist/go.mod @@ -9,7 +9,6 @@ require ( github.com/get-eventually/go-eventually v0.0.0 github.com/google/uuid v1.6.0 github.com/kelseyhightower/envconfig v1.4.0 - go.uber.org/zap v1.27.0 golang.org/x/net v0.50.0 google.golang.org/protobuf v1.36.11 ) @@ -18,7 +17,6 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/stretchr/testify v1.11.1 // indirect - go.uber.org/multierr v1.10.0 // indirect golang.org/x/text v0.36.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/examples/todolist/go.sum b/examples/todolist/go.sum index b9191dee..543c6085 100644 --- a/examples/todolist/go.sum +++ b/examples/todolist/go.sum @@ -16,12 +16,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= diff --git a/examples/todolist/main.go b/examples/todolist/main.go index 4b616ea6..165ab397 100644 --- a/examples/todolist/main.go +++ b/examples/todolist/main.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "log/slog" "net/http" "os" "os/signal" @@ -18,17 +19,14 @@ import ( connectgrpchealth "connectrpc.com/grpchealth" connectgrpcreflect "connectrpc.com/grpcreflect" "github.com/kelseyhightower/envconfig" - "go.uber.org/zap" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" "github.com/get-eventually/go-eventually/aggregate" "github.com/get-eventually/go-eventually/event" "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1/todolistv1connect" - "github.com/get-eventually/go-eventually/examples/todolist/internal/command" appconnect "github.com/get-eventually/go-eventually/examples/todolist/internal/connect" - "github.com/get-eventually/go-eventually/examples/todolist/internal/domain/todolist" - "github.com/get-eventually/go-eventually/examples/todolist/internal/query" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) type serverConfig struct { @@ -57,16 +55,12 @@ func run() error { //nolint:funlen // Single linear wire-up of the service; spli return err } - logger, err := zap.NewDevelopment() - if err != nil { - return fmt.Errorf("failed to initialize logger, %w", err) - } - - defer func() { - // Sync can fail on stderr with "invalid argument" on some - // platforms; it's safe to ignore at shutdown. - _ = logger.Sync() //nolint:errcheck // See comment above. - }() + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ + Level: slog.LevelDebug, + AddSource: false, + ReplaceAttr: nil, + })) + slog.SetDefault(logger) // In-memory plumbing: a single Store feeds both the command and query // sides through an EventSourcedRepository. @@ -75,14 +69,14 @@ func run() error { //nolint:funlen // Single linear wire-up of the service; spli server := appconnect.TodoListServiceServer{ UnimplementedTodoListServiceHandler: todolistv1connect.UnimplementedTodoListServiceHandler{}, - GetTodoListHandler: query.GetTodoListHandler{ + GetQueryHandler: todolist.GetQueryHandler{ Getter: todoListRepository, }, - CreateTodoListHandler: command.CreateTodoListHandler{ + CreateCommandHandler: todolist.CreateCommandHandler{ Clock: time.Now, Repository: todoListRepository, }, - AddTodoListHandler: command.AddTodoListItemHandler{ + AddItemCommandHandler: todolist.AddItemCommandHandler{ Clock: time.Now, Repository: todoListRepository, }, @@ -114,7 +108,7 @@ func run() error { //nolint:funlen // Single linear wire-up of the service; spli serverErrs := make(chan error, 1) go func() { - logger.Sugar().Infow("connect server started", "address", cfg.Server.Address) + logger.Info("connect server started", slog.String("address", cfg.Server.Address)) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { serverErrs <- fmt.Errorf("connect server exited unexpectedly, %w", err) From 63fbeca1139dbacca87d2707ffd38d596d725453 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:21:13 +0200 Subject: [PATCH 14/19] refactor(examples): fold connect + protoconv into todolist package Extends the package-by-domain reorganisation to the transport and conversion layers. internal/connect and internal/protoconv are gone; their content now lives in the same internal/todolist package as the aggregate, commands, and queries. Naming rides the package prefix: connect.TodoListServiceServer -> todolist.ConnectServiceHandler connect.parseUUID -> todolist.parseUUIDField (unexported) connect.mapCommandError -> todolist.mapCommandError (unexported) protoconv.FromTodoList -> todolist.ToProto The Connect service handler no longer needs a local import alias for aggregate / command / query types since they live in the same package; the file becomes markedly shorter. ToProto drops the trailing TodoList suffix: within the todolist package it is unambiguous. main.go loses the appconnect import alias; the server value is built directly as todolist.ConnectServiceHandler. README's 'package by domain' paragraph updated to reflect the fuller scope (transport and conversion now folded in too). --- examples/todolist/README.md | 14 ++-- .../connect_handler.go} | 83 +++++++++---------- .../todolist.go => todolist/proto.go} | 9 +- examples/todolist/main.go | 3 +- 4 files changed, 48 insertions(+), 61 deletions(-) rename examples/todolist/internal/{connect/todolist.go => todolist/connect_handler.go} (63%) rename examples/todolist/internal/{protoconv/todolist.go => todolist/proto.go} (70%) diff --git a/examples/todolist/README.md b/examples/todolist/README.md index 563fdb8f..f8c17274 100644 --- a/examples/todolist/README.md +++ b/examples/todolist/README.md @@ -61,13 +61,13 @@ grpcurl -plaintext -d '{"todo_list_id":"...","title":"chores","owner":"me"}' \ codes (`InvalidArgument`, `AlreadyExists`, `NotFound`, `Internal`) and the full error chain is propagated to the client. A real service would sanitize messages before they cross the wire. -- **Package by domain, not by layer.** All TodoList artifacts (aggregate, - events, commands, queries, handlers) live in a single - `internal/todolist` package. Names like `CreateCommand`, `GetQuery`, - and `AddItemCommandHandler` ride on top of the package prefix to keep - call sites terse and the domain boundary obvious at a glance. Transport - (`internal/connect`) and proto conversion (`internal/protoconv`) stay - in their own packages since they are not domain artifacts. +- **Package by domain, not by layer.** Everything TodoList-related — + aggregate, events, commands, queries, handlers, Connect transport, + proto conversion — lives in a single `internal/todolist` package. Names + like `CreateCommand`, `GetQuery`, `AddItemCommandHandler`, + `ConnectServiceHandler`, and `ToProto` ride on top of the package + prefix to keep call sites terse and the domain boundary obvious at a + glance. - **`MarkTodoItemAsDone` / `MarkTodoItemAsPending` / `DeleteTodoItem`** exist in the domain but don't yet have command handlers nor wired Connect handlers. Adding them follows the same pattern as diff --git a/examples/todolist/internal/connect/todolist.go b/examples/todolist/internal/todolist/connect_handler.go similarity index 63% rename from examples/todolist/internal/connect/todolist.go rename to examples/todolist/internal/todolist/connect_handler.go index f5d73c49..a931ae84 100644 --- a/examples/todolist/internal/connect/todolist.go +++ b/examples/todolist/internal/todolist/connect_handler.go @@ -1,10 +1,4 @@ -// Package connect contains the Connect server implementation for the TodoList -// service. -// -// This package deliberately uses the import alias "connect" for -// connectrpc.com/connect to match the framework's own naming; the package -// name is kept short because it exclusively hosts the Connect transport. -package connect +package todolist import ( "context" @@ -20,36 +14,33 @@ import ( "github.com/get-eventually/go-eventually/command" todolistv1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1/todolistv1connect" - "github.com/get-eventually/go-eventually/examples/todolist/internal/protoconv" - "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" "github.com/get-eventually/go-eventually/query" ) //nolint:exhaustruct // Interface implementation assertion. -var _ todolistv1connect.TodoListServiceHandler = TodoListServiceServer{} +var _ todolistv1connect.TodoListServiceHandler = ConnectServiceHandler{} -// TodoListServiceServer is the Connect server implementation for the TodoList -// service. +// ConnectServiceHandler is the Connect transport for the TodoList service. // // Clients generate IDs for new resources and pass them in the request; the // server responds to commands with google.protobuf.Empty. This keeps // commands idempotent and free of response-payload coupling. -type TodoListServiceServer struct { +type ConnectServiceHandler struct { todolistv1connect.UnimplementedTodoListServiceHandler - GetQueryHandler todolist.GetQueryHandler - CreateCommandHandler todolist.CreateCommandHandler - AddItemCommandHandler todolist.AddItemCommandHandler + GetQueryHandler GetQueryHandler + CreateCommandHandler CreateCommandHandler + AddItemCommandHandler AddItemCommandHandler } -// parseUUID converts a string field into a uuid.UUID, returning an +// parseUUIDField converts a string field into a uuid.UUID, returning an // InvalidArgument Connect error on failure. -func parseUUID(field, value string) (uuid.UUID, error) { +func parseUUIDField(field, value string) (uuid.UUID, error) { id, err := uuid.Parse(value) if err != nil { return uuid.Nil, connect.NewError( connect.CodeInvalidArgument, - fmt.Errorf("connect: failed to parse %s as uuid, %w", field, err), + fmt.Errorf("todolist.ConnectServiceHandler: failed to parse %s as uuid, %w", field, err), ) } @@ -65,17 +56,17 @@ func mapCommandError(op string, err error) *connect.Error { code := connect.CodeInternal switch { - case errors.Is(err, todolist.ErrEmptyID), - errors.Is(err, todolist.ErrEmptyTitle), - errors.Is(err, todolist.ErrNoOwnerSpecified), - errors.Is(err, todolist.ErrEmptyItemID), - errors.Is(err, todolist.ErrEmptyItemTitle): + case errors.Is(err, ErrEmptyID), + errors.Is(err, ErrEmptyTitle), + errors.Is(err, ErrNoOwnerSpecified), + errors.Is(err, ErrEmptyItemID), + errors.Is(err, ErrEmptyItemTitle): code = connect.CodeInvalidArgument - case errors.Is(err, todolist.ErrItemAlreadyExists): + case errors.Is(err, ErrItemAlreadyExists): code = connect.CodeAlreadyExists - case errors.Is(err, todolist.ErrItemNotFound), + case errors.Is(err, ErrItemNotFound), errors.Is(err, aggregate.ErrRootNotFound): code = connect.CodeNotFound } @@ -84,61 +75,61 @@ func mapCommandError(op string, err error) *connect.Error { } // CreateTodoList implements the Connect service handler. -func (srv TodoListServiceServer) CreateTodoList( +func (srv ConnectServiceHandler) CreateTodoList( ctx context.Context, req *connect.Request[todolistv1.CreateTodoListRequest], ) (*connect.Response[emptypb.Empty], error) { - id, err := parseUUID("todo_list_id", req.Msg.TodoListId) + id, err := parseUUIDField("todo_list_id", req.Msg.TodoListId) if err != nil { return nil, err } - cmd := command.ToEnvelope(todolist.CreateCommand{ - ID: todolist.ID(id), + cmd := command.ToEnvelope(CreateCommand{ + ID: ID(id), Title: req.Msg.Title, Owner: req.Msg.Owner, }) if err := srv.CreateCommandHandler.Handle(ctx, cmd); err != nil { - return nil, mapCommandError("connect.CreateTodoList", err) + return nil, mapCommandError("todolist.ConnectServiceHandler.CreateTodoList", err) } return connect.NewResponse(&emptypb.Empty{}), nil } // GetTodoList implements the Connect service handler. -func (srv TodoListServiceServer) GetTodoList( +func (srv ConnectServiceHandler) GetTodoList( ctx context.Context, req *connect.Request[todolistv1.GetTodoListRequest], ) (*connect.Response[todolistv1.GetTodoListResponse], error) { - id, err := parseUUID("todo_list_id", req.Msg.TodoListId) + id, err := parseUUIDField("todo_list_id", req.Msg.TodoListId) if err != nil { return nil, err } - q := query.ToEnvelope(todolist.GetQuery{ID: todolist.ID(id)}) + q := query.ToEnvelope(GetQuery{ID: ID(id)}) tl, err := srv.GetQueryHandler.Handle(ctx, q) if err != nil { - return nil, mapCommandError("connect.GetTodoList", err) + return nil, mapCommandError("todolist.ConnectServiceHandler.GetTodoList", err) } return connect.NewResponse(&todolistv1.GetTodoListResponse{ - TodoList: protoconv.FromTodoList(tl), + TodoList: ToProto(tl), }), nil } // AddTodoItem implements the Connect service handler. -func (srv TodoListServiceServer) AddTodoItem( +func (srv ConnectServiceHandler) AddTodoItem( ctx context.Context, req *connect.Request[todolistv1.AddTodoItemRequest], ) (*connect.Response[emptypb.Empty], error) { - listID, err := parseUUID("todo_list_id", req.Msg.TodoListId) + listID, err := parseUUIDField("todo_list_id", req.Msg.TodoListId) if err != nil { return nil, err } - itemID, err := parseUUID("todo_item_id", req.Msg.TodoItemId) + itemID, err := parseUUIDField("todo_item_id", req.Msg.TodoItemId) if err != nil { return nil, err } @@ -148,16 +139,16 @@ func (srv TodoListServiceServer) AddTodoItem( dueDate = req.Msg.DueDate.AsTime() } - cmd := command.ToEnvelope(todolist.AddItemCommand{ - TodoListID: todolist.ID(listID), - TodoItemID: todolist.ItemID(itemID), + cmd := command.ToEnvelope(AddItemCommand{ + TodoListID: ID(listID), + TodoItemID: ItemID(itemID), Title: req.Msg.Title, Description: req.Msg.Description, DueDate: dueDate, }) if err := srv.AddItemCommandHandler.Handle(ctx, cmd); err != nil { - return nil, mapCommandError("connect.AddTodoItem", err) + return nil, mapCommandError("todolist.ConnectServiceHandler.AddTodoItem", err) } return connect.NewResponse(&emptypb.Empty{}), nil @@ -167,7 +158,7 @@ func (srv TodoListServiceServer) AddTodoItem( // // Not wired up yet in the example: the corresponding command handler is not // yet defined, so this returns Unimplemented to be explicit about it. -func (srv TodoListServiceServer) MarkTodoItemAsDone( +func (srv ConnectServiceHandler) MarkTodoItemAsDone( _ context.Context, _ *connect.Request[todolistv1.MarkTodoItemAsDoneRequest], ) (*connect.Response[emptypb.Empty], error) { @@ -177,7 +168,7 @@ func (srv TodoListServiceServer) MarkTodoItemAsDone( // MarkTodoItemAsPending implements the Connect service handler. // // Not wired up yet in the example: see MarkTodoItemAsDone. -func (srv TodoListServiceServer) MarkTodoItemAsPending( +func (srv ConnectServiceHandler) MarkTodoItemAsPending( _ context.Context, _ *connect.Request[todolistv1.MarkTodoItemAsPendingRequest], ) (*connect.Response[emptypb.Empty], error) { @@ -187,7 +178,7 @@ func (srv TodoListServiceServer) MarkTodoItemAsPending( // DeleteTodoItem implements the Connect service handler. // // Not wired up yet in the example: see MarkTodoItemAsDone. -func (srv TodoListServiceServer) DeleteTodoItem( +func (srv ConnectServiceHandler) DeleteTodoItem( _ context.Context, _ *connect.Request[todolistv1.DeleteTodoItemRequest], ) (*connect.Response[emptypb.Empty], error) { diff --git a/examples/todolist/internal/protoconv/todolist.go b/examples/todolist/internal/todolist/proto.go similarity index 70% rename from examples/todolist/internal/protoconv/todolist.go rename to examples/todolist/internal/todolist/proto.go index 93953638..2c183c4f 100644 --- a/examples/todolist/internal/protoconv/todolist.go +++ b/examples/todolist/internal/todolist/proto.go @@ -1,16 +1,13 @@ -// Package protoconv contains conversions between domain types and their -// generated Protobuf counterparts. -package protoconv +package todolist import ( "google.golang.org/protobuf/types/known/timestamppb" todolistv1 "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1" - "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) -// FromTodoList converts a TodoList aggregate root into its Protobuf counterpart. -func FromTodoList(tl *todolist.TodoList) *todolistv1.TodoList { +// ToProto converts a TodoList into its generated Protobuf counterpart. +func ToProto(tl *TodoList) *todolistv1.TodoList { result := &todolistv1.TodoList{ Id: tl.ID.String(), Title: tl.Title, diff --git a/examples/todolist/main.go b/examples/todolist/main.go index 165ab397..12c5a3fe 100644 --- a/examples/todolist/main.go +++ b/examples/todolist/main.go @@ -25,7 +25,6 @@ import ( "github.com/get-eventually/go-eventually/aggregate" "github.com/get-eventually/go-eventually/event" "github.com/get-eventually/go-eventually/examples/todolist/gen/todolist/v1/todolistv1connect" - appconnect "github.com/get-eventually/go-eventually/examples/todolist/internal/connect" "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" ) @@ -67,7 +66,7 @@ func run() error { //nolint:funlen // Single linear wire-up of the service; spli eventStore := event.NewInMemoryStore() todoListRepository := aggregate.NewEventSourcedRepository(eventStore, todolist.Type) - server := appconnect.TodoListServiceServer{ + server := todolist.ConnectServiceHandler{ UnimplementedTodoListServiceHandler: todolistv1connect.UnimplementedTodoListServiceHandler{}, GetQueryHandler: todolist.GetQueryHandler{ Getter: todoListRepository, From 1dd1d8176fafebe1845291bc7891e0bbb7e11d0e Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:29:23 +0200 Subject: [PATCH 15/19] feat(examples): add mark-as-done, mark-as-pending, delete item commands Three new commands complete the TodoList command surface: - MarkItemAsDoneCommand / MarkItemAsDoneCommandHandler - MarkItemAsPendingCommand / MarkItemAsPendingCommandHandler - DeleteItemCommand / DeleteItemCommandHandler Each handler loads the aggregate, dispatches the corresponding domain method (TodoList.MarkItemAsDone / .MarkItemAsPending / .DeleteItem), and persists the new version. No Clock dependency on these handlers since the underlying events do not carry timestamps. Each command ships with four scenario tests using command.Scenario[](): - list not found -> aggregate.ErrRootNotFound - item not found -> todolist.ErrItemNotFound - empty item ID -> todolist.ErrEmptyItemID - happy path -> asserts the expected Persisted event Shared fixture constants (testListTitle, testListOwner) moved to a new fixtures_test.go so the same strings aren't repeated across five test files (the previous add_item_command_test.go also picks them up). --- .../todolist/add_item_command_test.go | 14 +-- .../internal/todolist/delete_item_command.go | 47 ++++++++ .../todolist/delete_item_command_test.go | 96 ++++++++++++++++ .../internal/todolist/fixtures_test.go | 7 ++ .../todolist/mark_item_as_done_command.go | 48 ++++++++ .../mark_item_as_done_command_test.go | 96 ++++++++++++++++ .../todolist/mark_item_as_pending_command.go | 48 ++++++++ .../mark_item_as_pending_command_test.go | 103 ++++++++++++++++++ 8 files changed, 451 insertions(+), 8 deletions(-) create mode 100644 examples/todolist/internal/todolist/delete_item_command.go create mode 100644 examples/todolist/internal/todolist/delete_item_command_test.go create mode 100644 examples/todolist/internal/todolist/fixtures_test.go create mode 100644 examples/todolist/internal/todolist/mark_item_as_done_command.go create mode 100644 examples/todolist/internal/todolist/mark_item_as_done_command_test.go create mode 100644 examples/todolist/internal/todolist/mark_item_as_pending_command.go create mode 100644 examples/todolist/internal/todolist/mark_item_as_pending_command_test.go diff --git a/examples/todolist/internal/todolist/add_item_command_test.go b/examples/todolist/internal/todolist/add_item_command_test.go index 9707cdf6..2fae4ca2 100644 --- a/examples/todolist/internal/todolist/add_item_command_test.go +++ b/examples/todolist/internal/todolist/add_item_command_test.go @@ -23,8 +23,6 @@ func TestAddItemCommandHandler(t *testing.T) { todoListID := todolist.ID(uuid.New()) todoItemID := todolist.ItemID(uuid.New()) - listTitle := "my list" - listOwner := "me" t.Run("it fails when the target TodoList does not exist", func(t *testing.T) { command.Scenario[todolist.AddItemCommand, todolist.AddItemCommandHandler](). @@ -46,8 +44,8 @@ func TestAddItemCommandHandler(t *testing.T) { Version: 1, Envelope: event.ToEnvelope(todolist.WasCreated{ ID: todoListID, - Title: listTitle, - Owner: listOwner, + Title: testListTitle, + Owner: testListOwner, CreationTime: now.Add(-2 * time.Minute), }), }, event.Persisted{ @@ -79,8 +77,8 @@ func TestAddItemCommandHandler(t *testing.T) { Version: 1, Envelope: event.ToEnvelope(todolist.WasCreated{ ID: todoListID, - Title: listTitle, - Owner: listOwner, + Title: testListTitle, + Owner: testListOwner, CreationTime: now.Add(-2 * time.Minute), }), }). @@ -102,8 +100,8 @@ func TestAddItemCommandHandler(t *testing.T) { Version: 1, Envelope: event.ToEnvelope(todolist.WasCreated{ ID: todoListID, - Title: listTitle, - Owner: listOwner, + Title: testListTitle, + Owner: testListOwner, CreationTime: now.Add(-2 * time.Minute), }), }). diff --git a/examples/todolist/internal/todolist/delete_item_command.go b/examples/todolist/internal/todolist/delete_item_command.go new file mode 100644 index 00000000..475e57a9 --- /dev/null +++ b/examples/todolist/internal/todolist/delete_item_command.go @@ -0,0 +1,47 @@ +package todolist + +import ( + "context" + "fmt" + + "github.com/get-eventually/go-eventually/command" +) + +// DeleteItemCommand is the Command used to remove an Item from a TodoList. +type DeleteItemCommand struct { + TodoListID ID + TodoItemID ItemID +} + +// Name implements message.Message. +func (DeleteItemCommand) Name() string { return "DeleteTodoListItem" } + +//nolint:exhaustruct // Interface implementation assertion. +var _ command.Handler[DeleteItemCommand] = DeleteItemCommandHandler{} + +// DeleteItemCommandHandler is the command.Handler for DeleteItemCommand +// commands. +type DeleteItemCommandHandler struct { + Repository Repository +} + +// Handle implements command.Handler. +func (h DeleteItemCommandHandler) Handle( + ctx context.Context, + cmd command.Envelope[DeleteItemCommand], +) error { + tl, err := h.Repository.Get(ctx, cmd.Message.TodoListID) + if err != nil { + return fmt.Errorf("todolist.DeleteItemCommandHandler: failed to get TodoList from repository, %w", err) + } + + if err := tl.DeleteItem(cmd.Message.TodoItemID); err != nil { + return fmt.Errorf("todolist.DeleteItemCommandHandler: failed to delete item, %w", err) + } + + if err := h.Repository.Save(ctx, tl); err != nil { + return fmt.Errorf("todolist.DeleteItemCommandHandler: failed to save new TodoList version, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/todolist/delete_item_command_test.go b/examples/todolist/internal/todolist/delete_item_command_test.go new file mode 100644 index 00000000..5cee26af --- /dev/null +++ b/examples/todolist/internal/todolist/delete_item_command_test.go @@ -0,0 +1,96 @@ +package todolist_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/event" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" +) + +func TestDeleteItemCommandHandler(t *testing.T) { + now := time.Now() + commandHandlerFactory := func(es event.Store) todolist.DeleteItemCommandHandler { + return todolist.DeleteItemCommandHandler{ + Repository: aggregate.NewEventSourcedRepository(es, todolist.Type), + } + } + + todoListID := todolist.ID(uuid.New()) + todoItemID := todolist.ItemID(uuid.New()) + + listCreated := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: testListTitle, + Owner: testListOwner, + CreationTime: now.Add(-2 * time.Minute), + }), + } + itemAdded := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 2, + Envelope: event.ToEnvelope(todolist.ItemWasAdded{ + ID: todoItemID, + Title: "buy groceries", + Description: "", + DueDate: time.Time{}, + CreationTime: now.Add(-time.Minute), + }), + } + + t.Run("it fails when the target TodoList does not exist", func(t *testing.T) { + command.Scenario[todolist.DeleteItemCommand, todolist.DeleteItemCommandHandler](). + When(command.ToEnvelope(todolist.DeleteItemCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + ThenError(aggregate.ErrRootNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item is not in the list", func(t *testing.T) { + command.Scenario[todolist.DeleteItemCommand, todolist.DeleteItemCommandHandler](). + Given(listCreated). + When(command.ToEnvelope(todolist.DeleteItemCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + ThenError(todolist.ErrItemNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item ID is empty", func(t *testing.T) { + command.Scenario[todolist.DeleteItemCommand, todolist.DeleteItemCommandHandler](). + Given(listCreated). + When(command.ToEnvelope(todolist.DeleteItemCommand{ + TodoListID: todoListID, + TodoItemID: todolist.ItemID(uuid.Nil), + })). + ThenError(todolist.ErrEmptyItemID). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it works", func(t *testing.T) { + command.Scenario[todolist.DeleteItemCommand, todolist.DeleteItemCommandHandler](). + Given(listCreated, itemAdded). + When(command.ToEnvelope(todolist.DeleteItemCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + Then(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 3, + Envelope: event.ToEnvelope(todolist.ItemWasDeleted{ + ID: todoItemID, + }), + }). + AssertOn(t, commandHandlerFactory) + }) +} diff --git a/examples/todolist/internal/todolist/fixtures_test.go b/examples/todolist/internal/todolist/fixtures_test.go new file mode 100644 index 00000000..dfd86e97 --- /dev/null +++ b/examples/todolist/internal/todolist/fixtures_test.go @@ -0,0 +1,7 @@ +package todolist_test + +// Shared fixture values used across command scenario tests. +const ( + testListTitle = "my list" + testListOwner = "me" +) diff --git a/examples/todolist/internal/todolist/mark_item_as_done_command.go b/examples/todolist/internal/todolist/mark_item_as_done_command.go new file mode 100644 index 00000000..6409d640 --- /dev/null +++ b/examples/todolist/internal/todolist/mark_item_as_done_command.go @@ -0,0 +1,48 @@ +package todolist + +import ( + "context" + "fmt" + + "github.com/get-eventually/go-eventually/command" +) + +// MarkItemAsDoneCommand is the Command used to mark an Item in a TodoList +// as completed. +type MarkItemAsDoneCommand struct { + TodoListID ID + TodoItemID ItemID +} + +// Name implements message.Message. +func (MarkItemAsDoneCommand) Name() string { return "MarkTodoListItemAsDone" } + +//nolint:exhaustruct // Interface implementation assertion. +var _ command.Handler[MarkItemAsDoneCommand] = MarkItemAsDoneCommandHandler{} + +// MarkItemAsDoneCommandHandler is the command.Handler for +// MarkItemAsDoneCommand commands. +type MarkItemAsDoneCommandHandler struct { + Repository Repository +} + +// Handle implements command.Handler. +func (h MarkItemAsDoneCommandHandler) Handle( + ctx context.Context, + cmd command.Envelope[MarkItemAsDoneCommand], +) error { + tl, err := h.Repository.Get(ctx, cmd.Message.TodoListID) + if err != nil { + return fmt.Errorf("todolist.MarkItemAsDoneCommandHandler: failed to get TodoList from repository, %w", err) + } + + if err := tl.MarkItemAsDone(cmd.Message.TodoItemID); err != nil { + return fmt.Errorf("todolist.MarkItemAsDoneCommandHandler: failed to mark item as done, %w", err) + } + + if err := h.Repository.Save(ctx, tl); err != nil { + return fmt.Errorf("todolist.MarkItemAsDoneCommandHandler: failed to save new TodoList version, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/todolist/mark_item_as_done_command_test.go b/examples/todolist/internal/todolist/mark_item_as_done_command_test.go new file mode 100644 index 00000000..734b5c9d --- /dev/null +++ b/examples/todolist/internal/todolist/mark_item_as_done_command_test.go @@ -0,0 +1,96 @@ +package todolist_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/event" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" +) + +func TestMarkItemAsDoneCommandHandler(t *testing.T) { + now := time.Now() + commandHandlerFactory := func(es event.Store) todolist.MarkItemAsDoneCommandHandler { + return todolist.MarkItemAsDoneCommandHandler{ + Repository: aggregate.NewEventSourcedRepository(es, todolist.Type), + } + } + + todoListID := todolist.ID(uuid.New()) + todoItemID := todolist.ItemID(uuid.New()) + + listCreated := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: testListTitle, + Owner: testListOwner, + CreationTime: now.Add(-2 * time.Minute), + }), + } + itemAdded := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 2, + Envelope: event.ToEnvelope(todolist.ItemWasAdded{ + ID: todoItemID, + Title: "buy groceries", + Description: "", + DueDate: time.Time{}, + CreationTime: now.Add(-time.Minute), + }), + } + + t.Run("it fails when the target TodoList does not exist", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsDoneCommand, todolist.MarkItemAsDoneCommandHandler](). + When(command.ToEnvelope(todolist.MarkItemAsDoneCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + ThenError(aggregate.ErrRootNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item is not in the list", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsDoneCommand, todolist.MarkItemAsDoneCommandHandler](). + Given(listCreated). + When(command.ToEnvelope(todolist.MarkItemAsDoneCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + ThenError(todolist.ErrItemNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item ID is empty", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsDoneCommand, todolist.MarkItemAsDoneCommandHandler](). + Given(listCreated). + When(command.ToEnvelope(todolist.MarkItemAsDoneCommand{ + TodoListID: todoListID, + TodoItemID: todolist.ItemID(uuid.Nil), + })). + ThenError(todolist.ErrEmptyItemID). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it works", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsDoneCommand, todolist.MarkItemAsDoneCommandHandler](). + Given(listCreated, itemAdded). + When(command.ToEnvelope(todolist.MarkItemAsDoneCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + Then(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 3, + Envelope: event.ToEnvelope(todolist.ItemMarkedAsDone{ + ID: todoItemID, + }), + }). + AssertOn(t, commandHandlerFactory) + }) +} diff --git a/examples/todolist/internal/todolist/mark_item_as_pending_command.go b/examples/todolist/internal/todolist/mark_item_as_pending_command.go new file mode 100644 index 00000000..3a279a2d --- /dev/null +++ b/examples/todolist/internal/todolist/mark_item_as_pending_command.go @@ -0,0 +1,48 @@ +package todolist + +import ( + "context" + "fmt" + + "github.com/get-eventually/go-eventually/command" +) + +// MarkItemAsPendingCommand is the Command used to mark an Item in a +// TodoList as pending (i.e. undoing a previous "mark as done"). +type MarkItemAsPendingCommand struct { + TodoListID ID + TodoItemID ItemID +} + +// Name implements message.Message. +func (MarkItemAsPendingCommand) Name() string { return "MarkTodoListItemAsPending" } + +//nolint:exhaustruct // Interface implementation assertion. +var _ command.Handler[MarkItemAsPendingCommand] = MarkItemAsPendingCommandHandler{} + +// MarkItemAsPendingCommandHandler is the command.Handler for +// MarkItemAsPendingCommand commands. +type MarkItemAsPendingCommandHandler struct { + Repository Repository +} + +// Handle implements command.Handler. +func (h MarkItemAsPendingCommandHandler) Handle( + ctx context.Context, + cmd command.Envelope[MarkItemAsPendingCommand], +) error { + tl, err := h.Repository.Get(ctx, cmd.Message.TodoListID) + if err != nil { + return fmt.Errorf("todolist.MarkItemAsPendingCommandHandler: failed to get TodoList from repository, %w", err) + } + + if err := tl.MarkItemAsPending(cmd.Message.TodoItemID); err != nil { + return fmt.Errorf("todolist.MarkItemAsPendingCommandHandler: failed to mark item as pending, %w", err) + } + + if err := h.Repository.Save(ctx, tl); err != nil { + return fmt.Errorf("todolist.MarkItemAsPendingCommandHandler: failed to save new TodoList version, %w", err) + } + + return nil +} diff --git a/examples/todolist/internal/todolist/mark_item_as_pending_command_test.go b/examples/todolist/internal/todolist/mark_item_as_pending_command_test.go new file mode 100644 index 00000000..7a3dca6b --- /dev/null +++ b/examples/todolist/internal/todolist/mark_item_as_pending_command_test.go @@ -0,0 +1,103 @@ +package todolist_test + +import ( + "testing" + "time" + + "github.com/google/uuid" + + "github.com/get-eventually/go-eventually/aggregate" + "github.com/get-eventually/go-eventually/command" + "github.com/get-eventually/go-eventually/event" + "github.com/get-eventually/go-eventually/examples/todolist/internal/todolist" +) + +func TestMarkItemAsPendingCommandHandler(t *testing.T) { + now := time.Now() + commandHandlerFactory := func(es event.Store) todolist.MarkItemAsPendingCommandHandler { + return todolist.MarkItemAsPendingCommandHandler{ + Repository: aggregate.NewEventSourcedRepository(es, todolist.Type), + } + } + + todoListID := todolist.ID(uuid.New()) + todoItemID := todolist.ItemID(uuid.New()) + + listCreated := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 1, + Envelope: event.ToEnvelope(todolist.WasCreated{ + ID: todoListID, + Title: testListTitle, + Owner: testListOwner, + CreationTime: now.Add(-2 * time.Minute), + }), + } + itemAdded := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 2, + Envelope: event.ToEnvelope(todolist.ItemWasAdded{ + ID: todoItemID, + Title: "buy groceries", + Description: "", + DueDate: time.Time{}, + CreationTime: now.Add(-time.Minute), + }), + } + itemMarkedAsDone := event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 3, + Envelope: event.ToEnvelope(todolist.ItemMarkedAsDone{ + ID: todoItemID, + }), + } + + t.Run("it fails when the target TodoList does not exist", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsPendingCommand, todolist.MarkItemAsPendingCommandHandler](). + When(command.ToEnvelope(todolist.MarkItemAsPendingCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + ThenError(aggregate.ErrRootNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item is not in the list", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsPendingCommand, todolist.MarkItemAsPendingCommandHandler](). + Given(listCreated). + When(command.ToEnvelope(todolist.MarkItemAsPendingCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + ThenError(todolist.ErrItemNotFound). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it fails when the item ID is empty", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsPendingCommand, todolist.MarkItemAsPendingCommandHandler](). + Given(listCreated). + When(command.ToEnvelope(todolist.MarkItemAsPendingCommand{ + TodoListID: todoListID, + TodoItemID: todolist.ItemID(uuid.Nil), + })). + ThenError(todolist.ErrEmptyItemID). + AssertOn(t, commandHandlerFactory) + }) + + t.Run("it works after an item has been marked as done", func(t *testing.T) { + command.Scenario[todolist.MarkItemAsPendingCommand, todolist.MarkItemAsPendingCommandHandler](). + Given(listCreated, itemAdded, itemMarkedAsDone). + When(command.ToEnvelope(todolist.MarkItemAsPendingCommand{ + TodoListID: todoListID, + TodoItemID: todoItemID, + })). + Then(event.Persisted{ + StreamID: event.StreamID(todoListID.String()), + Version: 4, + Envelope: event.ToEnvelope(todolist.ItemMarkedAsPending{ + ID: todoItemID, + }), + }). + AssertOn(t, commandHandlerFactory) + }) +} From 6e53061282293174952b273177661225d5bea45a Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 21:29:34 +0200 Subject: [PATCH 16/19] feat(examples): wire new commands into ConnectServiceHandler Replaces the three Unimplemented methods on ConnectServiceHandler with real implementations: - MarkTodoItemAsDone dispatches MarkItemAsDoneCommand - MarkTodoItemAsPending dispatches MarkItemAsPendingCommand - DeleteTodoItem dispatches DeleteItemCommand ConnectServiceHandler now carries six handler fields. Extracted a parseListAndItemIDs helper to avoid duplicating the (todo_list_id, todo_item_id) parsing dance across three otherwise identical methods. Two small consequences of the struct growth: - method receivers switched from value to pointer (the struct is now 112 bytes, past gocritic's hugeParam threshold); - interface-implementation assertion switched from the value-receiver form to (*ConnectServiceHandler)(nil), which also drops the //nolint:exhaustruct directive. main.go builds a *ConnectServiceHandler and wires in all three new handler dependencies alongside Create / AddItem / Get. README: drop the bullet noting these RPCs were unimplemented. --- examples/todolist/README.md | 4 - .../internal/todolist/connect_handler.go | 107 +++++++++++++----- examples/todolist/main.go | 11 +- 3 files changed, 90 insertions(+), 32 deletions(-) diff --git a/examples/todolist/README.md b/examples/todolist/README.md index f8c17274..f7bad69c 100644 --- a/examples/todolist/README.md +++ b/examples/todolist/README.md @@ -68,10 +68,6 @@ grpcurl -plaintext -d '{"todo_list_id":"...","title":"chores","owner":"me"}' \ `ConnectServiceHandler`, and `ToProto` ride on top of the package prefix to keep call sites terse and the domain boundary obvious at a glance. -- **`MarkTodoItemAsDone` / `MarkTodoItemAsPending` / `DeleteTodoItem`** - exist in the domain but don't yet have command handlers nor wired - Connect handlers. Adding them follows the same pattern as - `AddItemCommand`; left as an exercise / follow-up PR. ## Regenerating the protos diff --git a/examples/todolist/internal/todolist/connect_handler.go b/examples/todolist/internal/todolist/connect_handler.go index a931ae84..8a9d634a 100644 --- a/examples/todolist/internal/todolist/connect_handler.go +++ b/examples/todolist/internal/todolist/connect_handler.go @@ -17,8 +17,7 @@ import ( "github.com/get-eventually/go-eventually/query" ) -//nolint:exhaustruct // Interface implementation assertion. -var _ todolistv1connect.TodoListServiceHandler = ConnectServiceHandler{} +var _ todolistv1connect.TodoListServiceHandler = (*ConnectServiceHandler)(nil) // ConnectServiceHandler is the Connect transport for the TodoList service. // @@ -28,9 +27,12 @@ var _ todolistv1connect.TodoListServiceHandler = ConnectServiceHandler{} type ConnectServiceHandler struct { todolistv1connect.UnimplementedTodoListServiceHandler - GetQueryHandler GetQueryHandler - CreateCommandHandler CreateCommandHandler - AddItemCommandHandler AddItemCommandHandler + GetQueryHandler GetQueryHandler + CreateCommandHandler CreateCommandHandler + AddItemCommandHandler AddItemCommandHandler + MarkItemAsDoneCommandHandler MarkItemAsDoneCommandHandler + MarkItemAsPendingCommandHandler MarkItemAsPendingCommandHandler + DeleteItemCommandHandler DeleteItemCommandHandler } // parseUUIDField converts a string field into a uuid.UUID, returning an @@ -75,7 +77,7 @@ func mapCommandError(op string, err error) *connect.Error { } // CreateTodoList implements the Connect service handler. -func (srv ConnectServiceHandler) CreateTodoList( +func (srv *ConnectServiceHandler) CreateTodoList( ctx context.Context, req *connect.Request[todolistv1.CreateTodoListRequest], ) (*connect.Response[emptypb.Empty], error) { @@ -98,7 +100,7 @@ func (srv ConnectServiceHandler) CreateTodoList( } // GetTodoList implements the Connect service handler. -func (srv ConnectServiceHandler) GetTodoList( +func (srv *ConnectServiceHandler) GetTodoList( ctx context.Context, req *connect.Request[todolistv1.GetTodoListRequest], ) (*connect.Response[todolistv1.GetTodoListResponse], error) { @@ -120,7 +122,7 @@ func (srv ConnectServiceHandler) GetTodoList( } // AddTodoItem implements the Connect service handler. -func (srv ConnectServiceHandler) AddTodoItem( +func (srv *ConnectServiceHandler) AddTodoItem( ctx context.Context, req *connect.Request[todolistv1.AddTodoItemRequest], ) (*connect.Response[emptypb.Empty], error) { @@ -154,33 +156,84 @@ func (srv ConnectServiceHandler) AddTodoItem( return connect.NewResponse(&emptypb.Empty{}), nil } +// parseListAndItemIDs extracts and validates both UUID identifiers that +// appear in every per-item request. +func parseListAndItemIDs(todoListID, todoItemID string) (ID, ItemID, error) { + listID, err := parseUUIDField("todo_list_id", todoListID) + if err != nil { + return ID(uuid.Nil), ItemID(uuid.Nil), err + } + + itemID, err := parseUUIDField("todo_item_id", todoItemID) + if err != nil { + return ID(uuid.Nil), ItemID(uuid.Nil), err + } + + return ID(listID), ItemID(itemID), nil +} + // MarkTodoItemAsDone implements the Connect service handler. -// -// Not wired up yet in the example: the corresponding command handler is not -// yet defined, so this returns Unimplemented to be explicit about it. -func (srv ConnectServiceHandler) MarkTodoItemAsDone( - _ context.Context, - _ *connect.Request[todolistv1.MarkTodoItemAsDoneRequest], +func (srv *ConnectServiceHandler) MarkTodoItemAsDone( + ctx context.Context, + req *connect.Request[todolistv1.MarkTodoItemAsDoneRequest], ) (*connect.Response[emptypb.Empty], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("mark-as-done not implemented")) + listID, itemID, err := parseListAndItemIDs(req.Msg.TodoListId, req.Msg.TodoItemId) + if err != nil { + return nil, err + } + + cmd := command.ToEnvelope(MarkItemAsDoneCommand{ + TodoListID: listID, + TodoItemID: itemID, + }) + + if err := srv.MarkItemAsDoneCommandHandler.Handle(ctx, cmd); err != nil { + return nil, mapCommandError("todolist.ConnectServiceHandler.MarkTodoItemAsDone", err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil } // MarkTodoItemAsPending implements the Connect service handler. -// -// Not wired up yet in the example: see MarkTodoItemAsDone. -func (srv ConnectServiceHandler) MarkTodoItemAsPending( - _ context.Context, - _ *connect.Request[todolistv1.MarkTodoItemAsPendingRequest], +func (srv *ConnectServiceHandler) MarkTodoItemAsPending( + ctx context.Context, + req *connect.Request[todolistv1.MarkTodoItemAsPendingRequest], ) (*connect.Response[emptypb.Empty], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("mark-as-pending not implemented")) + listID, itemID, err := parseListAndItemIDs(req.Msg.TodoListId, req.Msg.TodoItemId) + if err != nil { + return nil, err + } + + cmd := command.ToEnvelope(MarkItemAsPendingCommand{ + TodoListID: listID, + TodoItemID: itemID, + }) + + if err := srv.MarkItemAsPendingCommandHandler.Handle(ctx, cmd); err != nil { + return nil, mapCommandError("todolist.ConnectServiceHandler.MarkTodoItemAsPending", err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil } // DeleteTodoItem implements the Connect service handler. -// -// Not wired up yet in the example: see MarkTodoItemAsDone. -func (srv ConnectServiceHandler) DeleteTodoItem( - _ context.Context, - _ *connect.Request[todolistv1.DeleteTodoItemRequest], +func (srv *ConnectServiceHandler) DeleteTodoItem( + ctx context.Context, + req *connect.Request[todolistv1.DeleteTodoItemRequest], ) (*connect.Response[emptypb.Empty], error) { - return nil, connect.NewError(connect.CodeUnimplemented, errors.New("delete not implemented")) + listID, itemID, err := parseListAndItemIDs(req.Msg.TodoListId, req.Msg.TodoItemId) + if err != nil { + return nil, err + } + + cmd := command.ToEnvelope(DeleteItemCommand{ + TodoListID: listID, + TodoItemID: itemID, + }) + + if err := srv.DeleteItemCommandHandler.Handle(ctx, cmd); err != nil { + return nil, mapCommandError("todolist.ConnectServiceHandler.DeleteTodoItem", err) + } + + return connect.NewResponse(&emptypb.Empty{}), nil } diff --git a/examples/todolist/main.go b/examples/todolist/main.go index 12c5a3fe..8497f29d 100644 --- a/examples/todolist/main.go +++ b/examples/todolist/main.go @@ -66,7 +66,7 @@ func run() error { //nolint:funlen // Single linear wire-up of the service; spli eventStore := event.NewInMemoryStore() todoListRepository := aggregate.NewEventSourcedRepository(eventStore, todolist.Type) - server := todolist.ConnectServiceHandler{ + server := &todolist.ConnectServiceHandler{ UnimplementedTodoListServiceHandler: todolistv1connect.UnimplementedTodoListServiceHandler{}, GetQueryHandler: todolist.GetQueryHandler{ Getter: todoListRepository, @@ -79,6 +79,15 @@ func run() error { //nolint:funlen // Single linear wire-up of the service; spli Clock: time.Now, Repository: todoListRepository, }, + MarkItemAsDoneCommandHandler: todolist.MarkItemAsDoneCommandHandler{ + Repository: todoListRepository, + }, + MarkItemAsPendingCommandHandler: todolist.MarkItemAsPendingCommandHandler{ + Repository: todoListRepository, + }, + DeleteItemCommandHandler: todolist.DeleteItemCommandHandler{ + Repository: todoListRepository, + }, } mux := http.NewServeMux() From 266ff1d7c753719e240d086f405bef6534250b8c Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 22:05:52 +0200 Subject: [PATCH 17/19] ci(examples): run lint and tests across all Go modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, `make go.lint` and `make go.test` only covered the root module. `go test ./...` and `golangci-lint run` both stop at module boundaries, so the todolist example — a nested module with its own go.mod — was silently excluded from CI. A library change that broke the example could land green. Fix: the Makefile now discovers Go modules via `git ls-files '*go.mod'` and runs each target in every module. Currently that means the root library + `examples/todolist`; adding another example automatically picks it up with no Makefile change needed. Each nested module runs golangci-lint with an explicit `--config $GOLANGCI_LINT_CONFIG` pointing at the root .golangci.yaml (absolute path), so every module is linted with the same rule set as the library. Coverage: `go test -coverprofile=coverage.txt` writes a file per module (one at repo root, one at examples/todolist/coverage.txt). The test workflow now uploads both to Codecov; the list is inlined in the workflow with a comment to keep it in sync with the Makefile loop. Also added a `go.build` target that mirrors the same module iteration, useful for local development and for any future CI step that wants a cheaper "does it compile" gate. README updated with a short 'CI coverage' section so the guarantee is visible to future contributors. --- .github/workflows/test.yml | 5 ++++- Makefile | 34 +++++++++++++++++++++++++++------- examples/todolist/README.md | 7 +++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f410de95..e5d6740b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,6 +35,9 @@ jobs: uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6 with: token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage.txt + # One coverage file per Go module: the root library and every + # example. Keep this list in sync with the modules iterated by + # the Makefile's go.test target. + files: ./coverage.txt,./examples/todolist/coverage.txt verbose: true fail_ci_if_error: true diff --git a/Makefile b/Makefile index c0644c27..46ecf3f0 100644 --- a/Makefile +++ b/Makefile @@ -9,17 +9,37 @@ endif GOLANGCI_LINT_FLAGS ?= -v GO_TEST_FLAGS ?= -v -cover -covermode=atomic -coverprofile=coverage.txt -coverpkg=./... +# GO_MODULES is the list of directories containing a go.mod, discovered via +# git so untracked scratch modules (e.g. vendored fixtures) never sneak in. +# The repo root lists itself as "." so the root module is always covered. +GO_MODULES := $(sort $(dir $(shell git ls-files '*go.mod'))) + +# GOLANGCI_LINT_CONFIG points each nested module's linter at the root config. +# Every module is linted with the same rules we apply to the library. +GOLANGCI_LINT_CONFIG := $(abspath .golangci.yaml) + +# run_in_modules runs a shell command in each Go module. The first argument +# is a human-readable label for logs; the second is the command itself, +# which runs with $$mod pointing at the module directory. +define run_in_modules + set -e; \ + for mod in $(GO_MODULES); do \ + echo "==> $(1) ($$mod)"; \ + ( cd "$$mod" && $(2) ); \ + done +endef + go.lint: - golangci-lint run $(GOLANGCI_LINT_FLAGS) + $(call run_in_modules,golangci-lint run,golangci-lint run --config $(GOLANGCI_LINT_CONFIG) $(GOLANGCI_LINT_FLAGS)) go.test: - go test $(GO_TEST_FLAGS) ./... + $(call run_in_modules,go test,go test $(GO_TEST_FLAGS) ./...) go.test.unit: - go test -short $(GO_TEST_FLAGS) ./... + $(call run_in_modules,go test -short,go test -short $(GO_TEST_FLAGS) ./...) + +go.build: + $(call run_in_modules,go build,go build ./...) go.mod.update: - echo "==> update dependencies recursively" - go get -u ./... - echo "==> run 'go mod tidy'" - go mod tidy + $(call run_in_modules,go get -u + go mod tidy,go get -u ./... && go mod tidy) diff --git a/examples/todolist/README.md b/examples/todolist/README.md index f7bad69c..bfe06947 100644 --- a/examples/todolist/README.md +++ b/examples/todolist/README.md @@ -79,3 +79,10 @@ buf generate Committed output lives under `gen/`; regenerate after any proto change. The buf configuration uses the v2 schema (see `buf.yaml` + `buf.gen.yaml` at the module root). + +## CI coverage + +`make go.lint` and `make go.test` at the repo root iterate over every +Go module (root + every nested example). This example is therefore +lint-gated and test-gated on every PR — a library change that breaks +the example fails CI. From b01b14aff2b9a46b09eb4cf854e7eeb90e343d2f Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 22:38:24 +0200 Subject: [PATCH 18/19] ci(examples): introduce Go workspace, drop replace directive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds go.work at repo root declaring both modules (root library + examples/todolist) as workspace members. The workspace delivers two concrete benefits: - IDE / gopls sees the library and example as one unit, so go-to-definition, find-usages, and inline errors work across the boundary while editing. - examples/todolist/go.mod no longer needs the `replace github.com/get-eventually/go-eventually => ../..` hack; the workspace resolves the module locally. It does NOT give us a single-invocation `go test ./...` across modules: neither go nor golangci-lint span workspace members from a single pattern (golang/vscode-go#2666). So the Makefile still iterates — but the module list now comes from `go work edit -json` instead of from a `git ls-files` heuristic, keeping go.work as the single source of truth for 'what modules participate in this repo'. Adding a new workspace member is now a single edit to go.work; the Makefile (and therefore CI) picks it up automatically. examples/todolist/go.mod's `require github.com/get-eventually/go-eventually` line stays at v0.4.0 as a nominal floor. GOWORK=off would fall back to resolving that version from the proxy — useful to know as a failure mode if someone accidentally disables the workspace. go.work.sum is committed, per Go 1.21+ convention. --- .github/workflows/test.yml | 5 +- Makefile | 17 ++- examples/todolist/README.md | 18 ++- examples/todolist/go.mod | 10 +- examples/todolist/go.sum | 10 +- go.work | 6 + go.work.sum | 283 ++++++++++++++++++++++++++++++++++++ 7 files changed, 327 insertions(+), 22 deletions(-) create mode 100644 go.work create mode 100644 go.work.sum diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5d6740b..0e3dbe12 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,9 +35,8 @@ jobs: uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6 with: token: ${{ secrets.CODECOV_TOKEN }} - # One coverage file per Go module: the root library and every - # example. Keep this list in sync with the modules iterated by - # the Makefile's go.test target. + # One coverage file per Go workspace member (see go.work). + # Keep this list in sync with go.work's use directives. files: ./coverage.txt,./examples/todolist/coverage.txt verbose: true fail_ci_if_error: true diff --git a/Makefile b/Makefile index 46ecf3f0..32dabd9d 100644 --- a/Makefile +++ b/Makefile @@ -9,18 +9,19 @@ endif GOLANGCI_LINT_FLAGS ?= -v GO_TEST_FLAGS ?= -v -cover -covermode=atomic -coverprofile=coverage.txt -coverpkg=./... -# GO_MODULES is the list of directories containing a go.mod, discovered via -# git so untracked scratch modules (e.g. vendored fixtures) never sneak in. -# The repo root lists itself as "." so the root module is always covered. -GO_MODULES := $(sort $(dir $(shell git ls-files '*go.mod'))) +# GO_MODULES is the list of directories participating in the Go workspace, +# discovered via `go work edit -json` so go.work stays the single source of +# truth. golangci-lint and go test don't span workspace modules on their own +# (see https://github.com/golang/vscode-go/issues/2666), so we iterate. +GO_MODULES := $(shell go work edit -json | jq -r '.Use[].DiskPath') # GOLANGCI_LINT_CONFIG points each nested module's linter at the root config. # Every module is linted with the same rules we apply to the library. GOLANGCI_LINT_CONFIG := $(abspath .golangci.yaml) -# run_in_modules runs a shell command in each Go module. The first argument -# is a human-readable label for logs; the second is the command itself, -# which runs with $$mod pointing at the module directory. +# run_in_modules runs a shell command in each Go workspace module. The first +# argument is a human-readable label for logs; the second is the command +# itself, which runs with $$mod pointing at the module directory. define run_in_modules set -e; \ for mod in $(GO_MODULES); do \ @@ -43,3 +44,5 @@ go.build: go.mod.update: $(call run_in_modules,go get -u + go mod tidy,go get -u ./... && go mod tidy) + echo "==> go work sync" + go work sync diff --git a/examples/todolist/README.md b/examples/todolist/README.md index bfe06947..926c0386 100644 --- a/examples/todolist/README.md +++ b/examples/todolist/README.md @@ -29,11 +29,19 @@ end-to-end. ## Running ```sh -cd examples/todolist -go run . +go run ./examples/todolist +# or from the example dir: +cd examples/todolist && go run . # Server listens on :8080 by default ``` +The example is a member of the repository's Go workspace (`go.work` at +repo root). The workspace is what resolves the `go-eventually` import +to the in-repo library code. The example's `go.mod` still carries a +`require github.com/get-eventually/go-eventually v0.4.0` line as a +nominal floor — `GOWORK=off` would fall back to that released version, +which is NOT what you want when evaluating in-progress library changes. + Hit it with a Connect client, `grpcurl`, or the built-in reflection: ```sh @@ -83,6 +91,6 @@ at the module root). ## CI coverage `make go.lint` and `make go.test` at the repo root iterate over every -Go module (root + every nested example). This example is therefore -lint-gated and test-gated on every PR — a library change that breaks -the example fails CI. +Go workspace member (discovered from `go.work`). This example is +therefore lint-gated and test-gated on every PR — a library change +that breaks the example fails CI. diff --git a/examples/todolist/go.mod b/examples/todolist/go.mod index 007b39bd..1d2f3408 100644 --- a/examples/todolist/go.mod +++ b/examples/todolist/go.mod @@ -6,19 +6,21 @@ require ( connectrpc.com/connect v1.19.2 connectrpc.com/grpchealth v1.4.0 connectrpc.com/grpcreflect v1.3.0 - github.com/get-eventually/go-eventually v0.0.0 + github.com/get-eventually/go-eventually v0.4.0 github.com/google/uuid v1.6.0 github.com/kelseyhightower/envconfig v1.4.0 - golang.org/x/net v0.50.0 + golang.org/x/net v0.52.0 google.golang.org/protobuf v1.36.11 ) require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/stretchr/testify v1.11.1 // indirect + golang.org/x/sync v0.20.0 // indirect golang.org/x/text v0.36.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -replace github.com/get-eventually/go-eventually => ../.. diff --git a/examples/todolist/go.sum b/examples/todolist/go.sum index 543c6085..9fe77cb6 100644 --- a/examples/todolist/go.sum +++ b/examples/todolist/go.sum @@ -6,25 +6,29 @@ connectrpc.com/grpcreflect v1.3.0 h1:Y4V+ACf8/vOb1XOc251Qun7jMB75gCUNw6llvB9csXc connectrpc.com/grpcreflect v1.3.0/go.mod h1:nfloOtCS8VUQOQ1+GTdFzVg2CJo4ZGaat8JIovCtDYs= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/get-eventually/go-eventually v0.4.0 h1:YmTYVR1acQO0ZL/KPUiy/J6ETitBiqIvuoZJAGmWbm0= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529 h1:QoMBg0moLIlB/eucPzc+ID5SgPZWuirtjAn3l8nW2Dg= google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529/go.mod h1:EjLmDZ8liSLBrCTK5vP+bGIxRQHE3ovGvOI0CzGk1PI= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go.work b/go.work new file mode 100644 index 00000000..4cfefe82 --- /dev/null +++ b/go.work @@ -0,0 +1,6 @@ +go 1.26.0 + +use ( + . + ./examples/todolist +) diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 00000000..ca8b2add --- /dev/null +++ b/go.work.sum @@ -0,0 +1,283 @@ +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI= +cloud.google.com/go/accessapproval v1.11.0/go.mod h1:7bmInw17bQX+ZPi7YmReC3xKymDrMmxXaUnaI6zQOqI= +cloud.google.com/go/accesscontextmanager v1.12.0/go.mod h1:VO15iVnsM0FO9Dt8hSFPgkuHRZjq6LEYZq1szJ27U2k= +cloud.google.com/go/aiplatform v1.124.0/go.mod h1:yWTZiCunYDnyxeWWD14tDo6+BMlvAUCC5VxuxhvbrVI= +cloud.google.com/go/analytics v0.33.0/go.mod h1:V9Qef2N0y8GDqQ9FTlmM2XpDEMYonZJRPSUNGZlPCcc= +cloud.google.com/go/apigateway v1.10.0/go.mod h1:f3Sk8Tdh1Ty5HR7kgbWB6Yu1M82LM+nIr5DTMZnLZWk= +cloud.google.com/go/apigeeconnect v1.10.0/go.mod h1:mYJekCKZHc2ia5yZX5lwtexTn9CzsOfb6+sh/2hi42Q= +cloud.google.com/go/apigeeregistry v0.13.0/go.mod h1:o+j6eA8hYhTWX5gEqMMBVDWY+/QQFrYe/YJBsO19pn0= +cloud.google.com/go/appengine v1.12.0/go.mod h1:JMjrVFg+YgfksZCWbtA3TgbKbPfZZtapB9cGL/5WVnM= +cloud.google.com/go/area120 v0.13.0/go.mod h1:jD1fw9W4xxIZMY68g7PpbCPleoeGddFs5jPcdhfg3+Y= +cloud.google.com/go/artifactregistry v1.23.0/go.mod h1:aMmdtqKVmbuxCCb/NGDJYZHsK6AtqlcyvD05ACzs1n8= +cloud.google.com/go/asset v1.25.0/go.mod h1:+HaDReZQAh/0syAf0uTMeUrMfXikr+KKyDtCdvf7j4M= +cloud.google.com/go/assuredworkloads v1.16.0/go.mod h1:zBnVYn0E+sDW/mhEmcg1R8+8tguXrtBgmfGY0q34kss= +cloud.google.com/go/auth v0.16.4/go.mod h1:j10ncYwjX/g3cdX7GpEzsdM+d+ZNsXAbb6qXA7p1Y5M= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/automl v1.18.0/go.mod h1:OkHxjbVDblDafhwuP8yEkz1xcUJhgcbhbsieCW7GaiI= +cloud.google.com/go/baremetalsolution v1.7.0/go.mod h1:o+stutiS8t+HmjNIG92Gkn8H9+5/q27d6lQp7e9GWdg= +cloud.google.com/go/batch v1.17.0/go.mod h1:dpWfhLmLQZqsTBAFYjZA3pS04fCY5ttTenZcWmSeILw= +cloud.google.com/go/beyondcorp v1.5.0/go.mod h1:vujdO0wfsBV2y1egrJxGtwKZr5P5V6bIHKWp1phWHBY= +cloud.google.com/go/bigquery v1.76.0/go.mod h1:J4wuqka/1hEpdJxH2oBrUR0vjTD+r7drGkpcA3yqERM= +cloud.google.com/go/bigtable v1.46.0/go.mod h1:GUM6PdkG3rrDse9kugqvX5+ktwo3ldfLtLi1VFn5Wj4= +cloud.google.com/go/billing v1.24.0/go.mod h1:axqDO1uHegh7u5qngkTfqN1djAeLGsWAFAblERgmgEk= +cloud.google.com/go/binaryauthorization v1.13.0/go.mod h1:+0CndCJPtcHuVCNok+qQskWvbP5Sp5m6eGL8Vpu5mss= +cloud.google.com/go/certificatemanager v1.12.0/go.mod h1:QOA8qRoM6/Ik03+srLnBykenGTy0fk78dnPcx5ZWOW8= +cloud.google.com/go/channel v1.24.0/go.mod h1:04T5Wjq+mHlvEUNzExydnBW1vO64q3Q2Wsblp/dpBxY= +cloud.google.com/go/cloudbuild v1.28.0/go.mod h1:rg52xEmndQQPiC9NV/8sCaVtKxHMU9D9MeU+oE9VGKA= +cloud.google.com/go/clouddms v1.11.0/go.mod h1:aMgrOZ+/EKF/PL+h1sDbS+7fAIYV5rTwD+G/apCeHQk= +cloud.google.com/go/cloudtasks v1.16.0/go.mod h1:3KeCxwtGEyaySL7CR3lMmEa2I4mq1ynXdgmfNiO4RYE= +cloud.google.com/go/compute v1.60.0/go.mod h1:Xm6PbsLgBpAg4va77ljbBdpMjzuU+uPp5Ze2dnZq7lw= +cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= +cloud.google.com/go/contactcenterinsights v1.20.0/go.mod h1:2Crd36H59Lwkt4gWrLgmnbnF59IIZIa3XYt1gtNqJkQ= +cloud.google.com/go/container v1.49.0/go.mod h1:EvqoT2eXfxLweXXUlhAMGR0sOAB00XPzEjoL01esSDs= +cloud.google.com/go/containeranalysis v0.17.0/go.mod h1:Zq0XHzUIa0oTa7H6aSR8HWqeJnoRI9syUcYJzfozjZQ= +cloud.google.com/go/datacatalog v1.29.0/go.mod h1:MP8V3kNuESnwMk4mB6zdWmw/4KQ5xZ8dyUNVsggqN5I= +cloud.google.com/go/dataflow v0.14.0/go.mod h1:BWhSrIGmsMfuYj3J+nJ2Tw7tplRR6r28kvRiqCD3WlQ= +cloud.google.com/go/dataform v0.17.0/go.mod h1:i1a0zkS751kvrY1IIPpUQZ77H5doxx7cs0AP3hnXTMk= +cloud.google.com/go/datafusion v1.11.0/go.mod h1:MQdANs3I/4gitzY+mTBx27rrQyMiUg8uc2Z4TPLWWfc= +cloud.google.com/go/datalabeling v0.12.0/go.mod h1:DYjvP4RhQ0332YgO22APYlBjCebb+SCaS0e2KApDq/Q= +cloud.google.com/go/dataplex v1.32.0/go.mod h1:sOazL+Bs/PTxiMHQ5yBboBvEW9qPrpGogx3+RAgfIt8= +cloud.google.com/go/dataproc/v2 v2.19.0/go.mod h1:oARVSa38kAHvSuG+cozsrY2sE6UajGuvOOf9vS+ADHI= +cloud.google.com/go/dataqna v0.12.0/go.mod h1:XiVVFTOEJLBSvm3ILbyjXngGQYpjb/66MSksqz/56fs= +cloud.google.com/go/datastore v1.22.0/go.mod h1:aopSX+Whx0lHspWWBj+AjWt68/zjYsPfDe3LjWtqZg8= +cloud.google.com/go/datastream v1.18.0/go.mod h1:uoWTtfP20W8MXuV2DPcl5zqnVsxQ9QEmmBHX858oYTQ= +cloud.google.com/go/deploy v1.30.0/go.mod h1:lUG7maG/NkoTXmQ8G1mtcVymnbizfDJh6ER7vljVa/U= +cloud.google.com/go/dialogflow v1.80.0/go.mod h1:UtuiGOq9gAlTz9u4Vt+q1syMrx9ANQzTk+lC3WDdSOw= +cloud.google.com/go/dlp v1.32.0/go.mod h1:+haQd/n0QTv5BK7wZnCk2qctd5sfKL50jjh9E6N0d/Q= +cloud.google.com/go/documentai v1.46.0/go.mod h1:mGjfbNf0cqCHKgxMZZV7frbfoF9T2hKkU1h88QyOy3c= +cloud.google.com/go/domains v0.13.0/go.mod h1:BjoSVNc+LVwoHMnE2fxTQNzGLSWWb6f3a8VAN6+VjVk= +cloud.google.com/go/edgecontainer v1.7.0/go.mod h1:mZmgXuMGTGI6RUUTXsOZa+F2rFF21v0JPnuX7LQEqBE= +cloud.google.com/go/errorreporting v0.7.0/go.mod h1:V7ojx7z76JITDZNGyDNkIIa9nNEkQzF6Yj+VHl2YF84= +cloud.google.com/go/essentialcontacts v1.10.0/go.mod h1:W8fTL17jP6vmsPHQaCT5rOjWGohEssuqDUroxnjST0A= +cloud.google.com/go/eventarc v1.21.0/go.mod h1:tIJL0hoWtZXVa5MjcAep/4xB+AXz4AbqQV14ogX5VwU= +cloud.google.com/go/filestore v1.13.0/go.mod h1:oD+PvCWu4HqfEdNv65yk2XaLIiP7h4AuAH9Ua5YBRTM= +cloud.google.com/go/firestore v1.22.0/go.mod h1:PaM4i7i7ruALSKmlpHXXZaPObcZw0W7ie5UOPr72iTU= +cloud.google.com/go/functions v1.22.0/go.mod h1:t40GeqBAQNuqKlHCxmV/pxhyYJnImLcvRa3GBv4tAy0= +cloud.google.com/go/gkebackup v1.11.0/go.mod h1:D2MDbHW4V/uKCmS9TnT8hNKX2tPkE/pWp9nSm0TQ9hY= +cloud.google.com/go/gkeconnect v0.15.0/go.mod h1:5iWSBQzMIRLwUHUWVhxxcNK45ZPE8ntyBgE0MkavlqQ= +cloud.google.com/go/gkehub v0.19.0/go.mod h1:xKePlMrI8LpKErzKMWdH/yQv+GDV60ypCNfTTdT+BN0= +cloud.google.com/go/gkemulticloud v1.9.0/go.mod h1:OtfHtgqOgDrXfcdFw8eUkCUI154Q51vvdqZYZV4c4qM= +cloud.google.com/go/gsuiteaddons v1.10.0/go.mod h1:rm/XT7wmwOFGn7jmWtVV65QmZCakzTbHLSojIC4Hskg= +cloud.google.com/go/iam v1.9.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4= +cloud.google.com/go/iap v1.15.0/go.mod h1:b+r+yjrss2WmAEzNrQQjlEdD5E9B8c47mOF7XnqT+z0= +cloud.google.com/go/ids v1.8.0/go.mod h1:uCSFrXfCnRUKBl5PdE/ZqBNp1+vKSKPWpdYGa61WjpQ= +cloud.google.com/go/iot v1.11.0/go.mod h1:62W4n2fe/Ct66NWJEfCB5suZ3XsL5Atx+MxFjScr+9s= +cloud.google.com/go/kms v1.29.0/go.mod h1:YIyXZym11R5uovJJt4oN5eUL3oPmirF3yKeIh6QAf4U= +cloud.google.com/go/language v1.17.0/go.mod h1:xSeiVB4UiA9wYmFy2GWjf1Mb1K3uR1Yi/80qoqTxH04= +cloud.google.com/go/lifesciences v0.13.0/go.mod h1:FwS+QkqPdVWl4SmKUCFozFvsTVWTLH13HCKcwR/MR9U= +cloud.google.com/go/logging v1.16.0/go.mod h1:ZGKnpBaURITh+g/uom2VhbiFoFWvejcrHPDhxFtU/gI= +cloud.google.com/go/longrunning v0.11.0/go.mod h1:8nqFBPOO1U/XkhWl0I19AMZEphrHi73VNABIpKYaTwM= +cloud.google.com/go/managedidentities v1.10.0/go.mod h1:rm72jf/v//0NG73VQNZM1JlV2E95uhJymmSXlgi6hMA= +cloud.google.com/go/maps v1.33.0/go.mod h1:HH1V8tduMn+b9oRMCdl3vok98uvHco/wElZXyJQ/9kU= +cloud.google.com/go/mediatranslation v0.12.0/go.mod h1:kjZrowuigFr+Bf1HM1TCtp1a3E3kfG1ovPK5VEuaNAQ= +cloud.google.com/go/memcache v1.14.0/go.mod h1:y/rXhJiieCF742K958dY29fSfM+Y3wh2thRmWspU2Dg= +cloud.google.com/go/metastore v1.17.0/go.mod h1:JGTjGdQ627m2ptDo86XsIKqzzZCk+GG41VEFD7ENsqs= +cloud.google.com/go/monitoring v1.27.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM= +cloud.google.com/go/networkconnectivity v1.24.0/go.mod h1:Uhzfk7NbiY6RNqV9XFvPWRji58+MkTYsTRfQ3EPtrGg= +cloud.google.com/go/networkmanagement v1.26.0/go.mod h1:2YogSU3sD7LvtmWntUAuGARbFQmy3A0En3LrJr69jkU= +cloud.google.com/go/networksecurity v0.14.0/go.mod h1:LMn10eRVf4K85PMF33yRoKAra7VhCOetxFcLDMh9A74= +cloud.google.com/go/notebooks v1.15.0/go.mod h1:NScGIhfQCqLRIlVaUVbm595F6dhqiTl5XS1KaKgitKM= +cloud.google.com/go/optimization v1.10.0/go.mod h1:qCWskZMcynh0GBsUrCP6oPwwnUhbwg5UcXvVM9hzOD8= +cloud.google.com/go/orchestration v1.14.0/go.mod h1:H7MFVP8Z/dtml39nf43sWYPL/2o7J4tdSZAlJrBuqnQ= +cloud.google.com/go/orgpolicy v1.18.0/go.mod h1:9LHqEGx5P5dhansdKTNIEXpM+QbebAIOs66+HUID4aQ= +cloud.google.com/go/osconfig v1.19.0/go.mod h1:BofnHqjjvu6lZQv/hqo2+rLCUiY4O6A9UYwwvVrSBjk= +cloud.google.com/go/oslogin v1.17.0/go.mod h1:3Oa36T3781Mv+yCSVYlfasi7auHjfPFqvNOd1q92umc= +cloud.google.com/go/phishingprotection v0.12.0/go.mod h1:2gyYqwNjePPEocXDkDve3EuJPaRqN/E7fp28K3arR0k= +cloud.google.com/go/policytroubleshooter v1.14.0/go.mod h1:yNuROjN6h+2/TE2JOvBBJMjYIjC6j0UYHq8f2kVHlA4= +cloud.google.com/go/privatecatalog v0.13.0/go.mod h1:av2b5Rv+oG5ORxUqGlCAYO9s4pXjgc6q2qO9nkTcqT8= +cloud.google.com/go/pubsub v1.50.2/go.mod h1:jyCWeZdGFqd4mitSsBERnJcpqaHBsxQoPkNvjj4sp0w= +cloud.google.com/go/pubsub/v2 v2.5.1/go.mod h1:Pd+qeabMX+576vQJhTN7TelE4k6kJh15dLU/ptOQ/UA= +cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= +cloud.google.com/go/recaptchaenterprise/v2 v2.24.0/go.mod h1:+ntF70/j7qBa6G/pwmYA0mkBcDeTCXV6WDqUL7GObfs= +cloud.google.com/go/recommendationengine v0.12.0/go.mod h1:UP9cN46tDpZ/N57eDYIWeIRHjMOchtiIyjWjV0Dvr3k= +cloud.google.com/go/recommender v1.16.0/go.mod h1:INRBLfBQJCrgPqjBVFht4OjaFq/WhB/c5V1sqBOdX8g= +cloud.google.com/go/redis v1.21.0/go.mod h1:EUlUT24BAL6LsE1f/N9Bg3LhRCfH+LzwLGbst3KuZRw= +cloud.google.com/go/resourcemanager v1.13.0/go.mod h1:ve0VNxPoDU6XxDuEMCjkineb0YzXQXx3mOWwnNckGDE= +cloud.google.com/go/resourcesettings v1.8.3/go.mod h1:BzgfXFHIWOOmHe6ZV9+r3OWfpHJgnqXy8jqwx4zTMLw= +cloud.google.com/go/retail v1.29.0/go.mod h1:sfq/cT+gfSLuURf/mdVAw5n0pav3hxSP1rT8RfL7Qxk= +cloud.google.com/go/run v1.19.0/go.mod h1:Z5wHbyFirI8XU48EPs5XJf/qmVm1SXZEhuS8EvZOuQU= +cloud.google.com/go/scheduler v1.14.0/go.mod h1:0hsZg0MZJADyke1lutI0FHAYJR8Dtm8oIivXkmpACkA= +cloud.google.com/go/secretmanager v1.19.0/go.mod h1:9OmSuOeiiUicANglrbdKWSnT3gYkRcXuUQDk7dDW0zU= +cloud.google.com/go/security v1.22.0/go.mod h1:XaB3p0SE7v2bBitsLBb1hM6R8/oI/k/IujpXFJalFK0= +cloud.google.com/go/securitycenter v1.42.0/go.mod h1:7BMMbSTAddVfiE+HrC8tKS6SuRkyK7FRPlkpAZBRV3U= +cloud.google.com/go/servicedirectory v1.15.0/go.mod h1:CtgjXS1idj3s9Q6tB68021Rzk8Q6decV6+ldXC1BoBk= +cloud.google.com/go/shell v1.11.0/go.mod h1:TivWrVriy6xQ0wBjNJJridJgODZz8zXUEW2u48kynzY= +cloud.google.com/go/spanner v1.90.0/go.mod h1:8NB5a7qgwIhGD19Ly+vkpKffPL78vIG9RcrgsuREha0= +cloud.google.com/go/speech v1.33.0/go.mod h1:shnf33sZbGnQQZyek1fdLOR5rRKV6D3jsNqpqyijvj8= +cloud.google.com/go/storage v1.56.0/go.mod h1:Tpuj6t4NweCLzlNbw9Z9iwxEkrSem20AetIeH/shgVU= +cloud.google.com/go/storagetransfer v1.16.0/go.mod h1:AbGutEym/KNasoiDpSj/CYbigp5yhgosSgwlhGvQNs4= +cloud.google.com/go/talent v1.11.0/go.mod h1:GSwli9V25WQdzeuJDJWH9TlQmA8lPFn7yKsxowdxW9Y= +cloud.google.com/go/texttospeech v1.19.0/go.mod h1:p/UVJILAo/S5vsJaWZVdDRzNzA7wXIA+hTACvpMeOBk= +cloud.google.com/go/tpu v1.11.0/go.mod h1:F5gT5BL22Dhsr05JLHdMjAjj+wcTn3Xtuu4jvq9yFug= +cloud.google.com/go/trace v1.14.0/go.mod h1:r+bdAn16dKLSV1G2D5v3e58IlQlizfxWrUfjx7kM7X0= +cloud.google.com/go/translate v1.15.0/go.mod h1:3mErnHTQBu9yeLiL35K0HBBuaM6Vk2fD/vyWFz790VU= +cloud.google.com/go/video v1.30.0/go.mod h1:KxDL728ZzH+FJwtEb9XkiLTETW5bI37hTWbJiRYeXkk= +cloud.google.com/go/videointelligence v1.15.0/go.mod h1:mmX1JpIWzwozaigrdRNjikZc3aFLNHFKh+OFwAdfiW4= +cloud.google.com/go/vision/v2 v2.12.0/go.mod h1:ODlLCajJOq4t8thoi1uVvbnfIfix73HsYWhZuIveagQ= +cloud.google.com/go/vmmigration v1.13.0/go.mod h1:MP6mQ21ru1usBeCbl805Ioz0Fy+yf3qK2kUkhZ69QQY= +cloud.google.com/go/vmwareengine v1.6.0/go.mod h1:e66l90IZhm1yQfYZv+YCWjSNSklQZCRmuEvKL8n3Ua0= +cloud.google.com/go/vpcaccess v1.11.0/go.mod h1:4Uus6E/9FYUtIrwBE1wJ1RosKwb02H6kEd9puJ02TL8= +cloud.google.com/go/webrisk v1.14.0/go.mod h1:VIQw8smiaMOlget/xOk6niTkNJTiQc5skEmCuAksxJc= +cloud.google.com/go/websecurityscanner v1.10.0/go.mod h1:cZSc9HqoFdccL1mqZtPIInOd4R8PBGwI20wdnrz6AO8= +cloud.google.com/go/workflows v1.17.0/go.mod h1:TWsrDGgsJy7xAJ07byzHhKKehEWItJG3BivEHVhGH5g= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8/go.mod h1:JTnlBSot91steJeti4ryyu/tLd4Sk84O5W22L7O2EQU= +github.com/aws/aws-sdk-go-v2/credentials v1.12.20/go.mod h1:UKY5HyIux08bbNA7Blv4PcXQ8cTkGh7ghHMFklaviR4= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.33/go.mod h1:84XgODVR8uRhmOnUkKGUZKqIMxmjmLOR8Uyp7G/TPwc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.17/go.mod h1:pRwaTYCJemADaqCbUAxltMoHKata7hmB5PjEXeu0kfg= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.14/go.mod h1:AyGgqiKv9ECM6IZeNQtdT8NnMvUb3/2wokeq2Fgryto= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9/go.mod h1:a9j48l6yL5XINLHLcOKInjdvknN+vWqPBxqeIDw7ktw= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.18/go.mod h1:NS55eQ4YixUJPTC+INxi2/jCqe1y2Uw3rnh9wEOVJxY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.17/go.mod h1:4nYOrY41Lrbk2170/BGkcJKBhws9Pfn8MG3aGqjjeFI= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17/go.mod h1:YqMdV+gEKCQ59NrB7rzrJdALeBIsYiVi8Inj3+KcqHI= +github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo= +github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM= +github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= +github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= +github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M= +github.com/get-eventually/go-eventually v0.4.0/go.mod h1:sp7/2JOA7HCwVhhmoYOIq51Re0GLZ6tsxoSs8i8V01I= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gocql/gocql v0.0.0-20210515062232-b7ef815b4556/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= +github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4= +github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/microsoft/go-mssqldb v1.0.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/sys/mount v0.3.4/go.mod h1:KcQJMbQdJHPlq5lcYT+/CjatWM4PuxKe+XLSVS4J6Os= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= +github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= +github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= +github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/pierrec/lz4/v4 v4.1.16/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rqlite/gorqlite v0.0.0-20230708021416-2acd02b70b79/go.mod h1:xF/KoXmrRyahPfo5L7Szb5cAAUl53dMWBh9cMruGEZg= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/snowflakedb/gosnowflake v1.6.19/go.mod h1:FM1+PWUdwB9udFDsXdfD58NONC0m+MlOSmQRvimobSM= +github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/api v0.247.0/go.mod h1:r1qZOPmxXffXg6xS5uhx16Fa/UFY8QU/K4bfKrnvovM= +google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= +modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8= +modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw= +modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM= +modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY= +modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k= +modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= +modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4= From 820482c60d9c72de2fe83a4703e8e7778bfa1e89 Mon Sep 17 00:00:00 2001 From: Danilo Cianfrone Date: Tue, 21 Apr 2026 22:51:26 +0200 Subject: [PATCH 19/19] ci: exclude examples and generated code from codecov metrics The todolist example's coverage file contains the example's own source files, which were dragging the project coverage metric down without meaningfully reflecting library quality. Tell Codecov to ignore: - examples/** : the example's purpose is to be a litmus test for the library API; its own code coverage is not a project KPI. Library packages hit by the example's tests still count via the root coverage upload. - **/gen/** : generated protobuf/connect stubs have no meaningful coverage story. Also sets a 1%% threshold on both project and patch status checks so tiny refactors do not flag PRs red over immaterial coverage drift. --- .codecov.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .codecov.yml diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 00000000..77ef1f31 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,7 @@ +--- +# Codecov configuration. +# https://docs.codecov.com/docs/codecov-yaml + +ignore: + - "examples/**" + - "**/gen/**"