Skip to content

Commit

Permalink
Add timestamp.valid evaluator
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Bos authored and simonbos committed Oct 20, 2023
1 parent ec5a306 commit 216b435
Show file tree
Hide file tree
Showing 5 changed files with 346 additions and 152 deletions.
24 changes: 24 additions & 0 deletions internal/evaluator/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ func (bldr *Builder) buildValue(
bldr.processEnumConstraints,
bldr.processMapConstraints,
bldr.processRepeatedConstraints,
bldr.processTimestampConstraints,
}

for _, step := range steps {
Expand Down Expand Up @@ -464,6 +465,29 @@ func (bldr *Builder) processRepeatedConstraints(
return nil
}

func (bldr *Builder) processTimestampConstraints(
fdesc protoreflect.FieldDescriptor,
fieldConstraints *validate.FieldConstraints,
_ bool,
valEval *value,
_ MessageCache,
) error {
if fdesc.Kind() != protoreflect.MessageKind ||
fdesc.Message().FullName() != "google.protobuf.Timestamp" {
return nil
}

secondsDesc := fdesc.Message().Fields().ByName("seconds")
nanosDesc := fdesc.Message().Fields().ByName("nanos")
timestampEval := timestampPB{
SecondsDescriptor: secondsDesc,
NanosDescriptor: nanosDesc,
Valid: fieldConstraints.GetTimestamp().GetValid(),

Check failure on line 485 in internal/evaluator/builder.go

View workflow job for this annotation

GitHub Actions / Go (stable)

fieldConstraints.GetTimestamp().GetValid undefined (type *validate.TimestampRules has no field or method GetValid)

Check failure on line 485 in internal/evaluator/builder.go

View workflow job for this annotation

GitHub Actions / Go (oldstable)

fieldConstraints.GetTimestamp().GetValid undefined (type *validate.TimestampRules has no field or method GetValid)

Check failure on line 485 in internal/evaluator/builder.go

View workflow job for this annotation

GitHub Actions / Go (oldstable)

fieldConstraints.GetTimestamp().GetValid undefined (type *validate.TimestampRules has no field or method GetValid)
}
valEval.Append(timestampEval)
return nil
}

type MessageCache map[protoreflect.MessageDescriptor]*message

func (c MessageCache) Clone() MessageCache {
Expand Down
64 changes: 64 additions & 0 deletions internal/evaluator/timestamp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2023 Buf Technologies, Inc.
//
// 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.

package evaluator

import (
"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
"github.com/bufbuild/protovalidate-go/internal/errors"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/known/timestamppb"
)

// timestampPB is a specialized evaluator for applying some validate.TimestampRules (only the
// `valid` rule currently) to a google.protobuf.Timestamp message. This is handled outside
// CEL which handles google.protobuf.Timestamp as an abstract type, thus not allowing access
// to the message fields.
type timestampPB struct {
SecondsDescriptor protoreflect.FieldDescriptor
NanosDescriptor protoreflect.FieldDescriptor
Valid bool
}

func (t timestampPB) Evaluate(val protoreflect.Value, failFast bool) error {
seconds := val.Message().Get(t.SecondsDescriptor).Int()
nanos := val.Message().Get(t.NanosDescriptor).Int()

timestamp := &timestamppb.Timestamp{Seconds: seconds, Nanos: int32(nanos)}

err := &errors.ValidationError{Violations: []*validate.Violation{}}
if t.Valid {
terr := timestamp.CheckValid()
if terr != nil {
err.Violations = append(err.Violations, &validate.Violation{
ConstraintId: "timestamp.valid",
Message: terr.Error(),
})
if failFast {
return err
}
}
}

if len(err.Violations) > 0 {
return err
}
return nil
}

func (t timestampPB) Tautology() bool {
return !t.Valid
}

var _ evaluator = timestampPB{}
Loading

0 comments on commit 216b435

Please sign in to comment.