diff --git a/entproto/cmd/protoc-gen-ent/google/type/date.proto b/entproto/cmd/protoc-gen-ent/google/type/date.proto new file mode 100644 index 000000000..6370cd869 --- /dev/null +++ b/entproto/cmd/protoc-gen-ent/google/type/date.proto @@ -0,0 +1,52 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/date;date"; +option java_multiple_files = true; +option java_outer_classname = "DateProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a whole or partial calendar date, such as a birthday. The time of +// day and time zone are either specified elsewhere or are insignificant. The +// date is relative to the Gregorian Calendar. This can represent one of the +// following: +// +// * A full date, with non-zero year, month, and day values +// * A month and day value, with a zero year, such as an anniversary +// * A year on its own, with zero month and day values +// * A year and month value, with a zero day, such as a credit card expiration +// date +// +// Related types are [google.type.TimeOfDay][google.type.TimeOfDay] and +// `google.protobuf.Timestamp`. +message Date { + // Year of the date. Must be from 1 to 9999, or 0 to specify a date without + // a year. + int32 year = 1; + + // Month of a year. Must be from 1 to 12, or 0 to specify a year without a + // month and day. + int32 month = 2; + + // Day of a month. Must be from 1 to 31 and valid for the year and month, or 0 + // to specify a year by itself or a year and month where the day isn't + // significant. + int32 day = 3; +} diff --git a/entproto/cmd/protoc-gen-ent/main.go b/entproto/cmd/protoc-gen-ent/main.go index 0a0f7c9e0..5464685d5 100644 --- a/entproto/cmd/protoc-gen-ent/main.go +++ b/entproto/cmd/protoc-gen-ent/main.go @@ -130,7 +130,16 @@ func toSchema(m *protogen.Message, opts *entopts.Schema) (*schemast.UpsertSchema } func isEdge(f *protogen.Field) bool { - return f.Desc.Kind() == protoreflect.MessageKind + isMessageKind := f.Desc.Kind() == protoreflect.MessageKind + if isMessageKind { + switch f.Desc.Message().FullName() { + case "google.protobuf.Timestamp": + return false + case "google.type.Date": + return false + } + } + return isMessageKind } func toEdge(f *protogen.Field) (ent.Edge, error) { @@ -194,6 +203,15 @@ func toField(f *protogen.Field) (ent.Field, error) { values = append(values, string(pbEnum.Get(i).Name())) } fld = field.Enum(name).Values(values...) + case protoreflect.MessageKind: + switch f.Desc.Message().FullName() { + case "google.protobuf.Timestamp": + fld = field.Time(name) + case "google.type.Date": + fld = field.Time(name) + default: + return nil, fmt.Errorf("protoc-gen-ent: unsupported kind %q", f.Desc.Kind()) + } default: return nil, fmt.Errorf("protoc-gen-ent: unsupported kind %q", f.Desc.Kind()) } diff --git a/entproto/cmd/protoc-gen-ent/main_test.go b/entproto/cmd/protoc-gen-ent/main_test.go index c93f4f26a..22f0d8a8e 100644 --- a/entproto/cmd/protoc-gen-ent/main_test.go +++ b/entproto/cmd/protoc-gen-ent/main_test.go @@ -41,6 +41,18 @@ func TestBasic(t *testing.T) { require.True(t, strings.HasPrefix(contents, "// File updated by protoc-gen-ent.")) } +func TestTimeTypes(t *testing.T) { + tt, err := newGenTest(t, "testdata/time_types.proto") + require.NoError(t, err) + contents, err := tt.fileContents("employee.go") + require.NoError(t, err) + require.Contains(t, contents, "type Employee struct") + require.Contains(t, contents, `field.String("name")`) + require.Contains(t, contents, `field.Time("date_of_birth")`) + require.Contains(t, contents, `field.Time("start_date")`) + require.True(t, strings.HasPrefix(contents, "// File updated by protoc-gen-ent.")) +} + func TestCustomName(t *testing.T) { tt, err := newGenTest(t, "testdata/custom_name.proto") require.NoError(t, err) @@ -106,7 +118,7 @@ func newGenTest(t *testing.T, files ...string) (*genTest, error) { }) var parser protoparse.Parser var descs []*descriptorpb.FileDescriptorProto - tgts := []string{"google/protobuf/descriptor.proto", "options/ent/opts.proto"} + tgts := []string{"google/protobuf/descriptor.proto", "google/protobuf/timestamp.proto", "google/type/date.proto", "options/ent/opts.proto"} tgts = append(tgts, files...) parsed, err := parser.ParseFiles(tgts...) require.NoError(t, err) diff --git a/entproto/cmd/protoc-gen-ent/testdata/time_types.proto b/entproto/cmd/protoc-gen-ent/testdata/time_types.proto new file mode 100644 index 000000000..a17aa22b5 --- /dev/null +++ b/entproto/cmd/protoc-gen-ent/testdata/time_types.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package testdata; + +import "options/ent/opts.proto"; +import "google/protobuf/timestamp.proto"; +import "google/type/date.proto"; + +option go_package = "ent/testdata"; + +message Employee { + option (ent.schema).gen = true; + string name = 1; + google.type.Date date_of_birth = 2; + google.protobuf.Timestamp start_date = 3; +} \ No newline at end of file