fix(orm)!: duration encoding doesn't handle nil values properly (#15138)
Co-authored-by: marbar3778 <marbar3778@yahoo.com> Co-authored-by: Ryan Christoffersen <12519942+ryanchristo@users.noreply.github.com>
This commit is contained in:
parent
9e4fbb6db1
commit
13493d3645
@ -47,3 +47,4 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
### State-machine Breaking Changes
|
||||
|
||||
* [#12273](https://github.com/cosmos/cosmos-sdk/pull/12273) The timestamp key encoding was reworked to properly handle nil values. Existing users will need to manually migrate their data to the new encoding before upgrading.
|
||||
* [#15138](https://github.com/cosmos/cosmos-sdk/pull/15138) The duration key encoding was reworked to properly handle nil values. Existing users will need to manually migrate their data to the new encoding before upgrading.
|
||||
|
||||
@ -4,9 +4,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/orm/encoding/ormfield"
|
||||
|
||||
@ -174,35 +171,3 @@ func TestCompactUInt64(t *testing.T) {
|
||||
assert.Equal(t, y, y2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
cdc := ormfield.TimestampCodec{}
|
||||
|
||||
// nil value
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(protoreflect.Value{}, buf))
|
||||
assert.Equal(t, 1, len(buf.Bytes()))
|
||||
val, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, !val.IsValid())
|
||||
|
||||
// no nanos
|
||||
ts := timestamppb.New(time.Date(2022, 1, 1, 12, 30, 15, 0, time.UTC))
|
||||
val = protoreflect.ValueOfMessage(ts.ProtoReflect())
|
||||
buf = &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 6, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
|
||||
// nanos
|
||||
ts = timestamppb.New(time.Date(2022, 1, 1, 12, 30, 15, 235809753, time.UTC))
|
||||
val = protoreflect.ValueOfMessage(ts.ProtoReflect())
|
||||
buf = &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 9, len(buf.Bytes()))
|
||||
val2, err = cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
}
|
||||
|
||||
@ -1,51 +1,102 @@
|
||||
package ormfield
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
io "io"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
var (
|
||||
durationSecondsField = durationMsgType.Descriptor().Fields().ByName("seconds")
|
||||
durationNanosField = durationMsgType.Descriptor().Fields().ByName("nanos")
|
||||
const (
|
||||
DurationSecondsMin = -315576000000
|
||||
DurationSecondsMax = 315576000000
|
||||
DurationNanosMin = -999999999
|
||||
DurationNanosMax = 999999999
|
||||
)
|
||||
|
||||
func getDurationSecondsAndNanos(value protoreflect.Value) (protoreflect.Value, protoreflect.Value) {
|
||||
msg := value.Message()
|
||||
return msg.Get(durationSecondsField), msg.Get(durationNanosField)
|
||||
}
|
||||
|
||||
// DurationCodec encodes a google.protobuf.Duration value as 12 bytes using
|
||||
// Int64Codec for seconds followed by Int32Codec for nanos. This allows for
|
||||
// sorted iteration.
|
||||
type DurationCodec struct{}
|
||||
|
||||
func (d DurationCodec) Decode(r Reader) (protoreflect.Value, error) {
|
||||
seconds, err := int64Codec.Decode(r)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
nanos, err := int32Codec.Decode(r)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
msg := durationMsgType.New()
|
||||
msg.Set(durationSecondsField, seconds)
|
||||
msg.Set(durationNanosField, nanos)
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
}
|
||||
|
||||
func (d DurationCodec) Encode(value protoreflect.Value, w io.Writer) error {
|
||||
// nil case
|
||||
if !value.IsValid() {
|
||||
_, err := w.Write(timestampDurationNilBz)
|
||||
return err
|
||||
}
|
||||
|
||||
seconds, nanos := getDurationSecondsAndNanos(value)
|
||||
err := int64Codec.Encode(seconds, w)
|
||||
secondsInt := seconds.Int()
|
||||
if secondsInt < DurationSecondsMin || secondsInt > DurationSecondsMax {
|
||||
return fmt.Errorf("duration seconds is out of range %d, must be between %d and %d", secondsInt, DurationSecondsMin, DurationSecondsMax)
|
||||
}
|
||||
negative := secondsInt < 0
|
||||
// we subtract the min duration value to make sure secondsInt is always non-negative and starts at 0
|
||||
secondsInt -= DurationSecondsMin
|
||||
err := encodeSeconds(secondsInt, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return int32Codec.Encode(nanos, w)
|
||||
|
||||
nanosInt := nanos.Int()
|
||||
if nanosInt == 0 {
|
||||
_, err = w.Write(timestampZeroNanosBz)
|
||||
return err
|
||||
}
|
||||
|
||||
if negative {
|
||||
if nanosInt < DurationNanosMin || nanosInt > 0 {
|
||||
return fmt.Errorf("negative duration nanos is out of range %d, must be between %d and %d", nanosInt, DurationNanosMin, 0)
|
||||
}
|
||||
nanosInt = -nanosInt
|
||||
} else if nanosInt < 0 || nanosInt > DurationNanosMax {
|
||||
return fmt.Errorf("duration nanos is out of range %d, must be between %d and %d", nanosInt, 0, DurationNanosMax)
|
||||
}
|
||||
|
||||
return encodeNanos(nanosInt, w)
|
||||
}
|
||||
|
||||
func (d DurationCodec) Decode(r Reader) (protoreflect.Value, error) {
|
||||
isNil, seconds, err := decodeSeconds(r)
|
||||
if isNil || err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
|
||||
// we add the min duration value to get back the original value
|
||||
seconds += DurationSecondsMin
|
||||
|
||||
negative := seconds < 0
|
||||
|
||||
msg := durationMsgType.New()
|
||||
msg.Set(durationSecondsField, protoreflect.ValueOfInt64(seconds))
|
||||
|
||||
nanos, err := decodeNanos(r)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
|
||||
if nanos == 0 {
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
}
|
||||
|
||||
if negative {
|
||||
nanos = -nanos
|
||||
}
|
||||
|
||||
msg.Set(durationNanosField, protoreflect.ValueOfInt32(nanos))
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
}
|
||||
|
||||
func (d DurationCodec) Compare(v1, v2 protoreflect.Value) int {
|
||||
if !v1.IsValid() {
|
||||
if !v2.IsValid() {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
if !v2.IsValid() {
|
||||
return -1
|
||||
}
|
||||
|
||||
s1, n1 := getDurationSecondsAndNanos(v1)
|
||||
s2, n2 := getDurationSecondsAndNanos(v2)
|
||||
c := compareInt(s1, s2)
|
||||
@ -61,9 +112,70 @@ func (d DurationCodec) IsOrdered() bool {
|
||||
}
|
||||
|
||||
func (d DurationCodec) FixedBufferSize() int {
|
||||
return 12
|
||||
return timestampDurationBufferSize
|
||||
}
|
||||
|
||||
func (d DurationCodec) ComputeBufferSize(protoreflect.Value) (int, error) {
|
||||
return timestampDurationBufferSize, nil
|
||||
}
|
||||
|
||||
var (
|
||||
durationSecondsField = durationMsgType.Descriptor().Fields().ByName("seconds")
|
||||
durationNanosField = durationMsgType.Descriptor().Fields().ByName("nanos")
|
||||
)
|
||||
|
||||
func getDurationSecondsAndNanos(value protoreflect.Value) (protoreflect.Value, protoreflect.Value) {
|
||||
msg := value.Message()
|
||||
return msg.Get(durationSecondsField), msg.Get(durationNanosField)
|
||||
}
|
||||
|
||||
// DurationV0Codec encodes a google.protobuf.Duration value as 12 bytes using
|
||||
// Int64Codec for seconds followed by Int32Codec for nanos. This allows for
|
||||
// sorted iteration.
|
||||
type DurationV0Codec struct{}
|
||||
|
||||
func (d DurationV0Codec) Decode(r Reader) (protoreflect.Value, error) {
|
||||
seconds, err := int64Codec.Decode(r)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
nanos, err := int32Codec.Decode(r)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
msg := durationMsgType.New()
|
||||
msg.Set(durationSecondsField, seconds)
|
||||
msg.Set(durationNanosField, nanos)
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
}
|
||||
|
||||
func (d DurationV0Codec) Encode(value protoreflect.Value, w io.Writer) error {
|
||||
seconds, nanos := getDurationSecondsAndNanos(value)
|
||||
err := int64Codec.Encode(seconds, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return int32Codec.Encode(nanos, w)
|
||||
}
|
||||
|
||||
func (d DurationV0Codec) Compare(v1, v2 protoreflect.Value) int {
|
||||
s1, n1 := getDurationSecondsAndNanos(v1)
|
||||
s2, n2 := getDurationSecondsAndNanos(v2)
|
||||
c := compareInt(s1, s2)
|
||||
if c != 0 {
|
||||
return c
|
||||
}
|
||||
return compareInt(n1, n2)
|
||||
}
|
||||
|
||||
func (d DurationV0Codec) IsOrdered() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (d DurationV0Codec) FixedBufferSize() int {
|
||||
return 12
|
||||
}
|
||||
|
||||
func (d DurationV0Codec) ComputeBufferSize(protoreflect.Value) (int, error) {
|
||||
return d.FixedBufferSize(), nil
|
||||
}
|
||||
|
||||
158
orm/encoding/ormfield/duration_test.go
Normal file
158
orm/encoding/ormfield/duration_test.go
Normal file
@ -0,0 +1,158 @@
|
||||
package ormfield_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/orm/encoding/ormfield"
|
||||
)
|
||||
|
||||
func TestDuration(t *testing.T) {
|
||||
t.Parallel()
|
||||
cdc := ormfield.DurationCodec{}
|
||||
|
||||
// nil value
|
||||
t.Run("nil value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(protoreflect.Value{}, buf))
|
||||
assert.Equal(t, 1, len(buf.Bytes()))
|
||||
val, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, !val.IsValid())
|
||||
})
|
||||
|
||||
// no nanos
|
||||
t.Run("no nanos", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dur, err := time.ParseDuration("100s")
|
||||
assert.NilError(t, err)
|
||||
durPb := durationpb.New(dur)
|
||||
val := protoreflect.ValueOfMessage(durPb.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 6, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
|
||||
t.Run("nanos", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
dur, err := time.ParseDuration("3879468295ns")
|
||||
assert.NilError(t, err)
|
||||
durPb := durationpb.New(dur)
|
||||
val := protoreflect.ValueOfMessage(durPb.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 9, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
|
||||
t.Run("min value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
durPb := &durationpb.Duration{
|
||||
Seconds: -315576000000,
|
||||
Nanos: -999999999,
|
||||
}
|
||||
val := protoreflect.ValueOfMessage(durPb.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 9, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
|
||||
t.Run("max value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
durPb := &durationpb.Duration{
|
||||
Seconds: 315576000000,
|
||||
Nanos: 999999999,
|
||||
}
|
||||
val := protoreflect.ValueOfMessage(durPb.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 9, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDurationOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
cdc := ormfield.DurationCodec{}
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
dur *durationpb.Duration
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "seconds too small",
|
||||
dur: &durationpb.Duration{
|
||||
Seconds: -315576000001,
|
||||
Nanos: 0,
|
||||
},
|
||||
expectErr: "seconds is out of range",
|
||||
},
|
||||
{
|
||||
name: "seconds too big",
|
||||
dur: &durationpb.Duration{
|
||||
Seconds: 315576000001,
|
||||
Nanos: 0,
|
||||
},
|
||||
expectErr: "seconds is out of range",
|
||||
},
|
||||
{
|
||||
name: "positive seconds negative nanos",
|
||||
dur: &durationpb.Duration{
|
||||
Seconds: 0,
|
||||
Nanos: -1,
|
||||
},
|
||||
expectErr: "nanos is out of range",
|
||||
},
|
||||
{
|
||||
name: "positive seconds nanos too big",
|
||||
dur: &durationpb.Duration{
|
||||
Seconds: 0,
|
||||
Nanos: 1000000000,
|
||||
},
|
||||
expectErr: "nanos is out of range",
|
||||
},
|
||||
{
|
||||
name: "negative seconds positive nanos",
|
||||
dur: &durationpb.Duration{
|
||||
Seconds: -1,
|
||||
Nanos: 1,
|
||||
},
|
||||
expectErr: "negative duration nanos is out of range",
|
||||
},
|
||||
{
|
||||
name: "negative seconds nanos too small",
|
||||
dur: &durationpb.Duration{
|
||||
Seconds: -1,
|
||||
Nanos: -1000000000,
|
||||
},
|
||||
expectErr: "negative duration nanos is out of range",
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
val := protoreflect.ValueOfMessage(tc.dur.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
err := cdc.Encode(val, buf)
|
||||
assert.ErrorContains(t, err, tc.expectErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -21,38 +21,33 @@ import (
|
||||
type TimestampCodec struct{}
|
||||
|
||||
const (
|
||||
timestampNilValue = 0xFF
|
||||
timestampZeroNanosValue = 0x0
|
||||
timestampSecondsMin = -62135579038
|
||||
timestampSecondsMax = 253402318799
|
||||
timestampNanosMax = 999999999
|
||||
timestampDurationNilValue = 0xFF
|
||||
timestampDurationZeroNanosValue = 0x0
|
||||
timestampDurationBufferSize = 9
|
||||
TimestampSecondsMin = -62135596800
|
||||
TimestampSecondsMax = 253402300799
|
||||
TimestampNanosMax = 999999999
|
||||
)
|
||||
|
||||
var (
|
||||
timestampNilBz = []byte{timestampNilValue}
|
||||
timestampZeroNanosBz = []byte{timestampZeroNanosValue}
|
||||
timestampDurationNilBz = []byte{timestampDurationNilValue}
|
||||
timestampZeroNanosBz = []byte{timestampDurationZeroNanosValue}
|
||||
)
|
||||
|
||||
func (t TimestampCodec) Encode(value protoreflect.Value, w io.Writer) error {
|
||||
// nil case
|
||||
if !value.IsValid() {
|
||||
_, err := w.Write(timestampNilBz)
|
||||
_, err := w.Write(timestampDurationNilBz)
|
||||
return err
|
||||
}
|
||||
|
||||
seconds, nanos := getTimestampSecondsAndNanos(value)
|
||||
secondsInt := seconds.Int()
|
||||
if secondsInt < timestampSecondsMin || secondsInt > timestampSecondsMax {
|
||||
return fmt.Errorf("seconds is out of range %d, must be between %d and %d", secondsInt, timestampSecondsMin, timestampSecondsMax)
|
||||
if secondsInt < TimestampSecondsMin || secondsInt > TimestampSecondsMax {
|
||||
return fmt.Errorf("timestamp seconds is out of range %d, must be between %d and %d", secondsInt, TimestampSecondsMin, TimestampSecondsMax)
|
||||
}
|
||||
secondsInt -= timestampSecondsMin
|
||||
var secondsBz [5]byte
|
||||
// write the seconds buffer from the end to the front
|
||||
for i := 4; i >= 0; i-- {
|
||||
secondsBz[i] = byte(secondsInt)
|
||||
secondsInt >>= 8
|
||||
}
|
||||
_, err := w.Write(secondsBz[:])
|
||||
secondsInt -= TimestampSecondsMin
|
||||
err := encodeSeconds(secondsInt, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -63,65 +58,104 @@ func (t TimestampCodec) Encode(value protoreflect.Value, w io.Writer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if nanosInt < 0 || nanosInt > timestampNanosMax {
|
||||
return fmt.Errorf("nanos is out of range %d, must be between %d and %d", secondsInt, 0, timestampNanosMax)
|
||||
if nanosInt < 0 || nanosInt > TimestampNanosMax {
|
||||
return fmt.Errorf("timestamp nanos is out of range %d, must be between %d and %d", secondsInt, 0, TimestampNanosMax)
|
||||
}
|
||||
|
||||
return encodeNanos(nanosInt, w)
|
||||
}
|
||||
|
||||
func encodeSeconds(secondsInt int64, w io.Writer) error {
|
||||
var secondsBz [5]byte
|
||||
// write the seconds buffer from the end to the front
|
||||
for i := 4; i >= 0; i-- {
|
||||
secondsBz[i] = byte(secondsInt)
|
||||
secondsInt >>= 8
|
||||
}
|
||||
_, err := w.Write(secondsBz[:])
|
||||
return err
|
||||
}
|
||||
|
||||
func encodeNanos(nanosInt int64, w io.Writer) error {
|
||||
var nanosBz [4]byte
|
||||
for i := 3; i >= 0; i-- {
|
||||
nanosBz[i] = byte(nanosInt)
|
||||
nanosInt >>= 8
|
||||
}
|
||||
nanosBz[0] |= 0xC0
|
||||
_, err = w.Write(nanosBz[:])
|
||||
_, err := w.Write(nanosBz[:])
|
||||
return err
|
||||
}
|
||||
|
||||
func (t TimestampCodec) Decode(r Reader) (protoreflect.Value, error) {
|
||||
b0, err := r.ReadByte()
|
||||
isNil, seconds, err := decodeSeconds(r)
|
||||
if isNil || err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
|
||||
seconds += TimestampSecondsMin
|
||||
|
||||
msg := timestampMsgType.New()
|
||||
msg.Set(timestampSecondsField, protoreflect.ValueOfInt64(seconds))
|
||||
|
||||
nanos, err := decodeNanos(r)
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
}
|
||||
|
||||
if b0 == timestampNilValue {
|
||||
return protoreflect.Value{}, nil
|
||||
if nanos == 0 {
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
}
|
||||
|
||||
msg.Set(timestampNanosField, protoreflect.ValueOfInt32(nanos))
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
}
|
||||
|
||||
func decodeSeconds(r Reader) (isNil bool, seconds int64, err error) {
|
||||
b0, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
if b0 == timestampDurationNilValue {
|
||||
return true, 0, nil
|
||||
}
|
||||
|
||||
var secondsBz [4]byte
|
||||
n, err := r.Read(secondsBz[:])
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
return false, 0, err
|
||||
}
|
||||
if n < 4 {
|
||||
return protoreflect.Value{}, io.EOF
|
||||
return false, 0, io.EOF
|
||||
}
|
||||
|
||||
seconds := int64(b0)
|
||||
seconds = int64(b0)
|
||||
for i := 0; i < 4; i++ {
|
||||
seconds <<= 8
|
||||
seconds |= int64(secondsBz[i])
|
||||
}
|
||||
seconds += timestampSecondsMin
|
||||
|
||||
msg := timestampMsgType.New()
|
||||
msg.Set(timestampSecondsField, protoreflect.ValueOfInt64(seconds))
|
||||
return false, seconds, nil
|
||||
}
|
||||
|
||||
b0, err = r.ReadByte()
|
||||
func decodeNanos(r Reader) (int32, error) {
|
||||
b0, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if b0 == timestampZeroNanosValue {
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
if b0 == timestampDurationZeroNanosValue {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var nanosBz [3]byte
|
||||
n, err = r.Read(nanosBz[:])
|
||||
n, err := r.Read(nanosBz[:])
|
||||
if err != nil {
|
||||
return protoreflect.Value{}, err
|
||||
return 0, err
|
||||
}
|
||||
if n < 3 {
|
||||
return protoreflect.Value{}, io.EOF
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
nanos := int32(b0) & 0x3F // clear first two bits
|
||||
@ -130,8 +164,7 @@ func (t TimestampCodec) Decode(r Reader) (protoreflect.Value, error) {
|
||||
nanos |= int32(nanosBz[i])
|
||||
}
|
||||
|
||||
msg.Set(timestampNanosField, protoreflect.ValueOfInt32(nanos))
|
||||
return protoreflect.ValueOfMessage(msg), nil
|
||||
return nanos, nil
|
||||
}
|
||||
|
||||
func (t TimestampCodec) Compare(v1, v2 protoreflect.Value) int {
|
||||
@ -161,11 +194,11 @@ func (t TimestampCodec) IsOrdered() bool {
|
||||
}
|
||||
|
||||
func (t TimestampCodec) FixedBufferSize() int {
|
||||
return 9
|
||||
return timestampDurationBufferSize
|
||||
}
|
||||
|
||||
func (t TimestampCodec) ComputeBufferSize(protoreflect.Value) (int, error) {
|
||||
return 9, nil
|
||||
return timestampDurationBufferSize, nil
|
||||
}
|
||||
|
||||
// TimestampV0Codec encodes a google.protobuf.Timestamp value as 12 bytes using
|
||||
|
||||
126
orm/encoding/ormfield/timestamp_test.go
Normal file
126
orm/encoding/ormfield/timestamp_test.go
Normal file
@ -0,0 +1,126 @@
|
||||
package ormfield_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/orm/encoding/ormfield"
|
||||
)
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
t.Parallel()
|
||||
cdc := ormfield.TimestampCodec{}
|
||||
|
||||
t.Run("nil value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(protoreflect.Value{}, buf))
|
||||
assert.Equal(t, 1, len(buf.Bytes()))
|
||||
val, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, !val.IsValid())
|
||||
})
|
||||
|
||||
t.Run("no nanos", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ts := timestamppb.New(time.Date(2022, 1, 1, 12, 30, 15, 0, time.UTC))
|
||||
val := protoreflect.ValueOfMessage(ts.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 6, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
|
||||
t.Run("nanos", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ts := timestamppb.New(time.Date(2022, 1, 1, 12, 30, 15, 235809753, time.UTC))
|
||||
val := protoreflect.ValueOfMessage(ts.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 9, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
|
||||
t.Run("min value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ts := timestamppb.New(time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC))
|
||||
val := protoreflect.ValueOfMessage(ts.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 6, len(buf.Bytes()))
|
||||
assert.Assert(t, bytes.Equal(buf.Bytes(), []byte{0, 0, 0, 0, 0, 0})) // the minimum value should be all zeros
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
|
||||
t.Run("max value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ts := timestamppb.New(time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC))
|
||||
val := protoreflect.ValueOfMessage(ts.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
assert.NilError(t, cdc.Encode(val, buf))
|
||||
assert.Equal(t, 9, len(buf.Bytes()))
|
||||
val2, err := cdc.Decode(buf)
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, 0, cdc.Compare(val, val2))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimestampOutOfRange(t *testing.T) {
|
||||
t.Parallel()
|
||||
cdc := ormfield.TimestampCodec{}
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
ts *timestamppb.Timestamp
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
name: "before min",
|
||||
ts: timestamppb.New(time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
expectErr: "timestamp seconds is out of range",
|
||||
},
|
||||
{
|
||||
name: "after max",
|
||||
ts: timestamppb.New(time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
expectErr: "timestamp seconds is out of range",
|
||||
},
|
||||
{
|
||||
name: "nanos too small",
|
||||
ts: ×tamppb.Timestamp{
|
||||
Seconds: 0,
|
||||
Nanos: -1,
|
||||
},
|
||||
expectErr: "timestamp nanos is out of range",
|
||||
},
|
||||
|
||||
{
|
||||
name: "nanos too big",
|
||||
ts: ×tamppb.Timestamp{
|
||||
Seconds: 0,
|
||||
Nanos: 1000000000,
|
||||
},
|
||||
expectErr: "timestamp nanos is out of range",
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
val := protoreflect.ValueOfMessage(tc.ts.ProtoReflect())
|
||||
buf := &bytes.Buffer{}
|
||||
err := cdc.Encode(val, buf)
|
||||
assert.ErrorContains(t, err, tc.expectErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import (
|
||||
ormlist "github.com/cosmos/cosmos-sdk/orm/model/ormlist"
|
||||
ormtable "github.com/cosmos/cosmos-sdk/orm/model/ormtable"
|
||||
ormerrors "github.com/cosmos/cosmos-sdk/orm/types/ormerrors"
|
||||
durationpb "google.golang.org/protobuf/types/known/durationpb"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
@ -540,6 +541,138 @@ func NewExampleTimestampTable(db ormtable.Schema) (ExampleTimestampTable, error)
|
||||
return exampleTimestampTable{table.(ormtable.AutoIncrementTable)}, nil
|
||||
}
|
||||
|
||||
type ExampleDurationTable interface {
|
||||
Insert(ctx context.Context, exampleDuration *ExampleDuration) error
|
||||
InsertReturningId(ctx context.Context, exampleDuration *ExampleDuration) (uint64, error)
|
||||
Update(ctx context.Context, exampleDuration *ExampleDuration) error
|
||||
Save(ctx context.Context, exampleDuration *ExampleDuration) error
|
||||
Delete(ctx context.Context, exampleDuration *ExampleDuration) error
|
||||
Has(ctx context.Context, id uint64) (found bool, err error)
|
||||
// Get returns nil and an error which responds true to ormerrors.IsNotFound() if the record was not found.
|
||||
Get(ctx context.Context, id uint64) (*ExampleDuration, error)
|
||||
List(ctx context.Context, prefixKey ExampleDurationIndexKey, opts ...ormlist.Option) (ExampleDurationIterator, error)
|
||||
ListRange(ctx context.Context, from, to ExampleDurationIndexKey, opts ...ormlist.Option) (ExampleDurationIterator, error)
|
||||
DeleteBy(ctx context.Context, prefixKey ExampleDurationIndexKey) error
|
||||
DeleteRange(ctx context.Context, from, to ExampleDurationIndexKey) error
|
||||
|
||||
doNotImplement()
|
||||
}
|
||||
|
||||
type ExampleDurationIterator struct {
|
||||
ormtable.Iterator
|
||||
}
|
||||
|
||||
func (i ExampleDurationIterator) Value() (*ExampleDuration, error) {
|
||||
var exampleDuration ExampleDuration
|
||||
err := i.UnmarshalMessage(&exampleDuration)
|
||||
return &exampleDuration, err
|
||||
}
|
||||
|
||||
type ExampleDurationIndexKey interface {
|
||||
id() uint32
|
||||
values() []interface{}
|
||||
exampleDurationIndexKey()
|
||||
}
|
||||
|
||||
// primary key starting index..
|
||||
type ExampleDurationPrimaryKey = ExampleDurationIdIndexKey
|
||||
|
||||
type ExampleDurationIdIndexKey struct {
|
||||
vs []interface{}
|
||||
}
|
||||
|
||||
func (x ExampleDurationIdIndexKey) id() uint32 { return 0 }
|
||||
func (x ExampleDurationIdIndexKey) values() []interface{} { return x.vs }
|
||||
func (x ExampleDurationIdIndexKey) exampleDurationIndexKey() {}
|
||||
|
||||
func (this ExampleDurationIdIndexKey) WithId(id uint64) ExampleDurationIdIndexKey {
|
||||
this.vs = []interface{}{id}
|
||||
return this
|
||||
}
|
||||
|
||||
type ExampleDurationDurIndexKey struct {
|
||||
vs []interface{}
|
||||
}
|
||||
|
||||
func (x ExampleDurationDurIndexKey) id() uint32 { return 1 }
|
||||
func (x ExampleDurationDurIndexKey) values() []interface{} { return x.vs }
|
||||
func (x ExampleDurationDurIndexKey) exampleDurationIndexKey() {}
|
||||
|
||||
func (this ExampleDurationDurIndexKey) WithDur(dur *durationpb.Duration) ExampleDurationDurIndexKey {
|
||||
this.vs = []interface{}{dur}
|
||||
return this
|
||||
}
|
||||
|
||||
type exampleDurationTable struct {
|
||||
table ormtable.AutoIncrementTable
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) Insert(ctx context.Context, exampleDuration *ExampleDuration) error {
|
||||
return this.table.Insert(ctx, exampleDuration)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) Update(ctx context.Context, exampleDuration *ExampleDuration) error {
|
||||
return this.table.Update(ctx, exampleDuration)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) Save(ctx context.Context, exampleDuration *ExampleDuration) error {
|
||||
return this.table.Save(ctx, exampleDuration)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) Delete(ctx context.Context, exampleDuration *ExampleDuration) error {
|
||||
return this.table.Delete(ctx, exampleDuration)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) InsertReturningId(ctx context.Context, exampleDuration *ExampleDuration) (uint64, error) {
|
||||
return this.table.InsertReturningPKey(ctx, exampleDuration)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) Has(ctx context.Context, id uint64) (found bool, err error) {
|
||||
return this.table.PrimaryKey().Has(ctx, id)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) Get(ctx context.Context, id uint64) (*ExampleDuration, error) {
|
||||
var exampleDuration ExampleDuration
|
||||
found, err := this.table.PrimaryKey().Get(ctx, &exampleDuration, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
return nil, ormerrors.NotFound
|
||||
}
|
||||
return &exampleDuration, nil
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) List(ctx context.Context, prefixKey ExampleDurationIndexKey, opts ...ormlist.Option) (ExampleDurationIterator, error) {
|
||||
it, err := this.table.GetIndexByID(prefixKey.id()).List(ctx, prefixKey.values(), opts...)
|
||||
return ExampleDurationIterator{it}, err
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) ListRange(ctx context.Context, from, to ExampleDurationIndexKey, opts ...ormlist.Option) (ExampleDurationIterator, error) {
|
||||
it, err := this.table.GetIndexByID(from.id()).ListRange(ctx, from.values(), to.values(), opts...)
|
||||
return ExampleDurationIterator{it}, err
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) DeleteBy(ctx context.Context, prefixKey ExampleDurationIndexKey) error {
|
||||
return this.table.GetIndexByID(prefixKey.id()).DeleteBy(ctx, prefixKey.values()...)
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) DeleteRange(ctx context.Context, from, to ExampleDurationIndexKey) error {
|
||||
return this.table.GetIndexByID(from.id()).DeleteRange(ctx, from.values(), to.values())
|
||||
}
|
||||
|
||||
func (this exampleDurationTable) doNotImplement() {}
|
||||
|
||||
var _ ExampleDurationTable = exampleDurationTable{}
|
||||
|
||||
func NewExampleDurationTable(db ormtable.Schema) (ExampleDurationTable, error) {
|
||||
table := db.GetTable(&ExampleDuration{})
|
||||
if table == nil {
|
||||
return nil, ormerrors.TableNotFound.Wrap(string((&ExampleDuration{}).ProtoReflect().Descriptor().FullName()))
|
||||
}
|
||||
return exampleDurationTable{table.(ormtable.AutoIncrementTable)}, nil
|
||||
}
|
||||
|
||||
type SimpleExampleTable interface {
|
||||
Insert(ctx context.Context, simpleExample *SimpleExample) error
|
||||
Update(ctx context.Context, simpleExample *SimpleExample) error
|
||||
@ -819,6 +952,7 @@ type TestSchemaStore interface {
|
||||
ExampleAutoIncrementTableTable() ExampleAutoIncrementTableTable
|
||||
ExampleSingletonTable() ExampleSingletonTable
|
||||
ExampleTimestampTable() ExampleTimestampTable
|
||||
ExampleDurationTable() ExampleDurationTable
|
||||
SimpleExampleTable() SimpleExampleTable
|
||||
ExampleAutoIncFieldNameTable() ExampleAutoIncFieldNameTable
|
||||
|
||||
@ -830,6 +964,7 @@ type testSchemaStore struct {
|
||||
exampleAutoIncrementTable ExampleAutoIncrementTableTable
|
||||
exampleSingleton ExampleSingletonTable
|
||||
exampleTimestamp ExampleTimestampTable
|
||||
exampleDuration ExampleDurationTable
|
||||
simpleExample SimpleExampleTable
|
||||
exampleAutoIncFieldName ExampleAutoIncFieldNameTable
|
||||
}
|
||||
@ -850,6 +985,10 @@ func (x testSchemaStore) ExampleTimestampTable() ExampleTimestampTable {
|
||||
return x.exampleTimestamp
|
||||
}
|
||||
|
||||
func (x testSchemaStore) ExampleDurationTable() ExampleDurationTable {
|
||||
return x.exampleDuration
|
||||
}
|
||||
|
||||
func (x testSchemaStore) SimpleExampleTable() SimpleExampleTable {
|
||||
return x.simpleExample
|
||||
}
|
||||
@ -883,6 +1022,11 @@ func NewTestSchemaStore(db ormtable.Schema) (TestSchemaStore, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exampleDurationTable, err := NewExampleDurationTable(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
simpleExampleTable, err := NewSimpleExampleTable(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -898,6 +1042,7 @@ func NewTestSchemaStore(db ormtable.Schema) (TestSchemaStore, error) {
|
||||
exampleAutoIncrementTableTable,
|
||||
exampleSingletonTable,
|
||||
exampleTimestampTable,
|
||||
exampleDurationTable,
|
||||
simpleExampleTable,
|
||||
exampleAutoIncFieldNameTable,
|
||||
}, nil
|
||||
|
||||
@ -480,6 +480,69 @@ func (x *ExampleTimestamp) GetTs() *timestamppb.Timestamp {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExampleDuration struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Dur *durationpb.Duration `protobuf:"bytes,3,opt,name=dur,proto3" json:"dur,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ExampleDuration) Reset() {
|
||||
*x = ExampleDuration{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ExampleDuration) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ExampleDuration) ProtoMessage() {}
|
||||
|
||||
func (x *ExampleDuration) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_testpb_test_schema_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 ExampleDuration.ProtoReflect.Descriptor instead.
|
||||
func (*ExampleDuration) Descriptor() ([]byte, []int) {
|
||||
return file_testpb_test_schema_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ExampleDuration) GetId() uint64 {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ExampleDuration) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExampleDuration) GetDur() *durationpb.Duration {
|
||||
if x != nil {
|
||||
return x.Dur
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SimpleExample struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -493,7 +556,7 @@ type SimpleExample struct {
|
||||
func (x *SimpleExample) Reset() {
|
||||
*x = SimpleExample{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[4]
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -506,7 +569,7 @@ func (x *SimpleExample) String() string {
|
||||
func (*SimpleExample) ProtoMessage() {}
|
||||
|
||||
func (x *SimpleExample) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[4]
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -519,7 +582,7 @@ func (x *SimpleExample) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use SimpleExample.ProtoReflect.Descriptor instead.
|
||||
func (*SimpleExample) Descriptor() ([]byte, []int) {
|
||||
return file_testpb_test_schema_proto_rawDescGZIP(), []int{4}
|
||||
return file_testpb_test_schema_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *SimpleExample) GetName() string {
|
||||
@ -556,7 +619,7 @@ type ExampleAutoIncFieldName struct {
|
||||
func (x *ExampleAutoIncFieldName) Reset() {
|
||||
*x = ExampleAutoIncFieldName{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[5]
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -569,7 +632,7 @@ func (x *ExampleAutoIncFieldName) String() string {
|
||||
func (*ExampleAutoIncFieldName) ProtoMessage() {}
|
||||
|
||||
func (x *ExampleAutoIncFieldName) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[5]
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -582,7 +645,7 @@ func (x *ExampleAutoIncFieldName) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ExampleAutoIncFieldName.ProtoReflect.Descriptor instead.
|
||||
func (*ExampleAutoIncFieldName) Descriptor() ([]byte, []int) {
|
||||
return file_testpb_test_schema_proto_rawDescGZIP(), []int{5}
|
||||
return file_testpb_test_schema_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *ExampleAutoIncFieldName) GetFoo() uint64 {
|
||||
@ -611,7 +674,7 @@ type ExampleTable_ExampleMessage struct {
|
||||
func (x *ExampleTable_ExampleMessage) Reset() {
|
||||
*x = ExampleTable_ExampleMessage{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[7]
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -624,7 +687,7 @@ func (x *ExampleTable_ExampleMessage) String() string {
|
||||
func (*ExampleTable_ExampleMessage) ProtoMessage() {}
|
||||
|
||||
func (x *ExampleTable_ExampleMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[7]
|
||||
mi := &file_testpb_test_schema_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -727,35 +790,43 @@ var file_testpb_test_schema_proto_rawDesc = []byte{
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x52, 0x02, 0x74, 0x73, 0x3a, 0x18, 0xf2, 0x9e, 0xd3, 0x8e, 0x03, 0x12, 0x0a, 0x06,
|
||||
0x0a, 0x02, 0x69, 0x64, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x74, 0x73, 0x10, 0x01, 0x18, 0x04,
|
||||
0x22, 0x7a, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x6e, 0x6f, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x3a, 0x1e, 0xf2, 0x9e,
|
||||
0xd3, 0x8e, 0x03, 0x18, 0x0a, 0x06, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0c, 0x0a, 0x06,
|
||||
0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x10, 0x01, 0x18, 0x01, 0x18, 0x05, 0x22, 0x50, 0x0a, 0x17,
|
||||
0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x49, 0x6e, 0x63, 0x46, 0x69,
|
||||
0x65, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x11, 0xf2, 0x9e, 0xd3,
|
||||
0x8e, 0x03, 0x0b, 0x0a, 0x07, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x10, 0x01, 0x18, 0x06, 0x2a, 0x64,
|
||||
0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55,
|
||||
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08,
|
||||
0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x4e,
|
||||
0x55, 0x4d, 0x5f, 0x54, 0x57, 0x4f, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x4e, 0x55, 0x4d,
|
||||
0x5f, 0x46, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x0e, 0x45, 0x4e, 0x55, 0x4d, 0x5f,
|
||||
0x4e, 0x45, 0x47, 0x5f, 0x54, 0x48, 0x52, 0x45, 0x45, 0x10, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x01, 0x42, 0x87, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73,
|
||||
0x74, 0x70, 0x62, 0x42, 0x0f, 0x54, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x50,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
|
||||
0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02,
|
||||
0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62,
|
||||
0xe2, 0x02, 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
|
||||
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x22, 0x7d, 0x0a, 0x0f, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x03, 0x64, 0x75, 0x72, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
|
||||
0x03, 0x64, 0x75, 0x72, 0x3a, 0x19, 0xf2, 0x9e, 0xd3, 0x8e, 0x03, 0x13, 0x0a, 0x06, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x64, 0x75, 0x72, 0x10, 0x01, 0x18, 0x04, 0x22,
|
||||
0x7a, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x6e, 0x6f, 0x74, 0x5f, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x09, 0x6e, 0x6f, 0x74, 0x55, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x3a, 0x1e, 0xf2, 0x9e, 0xd3,
|
||||
0x8e, 0x03, 0x18, 0x0a, 0x06, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0c, 0x0a, 0x06, 0x75,
|
||||
0x6e, 0x69, 0x71, 0x75, 0x65, 0x10, 0x01, 0x18, 0x01, 0x18, 0x05, 0x22, 0x50, 0x0a, 0x17, 0x45,
|
||||
0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x49, 0x6e, 0x63, 0x46, 0x69, 0x65,
|
||||
0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x62, 0x61, 0x72, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x62, 0x61, 0x72, 0x3a, 0x11, 0xf2, 0x9e, 0xd3, 0x8e,
|
||||
0x03, 0x0b, 0x0a, 0x07, 0x0a, 0x03, 0x66, 0x6f, 0x6f, 0x10, 0x01, 0x18, 0x06, 0x2a, 0x64, 0x0a,
|
||||
0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x10, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x55, 0x4e,
|
||||
0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x45,
|
||||
0x4e, 0x55, 0x4d, 0x5f, 0x4f, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x45, 0x4e, 0x55,
|
||||
0x4d, 0x5f, 0x54, 0x57, 0x4f, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x45, 0x4e, 0x55, 0x4d, 0x5f,
|
||||
0x46, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x1b, 0x0a, 0x0e, 0x45, 0x4e, 0x55, 0x4d, 0x5f, 0x4e,
|
||||
0x45, 0x47, 0x5f, 0x54, 0x48, 0x52, 0x45, 0x45, 0x10, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x01, 0x42, 0x87, 0x01, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74,
|
||||
0x70, 0x62, 0x42, 0x0f, 0x54, 0x65, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x50, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d,
|
||||
0x73, 0x64, 0x6b, 0x2f, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x62, 0xa2, 0x02, 0x03, 0x54, 0x58, 0x58, 0xaa, 0x02, 0x06,
|
||||
0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xca, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0xe2,
|
||||
0x02, 0x12, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61,
|
||||
0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x06, 0x54, 0x65, 0x73, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -771,32 +842,34 @@ func file_testpb_test_schema_proto_rawDescGZIP() []byte {
|
||||
}
|
||||
|
||||
var file_testpb_test_schema_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_testpb_test_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_testpb_test_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_testpb_test_schema_proto_goTypes = []interface{}{
|
||||
(Enum)(0), // 0: testpb.Enum
|
||||
(*ExampleTable)(nil), // 1: testpb.ExampleTable
|
||||
(*ExampleAutoIncrementTable)(nil), // 2: testpb.ExampleAutoIncrementTable
|
||||
(*ExampleSingleton)(nil), // 3: testpb.ExampleSingleton
|
||||
(*ExampleTimestamp)(nil), // 4: testpb.ExampleTimestamp
|
||||
(*SimpleExample)(nil), // 5: testpb.SimpleExample
|
||||
(*ExampleAutoIncFieldName)(nil), // 6: testpb.ExampleAutoIncFieldName
|
||||
nil, // 7: testpb.ExampleTable.MapEntry
|
||||
(*ExampleTable_ExampleMessage)(nil), // 8: testpb.ExampleTable.ExampleMessage
|
||||
(*timestamppb.Timestamp)(nil), // 9: google.protobuf.Timestamp
|
||||
(*durationpb.Duration)(nil), // 10: google.protobuf.Duration
|
||||
(*ExampleDuration)(nil), // 5: testpb.ExampleDuration
|
||||
(*SimpleExample)(nil), // 6: testpb.SimpleExample
|
||||
(*ExampleAutoIncFieldName)(nil), // 7: testpb.ExampleAutoIncFieldName
|
||||
nil, // 8: testpb.ExampleTable.MapEntry
|
||||
(*ExampleTable_ExampleMessage)(nil), // 9: testpb.ExampleTable.ExampleMessage
|
||||
(*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp
|
||||
(*durationpb.Duration)(nil), // 11: google.protobuf.Duration
|
||||
}
|
||||
var file_testpb_test_schema_proto_depIdxs = []int32{
|
||||
9, // 0: testpb.ExampleTable.ts:type_name -> google.protobuf.Timestamp
|
||||
10, // 1: testpb.ExampleTable.dur:type_name -> google.protobuf.Duration
|
||||
10, // 0: testpb.ExampleTable.ts:type_name -> google.protobuf.Timestamp
|
||||
11, // 1: testpb.ExampleTable.dur:type_name -> google.protobuf.Duration
|
||||
0, // 2: testpb.ExampleTable.e:type_name -> testpb.Enum
|
||||
7, // 3: testpb.ExampleTable.map:type_name -> testpb.ExampleTable.MapEntry
|
||||
8, // 4: testpb.ExampleTable.msg:type_name -> testpb.ExampleTable.ExampleMessage
|
||||
9, // 5: testpb.ExampleTimestamp.ts:type_name -> google.protobuf.Timestamp
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
8, // 3: testpb.ExampleTable.map:type_name -> testpb.ExampleTable.MapEntry
|
||||
9, // 4: testpb.ExampleTable.msg:type_name -> testpb.ExampleTable.ExampleMessage
|
||||
10, // 5: testpb.ExampleTimestamp.ts:type_name -> google.protobuf.Timestamp
|
||||
11, // 6: testpb.ExampleDuration.dur:type_name -> google.protobuf.Duration
|
||||
7, // [7:7] is the sub-list for method output_type
|
||||
7, // [7:7] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_testpb_test_schema_proto_init() }
|
||||
@ -854,7 +927,7 @@ func file_testpb_test_schema_proto_init() {
|
||||
}
|
||||
}
|
||||
file_testpb_test_schema_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SimpleExample); i {
|
||||
switch v := v.(*ExampleDuration); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
@ -866,6 +939,18 @@ func file_testpb_test_schema_proto_init() {
|
||||
}
|
||||
}
|
||||
file_testpb_test_schema_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*SimpleExample); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_testpb_test_schema_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ExampleAutoIncFieldName); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -877,7 +962,7 @@ func file_testpb_test_schema_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_testpb_test_schema_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
file_testpb_test_schema_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ExampleTable_ExampleMessage); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
@ -899,7 +984,7 @@ func file_testpb_test_schema_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_testpb_test_schema_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 8,
|
||||
NumMessages: 9,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
||||
@ -107,6 +107,18 @@ message ExampleTimestamp {
|
||||
google.protobuf.Timestamp ts = 3;
|
||||
}
|
||||
|
||||
message ExampleDuration {
|
||||
option (cosmos.orm.v1.table) = {
|
||||
id: 4
|
||||
primary_key: {fields: "id" auto_increment: true}
|
||||
index: {id: 1 fields: "dur"}
|
||||
};
|
||||
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
google.protobuf.Duration dur = 3;
|
||||
}
|
||||
|
||||
message SimpleExample {
|
||||
option (cosmos.orm.v1.table) = {
|
||||
id: 5
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@ syntax = "proto3";
|
||||
package testpb;
|
||||
|
||||
import "cosmos/base/query/v1beta1/pagination.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "testpb/test_schema.proto";
|
||||
|
||||
@ -30,6 +31,10 @@ service TestSchemaQueryService {
|
||||
rpc GetExampleTimestamp(GetExampleTimestampRequest) returns (GetExampleTimestampResponse) {}
|
||||
// ListExampleTimestamp queries the ExampleTimestamp table using prefix and range queries against defined indexes.
|
||||
rpc ListExampleTimestamp(ListExampleTimestampRequest) returns (ListExampleTimestampResponse) {}
|
||||
// Get queries the ExampleDuration table by its primary key.
|
||||
rpc GetExampleDuration(GetExampleDurationRequest) returns (GetExampleDurationResponse) {}
|
||||
// ListExampleDuration queries the ExampleDuration table using prefix and range queries against defined indexes.
|
||||
rpc ListExampleDuration(ListExampleDurationRequest) returns (ListExampleDurationResponse) {}
|
||||
// Get queries the SimpleExample table by its primary key.
|
||||
rpc GetSimpleExample(GetSimpleExampleRequest) returns (GetSimpleExampleResponse) {}
|
||||
// GetSimpleExampleByUnique queries the SimpleExample table by its Unique index
|
||||
@ -308,6 +313,73 @@ message ListExampleTimestampResponse {
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// GetExampleDurationRequest is the TestSchemaQuery/GetExampleDurationRequest request type.
|
||||
message GetExampleDurationRequest {
|
||||
// id specifies the value of the id field in the primary key.
|
||||
uint64 id = 1;
|
||||
}
|
||||
|
||||
// GetExampleDurationResponse is the TestSchemaQuery/GetExampleDurationResponse response type.
|
||||
message GetExampleDurationResponse {
|
||||
// value is the response value.
|
||||
ExampleDuration value = 1;
|
||||
}
|
||||
|
||||
// ListExampleDurationRequest is the TestSchemaQuery/ListExampleDurationRequest request type.
|
||||
message ListExampleDurationRequest {
|
||||
// IndexKey specifies the value of an index key to use in prefix and range queries.
|
||||
message IndexKey {
|
||||
// key specifies the index key value.
|
||||
oneof key {
|
||||
// id specifies the value of the Id index key to use in the query.
|
||||
Id id = 1;
|
||||
// dur specifies the value of the Dur index key to use in the query.
|
||||
Dur dur = 2;
|
||||
}
|
||||
|
||||
message Id {
|
||||
// id is the value of the id field in the index.
|
||||
// It can be omitted to query for all valid values of that field in this segment of the index.
|
||||
optional uint64 id = 1;
|
||||
}
|
||||
|
||||
message Dur {
|
||||
// dur is the value of the dur field in the index.
|
||||
// It can be omitted to query for all valid values of that field in this segment of the index.
|
||||
optional google.protobuf.Duration dur = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// query specifies the type of query - either a prefix or range query.
|
||||
oneof query {
|
||||
// prefix_query specifies the index key value to use for the prefix query.
|
||||
IndexKey prefix_query = 1;
|
||||
// range_query specifies the index key from/to values to use for the range query.
|
||||
RangeQuery range_query = 2;
|
||||
}
|
||||
// pagination specifies optional pagination parameters.
|
||||
cosmos.base.query.v1beta1.PageRequest pagination = 3;
|
||||
|
||||
// RangeQuery specifies the from/to index keys for a range query.
|
||||
message RangeQuery {
|
||||
// from is the index key to use for the start of the range query.
|
||||
// To query from the start of an index, specify an index key for that index with empty values.
|
||||
IndexKey from = 1;
|
||||
// to is the index key to use for the end of the range query.
|
||||
// The index key type MUST be the same as the index key type used for from.
|
||||
// To query from to the end of an index it can be omitted.
|
||||
IndexKey to = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// ListExampleDurationResponse is the TestSchemaQuery/ListExampleDurationResponse response type.
|
||||
message ListExampleDurationResponse {
|
||||
// values are the results of the query.
|
||||
repeated ExampleDuration values = 1;
|
||||
// pagination is the pagination response.
|
||||
cosmos.base.query.v1beta1.PageResponse pagination = 2;
|
||||
}
|
||||
|
||||
// GetSimpleExampleRequest is the TestSchemaQuery/GetSimpleExampleRequest request type.
|
||||
message GetSimpleExampleRequest {
|
||||
// name specifies the value of the name field in the primary key.
|
||||
|
||||
@ -40,6 +40,10 @@ type TestSchemaQueryServiceClient interface {
|
||||
GetExampleTimestamp(ctx context.Context, in *GetExampleTimestampRequest, opts ...grpc.CallOption) (*GetExampleTimestampResponse, error)
|
||||
// ListExampleTimestamp queries the ExampleTimestamp table using prefix and range queries against defined indexes.
|
||||
ListExampleTimestamp(ctx context.Context, in *ListExampleTimestampRequest, opts ...grpc.CallOption) (*ListExampleTimestampResponse, error)
|
||||
// Get queries the ExampleDuration table by its primary key.
|
||||
GetExampleDuration(ctx context.Context, in *GetExampleDurationRequest, opts ...grpc.CallOption) (*GetExampleDurationResponse, error)
|
||||
// ListExampleDuration queries the ExampleDuration table using prefix and range queries against defined indexes.
|
||||
ListExampleDuration(ctx context.Context, in *ListExampleDurationRequest, opts ...grpc.CallOption) (*ListExampleDurationResponse, error)
|
||||
// Get queries the SimpleExample table by its primary key.
|
||||
GetSimpleExample(ctx context.Context, in *GetSimpleExampleRequest, opts ...grpc.CallOption) (*GetSimpleExampleResponse, error)
|
||||
// GetSimpleExampleByUnique queries the SimpleExample table by its Unique index
|
||||
@ -141,6 +145,24 @@ func (c *testSchemaQueryServiceClient) ListExampleTimestamp(ctx context.Context,
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testSchemaQueryServiceClient) GetExampleDuration(ctx context.Context, in *GetExampleDurationRequest, opts ...grpc.CallOption) (*GetExampleDurationResponse, error) {
|
||||
out := new(GetExampleDurationResponse)
|
||||
err := c.cc.Invoke(ctx, "/testpb.TestSchemaQueryService/GetExampleDuration", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testSchemaQueryServiceClient) ListExampleDuration(ctx context.Context, in *ListExampleDurationRequest, opts ...grpc.CallOption) (*ListExampleDurationResponse, error) {
|
||||
out := new(ListExampleDurationResponse)
|
||||
err := c.cc.Invoke(ctx, "/testpb.TestSchemaQueryService/ListExampleDuration", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *testSchemaQueryServiceClient) GetSimpleExample(ctx context.Context, in *GetSimpleExampleRequest, opts ...grpc.CallOption) (*GetSimpleExampleResponse, error) {
|
||||
out := new(GetSimpleExampleResponse)
|
||||
err := c.cc.Invoke(ctx, "/testpb.TestSchemaQueryService/GetSimpleExample", in, out, opts...)
|
||||
@ -208,6 +230,10 @@ type TestSchemaQueryServiceServer interface {
|
||||
GetExampleTimestamp(context.Context, *GetExampleTimestampRequest) (*GetExampleTimestampResponse, error)
|
||||
// ListExampleTimestamp queries the ExampleTimestamp table using prefix and range queries against defined indexes.
|
||||
ListExampleTimestamp(context.Context, *ListExampleTimestampRequest) (*ListExampleTimestampResponse, error)
|
||||
// Get queries the ExampleDuration table by its primary key.
|
||||
GetExampleDuration(context.Context, *GetExampleDurationRequest) (*GetExampleDurationResponse, error)
|
||||
// ListExampleDuration queries the ExampleDuration table using prefix and range queries against defined indexes.
|
||||
ListExampleDuration(context.Context, *ListExampleDurationRequest) (*ListExampleDurationResponse, error)
|
||||
// Get queries the SimpleExample table by its primary key.
|
||||
GetSimpleExample(context.Context, *GetSimpleExampleRequest) (*GetSimpleExampleResponse, error)
|
||||
// GetSimpleExampleByUnique queries the SimpleExample table by its Unique index
|
||||
@ -252,6 +278,12 @@ func (UnimplementedTestSchemaQueryServiceServer) GetExampleTimestamp(context.Con
|
||||
func (UnimplementedTestSchemaQueryServiceServer) ListExampleTimestamp(context.Context, *ListExampleTimestampRequest) (*ListExampleTimestampResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListExampleTimestamp not implemented")
|
||||
}
|
||||
func (UnimplementedTestSchemaQueryServiceServer) GetExampleDuration(context.Context, *GetExampleDurationRequest) (*GetExampleDurationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetExampleDuration not implemented")
|
||||
}
|
||||
func (UnimplementedTestSchemaQueryServiceServer) ListExampleDuration(context.Context, *ListExampleDurationRequest) (*ListExampleDurationResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListExampleDuration not implemented")
|
||||
}
|
||||
func (UnimplementedTestSchemaQueryServiceServer) GetSimpleExample(context.Context, *GetSimpleExampleRequest) (*GetSimpleExampleResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetSimpleExample not implemented")
|
||||
}
|
||||
@ -443,6 +475,42 @@ func _TestSchemaQueryService_ListExampleTimestamp_Handler(srv interface{}, ctx c
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TestSchemaQueryService_GetExampleDuration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetExampleDurationRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TestSchemaQueryServiceServer).GetExampleDuration(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/testpb.TestSchemaQueryService/GetExampleDuration",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TestSchemaQueryServiceServer).GetExampleDuration(ctx, req.(*GetExampleDurationRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TestSchemaQueryService_ListExampleDuration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListExampleDurationRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TestSchemaQueryServiceServer).ListExampleDuration(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/testpb.TestSchemaQueryService/ListExampleDuration",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TestSchemaQueryServiceServer).ListExampleDuration(ctx, req.(*ListExampleDurationRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _TestSchemaQueryService_GetSimpleExample_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetSimpleExampleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -576,6 +644,14 @@ var TestSchemaQueryService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ListExampleTimestamp",
|
||||
Handler: _TestSchemaQueryService_ListExampleTimestamp_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetExampleDuration",
|
||||
Handler: _TestSchemaQueryService_GetExampleDuration_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListExampleDuration",
|
||||
Handler: _TestSchemaQueryService_ListExampleDuration_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetSimpleExample",
|
||||
Handler: _TestSchemaQueryService_GetSimpleExample_Handler,
|
||||
|
||||
@ -84,8 +84,8 @@ var TestFieldSpecs = []TestFieldSpec{
|
||||
if isNil >= 0.95 { // draw a nil 5% of the time
|
||||
return nil
|
||||
}
|
||||
seconds := rapid.Int64Range(-9999999999, 9999999999).Draw(t, "seconds")
|
||||
nanos := rapid.Int32Range(0, 999999999).Draw(t, "nanos")
|
||||
seconds := rapid.Int64Range(ormfield.TimestampSecondsMin, ormfield.TimestampSecondsMax).Draw(t, "seconds")
|
||||
nanos := rapid.Int32Range(0, ormfield.TimestampNanosMax).Draw(t, "nanos")
|
||||
return (×tamppb.Timestamp{
|
||||
Seconds: seconds,
|
||||
Nanos: nanos,
|
||||
@ -95,8 +95,15 @@ var TestFieldSpecs = []TestFieldSpec{
|
||||
{
|
||||
"dur",
|
||||
rapid.Custom(func(t *rapid.T) protoreflect.Message {
|
||||
seconds := rapid.Int64Range(0, 315576000000).Draw(t, "seconds")
|
||||
nanos := rapid.Int32Range(0, 999999999).Draw(t, "nanos")
|
||||
isNil := rapid.Float32().Draw(t, "isNil")
|
||||
if isNil >= 0.95 { // draw a nil 5% of the time
|
||||
return nil
|
||||
}
|
||||
seconds := rapid.Int64Range(ormfield.DurationNanosMin, ormfield.DurationNanosMax).Draw(t, "seconds")
|
||||
nanos := rapid.Int32Range(0, ormfield.DurationNanosMax).Draw(t, "nanos")
|
||||
if seconds < 0 {
|
||||
nanos = -nanos
|
||||
}
|
||||
return (&durationpb.Duration{
|
||||
Seconds: seconds,
|
||||
Nanos: nanos,
|
||||
|
||||
103
orm/model/ormtable/duration_test.go
Normal file
103
orm/model/ormtable/duration_test.go
Normal file
@ -0,0 +1,103 @@
|
||||
package ormtable_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/orm/internal/testkv"
|
||||
"github.com/cosmos/cosmos-sdk/orm/internal/testpb"
|
||||
"github.com/cosmos/cosmos-sdk/orm/model/ormtable"
|
||||
)
|
||||
|
||||
func TestDurationIndex(t *testing.T) {
|
||||
table, err := ormtable.Build(ormtable.Options{
|
||||
MessageType: (&testpb.ExampleDuration{}).ProtoReflect().Type(),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
backend := testkv.NewDebugBackend(testkv.NewSplitMemBackend(), &testkv.EntryCodecDebugger{
|
||||
EntryCodec: table,
|
||||
})
|
||||
ctx := ormtable.WrapContextDefault(backend)
|
||||
store, err := testpb.NewExampleDurationTable(table)
|
||||
assert.NilError(t, err)
|
||||
|
||||
neg, err := time.ParseDuration("-1h")
|
||||
assert.NilError(t, err)
|
||||
zero, err := time.ParseDuration("0")
|
||||
assert.NilError(t, err)
|
||||
pos, err := time.ParseDuration("11000ms")
|
||||
assert.NilError(t, err)
|
||||
|
||||
negPb, zeroPb, posPb := durationpb.New(neg), durationpb.New(zero), durationpb.New(pos)
|
||||
durOrder := []*durationpb.Duration{negPb, zeroPb, posPb}
|
||||
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleDuration{
|
||||
Name: "foo",
|
||||
Dur: negPb,
|
||||
}))
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleDuration{
|
||||
Name: "bar",
|
||||
Dur: zeroPb,
|
||||
}))
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleDuration{
|
||||
Name: "baz",
|
||||
Dur: posPb,
|
||||
}))
|
||||
|
||||
from, to := testpb.ExampleDurationDurIndexKey{}.WithDur(durationpb.New(neg)),
|
||||
testpb.ExampleDurationDurIndexKey{}.WithDur(durationpb.New(pos))
|
||||
it, err := store.ListRange(ctx, from, to)
|
||||
assert.NilError(t, err)
|
||||
|
||||
i := 0
|
||||
for it.Next() {
|
||||
v, err := it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, durOrder[i].String(), v.Dur.String())
|
||||
i++
|
||||
}
|
||||
|
||||
// insert a nil entry
|
||||
id, err := store.InsertReturningId(ctx, &testpb.ExampleDuration{
|
||||
Name: "nil",
|
||||
Dur: nil,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := store.Get(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, res.Dur == nil)
|
||||
|
||||
it, err = store.List(ctx, testpb.ExampleDurationDurIndexKey{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// make sure nils are ordered last
|
||||
durOrder = append(durOrder, nil)
|
||||
i = 0
|
||||
for it.Next() {
|
||||
v, err := it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, v != nil)
|
||||
x := durOrder[i]
|
||||
if x == nil {
|
||||
assert.Assert(t, v.Dur == nil)
|
||||
} else {
|
||||
assert.Equal(t, x.String(), v.Dur.String())
|
||||
}
|
||||
i++
|
||||
}
|
||||
it.Close()
|
||||
|
||||
// try iterating over just nil timestamps
|
||||
it, err = store.List(ctx, testpb.ExampleDurationDurIndexKey{}.WithDur(nil))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, it.Next())
|
||||
res, err = it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, res.Dur == nil)
|
||||
assert.Assert(t, !it.Next())
|
||||
it.Close()
|
||||
}
|
||||
@ -7,9 +7,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
|
||||
@ -101,98 +98,6 @@ func TestPaginationLimitCountTotal(t *testing.T) {
|
||||
assert.Equal(t, uint64(3), pr.Total)
|
||||
}
|
||||
|
||||
func TestTimestampIndex(t *testing.T) {
|
||||
table, err := ormtable.Build(ormtable.Options{
|
||||
MessageType: (&testpb.ExampleTimestamp{}).ProtoReflect().Type(),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
backend := testkv.NewDebugBackend(testkv.NewSplitMemBackend(), &testkv.EntryCodecDebugger{
|
||||
EntryCodec: table,
|
||||
Print: func(s string) {
|
||||
t.Log(s)
|
||||
},
|
||||
})
|
||||
ctx := ormtable.WrapContextDefault(backend)
|
||||
store, err := testpb.NewExampleTimestampTable(table)
|
||||
assert.NilError(t, err)
|
||||
|
||||
past, err := time.Parse("2006-01-02", "2000-01-01")
|
||||
assert.NilError(t, err)
|
||||
middle, err := time.Parse("2006-01-02", "2020-01-01")
|
||||
assert.NilError(t, err)
|
||||
future, err := time.Parse("2006-01-02", "2049-01-01")
|
||||
assert.NilError(t, err)
|
||||
|
||||
pastPb, middlePb, futurePb := timestamppb.New(past), timestamppb.New(middle), timestamppb.New(future)
|
||||
timeOrder := []*timestamppb.Timestamp{pastPb, middlePb, futurePb}
|
||||
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "foo",
|
||||
Ts: pastPb,
|
||||
}))
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "bar",
|
||||
Ts: middlePb,
|
||||
}))
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "baz",
|
||||
Ts: futurePb,
|
||||
}))
|
||||
|
||||
from, to := testpb.ExampleTimestampTsIndexKey{}.WithTs(timestamppb.New(past)), testpb.ExampleTimestampTsIndexKey{}.WithTs(timestamppb.New(future))
|
||||
it, err := store.ListRange(ctx, from, to)
|
||||
assert.NilError(t, err)
|
||||
|
||||
i := 0
|
||||
for it.Next() {
|
||||
v, err := it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, timeOrder[i].String(), v.Ts.String())
|
||||
i++
|
||||
}
|
||||
|
||||
// insert a nil entry
|
||||
id, err := store.InsertReturningId(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "nil",
|
||||
Ts: nil,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := store.Get(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, res.Ts == nil)
|
||||
|
||||
it, err = store.List(ctx, testpb.ExampleTimestampTsIndexKey{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// make sure nils are ordered last
|
||||
timeOrder = append(timeOrder, nil)
|
||||
i = 0
|
||||
for it.Next() {
|
||||
v, err := it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, v != nil)
|
||||
x := timeOrder[i]
|
||||
if x == nil {
|
||||
assert.Assert(t, v.Ts == nil)
|
||||
} else {
|
||||
assert.Equal(t, x.String(), v.Ts.String())
|
||||
}
|
||||
i++
|
||||
}
|
||||
it.Close()
|
||||
|
||||
// try iterating over just nil timestamps
|
||||
it, err = store.List(ctx, testpb.ExampleTimestampTsIndexKey{}.WithTs(nil))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, it.Next())
|
||||
res, err = it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, res.Ts == nil)
|
||||
assert.Assert(t, !it.Next())
|
||||
it.Close()
|
||||
}
|
||||
|
||||
// check that the ormkv.Entry's decode and encode to the same bytes
|
||||
func checkEncodeDecodeEntries(t *testing.T, table ormtable.Table, store kv.ReadonlyStore) {
|
||||
it, err := store.Iterator(nil, nil)
|
||||
|
||||
103
orm/model/ormtable/timestamp_test.go
Normal file
103
orm/model/ormtable/timestamp_test.go
Normal file
@ -0,0 +1,103 @@
|
||||
package ormtable_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/orm/internal/testkv"
|
||||
"github.com/cosmos/cosmos-sdk/orm/internal/testpb"
|
||||
"github.com/cosmos/cosmos-sdk/orm/model/ormtable"
|
||||
)
|
||||
|
||||
func TestTimestampIndex(t *testing.T) {
|
||||
table, err := ormtable.Build(ormtable.Options{
|
||||
MessageType: (&testpb.ExampleTimestamp{}).ProtoReflect().Type(),
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
backend := testkv.NewDebugBackend(testkv.NewSplitMemBackend(), &testkv.EntryCodecDebugger{
|
||||
EntryCodec: table,
|
||||
})
|
||||
ctx := ormtable.WrapContextDefault(backend)
|
||||
store, err := testpb.NewExampleTimestampTable(table)
|
||||
assert.NilError(t, err)
|
||||
|
||||
past, err := time.Parse("2006-01-02", "2000-01-01")
|
||||
assert.NilError(t, err)
|
||||
middle, err := time.Parse("2006-01-02", "2020-01-01")
|
||||
assert.NilError(t, err)
|
||||
future, err := time.Parse("2006-01-02", "2049-01-01")
|
||||
assert.NilError(t, err)
|
||||
|
||||
pastPb, middlePb, futurePb := timestamppb.New(past), timestamppb.New(middle), timestamppb.New(future)
|
||||
timeOrder := []*timestamppb.Timestamp{pastPb, middlePb, futurePb}
|
||||
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "foo",
|
||||
Ts: pastPb,
|
||||
}))
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "bar",
|
||||
Ts: middlePb,
|
||||
}))
|
||||
assert.NilError(t, store.Insert(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "baz",
|
||||
Ts: futurePb,
|
||||
}))
|
||||
|
||||
from, to := testpb.ExampleTimestampTsIndexKey{}.WithTs(timestamppb.New(past)), testpb.ExampleTimestampTsIndexKey{}.WithTs(timestamppb.New(future))
|
||||
it, err := store.ListRange(ctx, from, to)
|
||||
assert.NilError(t, err)
|
||||
|
||||
i := 0
|
||||
for it.Next() {
|
||||
v, err := it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Equal(t, timeOrder[i].String(), v.Ts.String())
|
||||
i++
|
||||
}
|
||||
|
||||
// insert a nil entry
|
||||
id, err := store.InsertReturningId(ctx, &testpb.ExampleTimestamp{
|
||||
Name: "nil",
|
||||
Ts: nil,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
res, err := store.Get(ctx, id)
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, res.Ts == nil)
|
||||
|
||||
it, err = store.List(ctx, testpb.ExampleTimestampTsIndexKey{})
|
||||
assert.NilError(t, err)
|
||||
|
||||
// make sure nils are ordered last
|
||||
timeOrder = append(timeOrder, nil)
|
||||
i = 0
|
||||
for it.Next() {
|
||||
v, err := it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, v != nil)
|
||||
x := timeOrder[i]
|
||||
if x == nil {
|
||||
assert.Assert(t, v.Ts == nil)
|
||||
} else {
|
||||
assert.Equal(t, x.String(), v.Ts.String())
|
||||
}
|
||||
i++
|
||||
}
|
||||
it.Close()
|
||||
|
||||
// try iterating over just nil timestamps
|
||||
it, err = store.List(ctx, testpb.ExampleTimestampTsIndexKey{}.WithTs(nil))
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, it.Next())
|
||||
res, err = it.Value()
|
||||
assert.NilError(t, err)
|
||||
assert.Assert(t, res.Ts == nil)
|
||||
assert.Assert(t, !it.Next())
|
||||
it.Close()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user