Skip to content

Commit 28af8fe

Browse files
author
Simon Bos
committed
Add timestamp.valid evaluator
1 parent ec5a306 commit 28af8fe

File tree

5 files changed

+346
-152
lines changed

5 files changed

+346
-152
lines changed

internal/evaluator/builder.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ func (bldr *Builder) buildValue(
235235
bldr.processEnumConstraints,
236236
bldr.processMapConstraints,
237237
bldr.processRepeatedConstraints,
238+
bldr.processTimestampConstraints,
238239
}
239240

240241
for _, step := range steps {
@@ -464,6 +465,29 @@ func (bldr *Builder) processRepeatedConstraints(
464465
return nil
465466
}
466467

468+
func (bldr *Builder) processTimestampConstraints(
469+
fdesc protoreflect.FieldDescriptor,
470+
fieldConstraints *validate.FieldConstraints,
471+
_ bool,
472+
valEval *value,
473+
_ MessageCache,
474+
) error {
475+
if fdesc.Kind() != protoreflect.MessageKind ||
476+
fdesc.Message().FullName() != "google.protobuf.Timestamp" {
477+
return nil
478+
}
479+
480+
secondsDesc := fdesc.Message().Fields().ByName("seconds")
481+
nanosDesc := fdesc.Message().Fields().ByName("nanos")
482+
timestampEval := timestampPB{
483+
SecondsDescriptor: secondsDesc,
484+
NanosDescriptor: nanosDesc,
485+
Valid: fieldConstraints.GetTimestamp().GetValid(),
486+
}
487+
valEval.Append(timestampEval)
488+
return nil
489+
}
490+
467491
type MessageCache map[protoreflect.MessageDescriptor]*message
468492

469493
func (c MessageCache) Clone() MessageCache {

internal/evaluator/timestamp.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2023 Buf Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package evaluator
16+
17+
import (
18+
"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
19+
"github.com/bufbuild/protovalidate-go/internal/errors"
20+
"google.golang.org/protobuf/reflect/protoreflect"
21+
"google.golang.org/protobuf/types/known/timestamppb"
22+
)
23+
24+
// timestampPB is a specialized evaluator for applying some validate.TimestampRules (only the
25+
// `valid` rule currently) to a google.protobuf.Timestamp message. This is handled outside
26+
// CEL which handles google.protobuf.Timestamp as an abstract type, thus not allowing access
27+
// to the message fields.
28+
type timestampPB struct {
29+
SecondsDescriptor protoreflect.FieldDescriptor
30+
NanosDescriptor protoreflect.FieldDescriptor
31+
Valid bool
32+
}
33+
34+
func (t timestampPB) Evaluate(val protoreflect.Value, failFast bool) error {
35+
seconds := val.Message().Get(t.SecondsDescriptor).Int()
36+
nanos := val.Message().Get(t.NanosDescriptor).Int()
37+
38+
timestamp := &timestamppb.Timestamp{Seconds: seconds, Nanos: int32(nanos)}
39+
40+
err := &errors.ValidationError{Violations: []*validate.Violation{}}
41+
if t.Valid {
42+
terr := timestamp.CheckValid()
43+
if terr != nil {
44+
err.Violations = append(err.Violations, &validate.Violation{
45+
ConstraintId: "timestamp.valid",
46+
Message: terr.Error(),
47+
})
48+
if failFast {
49+
return err
50+
}
51+
}
52+
}
53+
54+
if len(err.Violations) > 0 {
55+
return err
56+
}
57+
return nil
58+
}
59+
60+
func (t timestampPB) Tautology() bool {
61+
return !t.Valid
62+
}
63+
64+
var _ evaluator = timestampPB{}

0 commit comments

Comments
 (0)