Drop duration type

This commit is contained in:
Asdine El Hrychy
2020-09-28 22:32:06 +04:00
parent e146328321
commit dfdbc16b18
24 changed files with 11 additions and 312 deletions

View File

@@ -4,7 +4,6 @@ import (
"encoding/base64"
"fmt"
"strconv"
"time"
)
// CastAs casts v as the selected type when possible.
@@ -25,8 +24,6 @@ func (v Value) CastAs(t ValueType) (Value, error) {
return v.CastAsInteger()
case DoubleValue:
return v.CastAsDouble()
case DurationValue:
return v.CastAsDuration()
case BlobValue:
return v.CastAsBlob()
case TextValue:
@@ -65,7 +62,6 @@ func (v Value) CastAsBool() (Value, error) {
// CastAsInteger casts according to the following rules:
// Bool: returns 1 if true, 0 if false.
// Double: cuts off the decimal and remaining numbers.
// Duration: returns the number of nanoseconds in the duration.
// Text: uses strconv.ParseInt to determine the integer value,
// then casts it to an integer. If it fails uses strconv.ParseFloat
// to determine the double value, then casts it to an integer
@@ -82,8 +78,6 @@ func (v Value) CastAsInteger() (Value, error) {
return NewIntegerValue(0), nil
case DoubleValue:
return NewIntegerValue(int64(v.V.(float64))), nil
case DurationValue:
return NewIntegerValue(int64(v.V.(time.Duration))), nil
case TextValue:
i, err := strconv.ParseInt(v.V.(string), 10, 64)
if err != nil {
@@ -122,26 +116,6 @@ func (v Value) CastAsDouble() (Value, error) {
return Value{}, fmt.Errorf("cannot cast %s as double", v.Type)
}
// CastAsDuration casts according to the following rules:
// Text: decodes using time.ParseDuration, otherwise fails.
// Any other type is considered an invalid cast.
func (v Value) CastAsDuration() (Value, error) {
if v.Type == DurationValue {
return v, nil
}
if v.Type == TextValue {
d, err := time.ParseDuration(v.V.(string))
if err != nil {
return Value{}, fmt.Errorf(`cannot cast %q as duration: %w`, v.V, err)
}
return NewDurationValue(d), nil
}
return Value{}, fmt.Errorf("cannot cast %s as duration", v.Type)
}
// CastAsText returns a JSON representation of v.
// If the representation is a string, it gets unquoted.
func (v Value) CastAsText() (Value, error) {
@@ -156,7 +130,7 @@ func (v Value) CastAsText() (Value, error) {
s := string(d)
if v.Type == DurationValue || v.Type == BlobValue {
if v.Type == BlobValue {
s, err = strconv.Unquote(s)
if err != nil {
return Value{}, err

View File

@@ -2,7 +2,6 @@ package document
import (
"testing"
"time"
"github.com/stretchr/testify/require"
)
@@ -15,7 +14,6 @@ func TestCastAs(t *testing.T) {
boolV := NewBoolValue(true)
integerV := NewIntegerValue(10)
durationV := NewDurationValue(3 * time.Second)
doubleV := NewDoubleValue(10.5)
textV := NewTextValue("foo")
blobV := NewBlobValue([]byte("abc"))
@@ -45,7 +43,6 @@ func TestCastAs(t *testing.T) {
{boolV, boolV, false},
{integerV, boolV, false},
{NewIntegerValue(0), NewBoolValue(false), false},
{durationV, Value{}, true},
{doubleV, Value{}, true},
{textV, Value{}, true},
{NewTextValue("true"), boolV, false},
@@ -61,7 +58,6 @@ func TestCastAs(t *testing.T) {
{boolV, NewIntegerValue(1), false},
{NewBoolValue(false), NewIntegerValue(0), false},
{integerV, integerV, false},
{durationV, NewIntegerValue(int64(3 * time.Second)), false},
{doubleV, integerV, false},
{textV, Value{}, true},
{NewTextValue("10"), integerV, false},
@@ -76,7 +72,6 @@ func TestCastAs(t *testing.T) {
check(t, DoubleValue, []test{
{boolV, Value{}, true},
{integerV, NewDoubleValue(10), false},
{durationV, Value{}, true},
{doubleV, doubleV, false},
{textV, Value{}, true},
{NewTextValue("10"), NewDoubleValue(10), false},
@@ -87,26 +82,10 @@ func TestCastAs(t *testing.T) {
})
})
t.Run("duration", func(t *testing.T) {
check(t, DurationValue, []test{
{boolV, Value{}, true},
{integerV, Value{}, true},
{durationV, durationV, false},
{doubleV, Value{}, true},
{textV, Value{}, true},
{NewTextValue("3s"), durationV, false},
{NewTextValue("10.5"), Value{}, true},
{blobV, Value{}, true},
{arrayV, Value{}, true},
{docV, Value{}, true},
})
})
t.Run("text", func(t *testing.T) {
check(t, TextValue, []test{
{boolV, NewTextValue("true"), false},
{integerV, NewTextValue("10"), false},
{durationV, NewTextValue("3s"), false},
{doubleV, NewTextValue("10.5"), false},
{textV, textV, false},
{blobV, NewTextValue("YWJj"), false},
@@ -121,7 +100,6 @@ func TestCastAs(t *testing.T) {
check(t, BlobValue, []test{
{boolV, Value{}, true},
{integerV, Value{}, true},
{durationV, Value{}, true},
{doubleV, Value{}, true},
{NewTextValue("YWJj"), blobV, false},
{NewTextValue(" dww "), Value{}, true},
@@ -135,7 +113,6 @@ func TestCastAs(t *testing.T) {
check(t, ArrayValue, []test{
{boolV, Value{}, true},
{integerV, Value{}, true},
{durationV, Value{}, true},
{doubleV, Value{}, true},
{NewTextValue(`["bar", 10]`), arrayV, false},
{NewTextValue("abc"), Value{}, true},
@@ -149,7 +126,6 @@ func TestCastAs(t *testing.T) {
check(t, DocumentValue, []test{
{boolV, Value{}, true},
{integerV, Value{}, true},
{durationV, Value{}, true},
{doubleV, Value{}, true},
{NewTextValue(`{"a": 10, "b": "foo"}`), docV, false},
{NewTextValue("abc"), Value{}, true},

View File

@@ -3,7 +3,6 @@ package document
import (
"bytes"
"strings"
"time"
)
type operator uint8
@@ -94,10 +93,6 @@ func compare(op operator, l, r Value, compareDifferentTypes bool) (bool, error)
case l.Type.IsNumber() && r.Type.IsNumber():
return compareNumbers(op, l, r)
// compare durations together
case l.Type == DurationValue && r.Type == DurationValue:
return compareIntegers(op, int64(l.V.(time.Duration)), int64(r.V.(time.Duration))), nil
// compare arrays together
case l.Type == ArrayValue && r.Type == ArrayValue:
return compareArrays(op, l.V.(Array), r.V.(Array))

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"testing"
"time"
"github.com/genjidb/genji/document"
"github.com/stretchr/testify/require"
@@ -34,14 +33,6 @@ func jsonToBoolean(t testing.TB, x string) document.Value {
return document.NewBoolValue(b)
}
func jsonToDuration(t testing.TB, x string) document.Value {
var d time.Duration
err := json.Unmarshal([]byte(x), &d)
require.NoError(t, err)
return document.NewDurationValue(d)
}
func toText(t testing.TB, x string) document.Value {
return document.NewTextValue(x)
}
@@ -127,24 +118,6 @@ func TestCompare(t *testing.T) {
{"<=", "1", "2", true, jsonToDouble},
{"<=", "2", "2", true, jsonToDouble},
// duration
{"=", "2", "1", false, jsonToDuration},
{"=", "2", "2", true, jsonToDuration},
{"!=", "2", "1", true, jsonToDuration},
{"!=", "2", "2", false, jsonToDuration},
{">", "2", "1", true, jsonToDuration},
{">", "1", "2", false, jsonToDuration},
{">", "2", "2", false, jsonToDuration},
{">=", "2", "1", true, jsonToDuration},
{">=", "1", "2", false, jsonToDuration},
{">=", "2", "2", true, jsonToDuration},
{"<", "2", "1", false, jsonToDuration},
{"<", "1", "2", true, jsonToDuration},
{"<", "2", "2", false, jsonToDuration},
{"<=", "2", "1", false, jsonToDuration},
{"<=", "1", "2", true, jsonToDuration},
{"<=", "2", "2", true, jsonToDuration},
// text
{"=", "b", "a", false, toText},
{"=", "b", "b", true, toText},

View File

@@ -165,8 +165,6 @@ func (s structDocument) MarshalJSON() ([]byte, error) {
func NewValue(x interface{}) (Value, error) {
// Attempt exact matches first:
switch v := x.(type) {
case time.Duration:
return NewDurationValue(v), nil
case time.Time:
return NewTextValue(v.Format(time.RFC3339Nano)), nil
case nil:

View File

@@ -5,7 +5,6 @@ import (
"encoding/binary"
"errors"
"io"
"time"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/document/encoding"
@@ -128,8 +127,6 @@ func EncodeValue(v document.Value) ([]byte, error) {
return encodeInt64(v.V.(int64)), nil
case document.DoubleValue:
key.AppendFloat64(nil, v.V.(float64))
case document.DurationValue:
return encodeInt64(int64(v.V.(time.Duration))), nil
case document.NullValue:
return nil, nil
}
@@ -331,9 +328,6 @@ func DecodeValue(t document.ValueType, data []byte) (document.Value, error) {
return document.Value{}, err
}
return document.NewDoubleValue(x), nil
case document.DurationValue:
x, _ := binary.Varint(data)
return document.NewDurationValue(time.Duration(x)), nil
case document.NullValue:
return document.NewNullValue(), nil
}

View File

@@ -4,7 +4,6 @@ package encodingtest
import (
"bytes"
"testing"
"time"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/document/encoding"
@@ -97,8 +96,7 @@ func testArrayGetByIndex(t *testing.T, codecBuilder func() encoding.Codec) {
arr := document.NewValueBuffer().
Append(document.NewIntegerValue(10)).
Append(document.NewNullValue()).
Append(document.NewTextValue("john")).
Append(document.NewDurationValue(10 * time.Nanosecond))
Append(document.NewTextValue("john"))
var buf bytes.Buffer

View File

@@ -3,7 +3,6 @@ package msgpack
import (
"fmt"
"io"
"time"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/document/encoding"
@@ -11,11 +10,6 @@ import (
"github.com/vmihailenco/msgpack/v5/codes"
)
// List of custom types
const (
DurationType int8 = 0x1
)
// A Codec is a MessagePack implementation of an encoding.Codec.
type Codec struct{}
@@ -115,7 +109,6 @@ func (e *Encoder) EncodeArray(a document.Array) error {
// - int32 -> int32
// - int64 -> int64
// - float64 -> float64
// - duration -> custom type with code 0x1 and size 8
func (e *Encoder) EncodeValue(v document.Value) error {
switch v.Type {
case document.DocumentValue:
@@ -134,32 +127,6 @@ func (e *Encoder) EncodeValue(v document.Value) error {
return e.enc.EncodeInt64(v.V.(int64))
case document.DoubleValue:
return e.enc.EncodeFloat64(v.V.(float64))
case document.DurationValue:
// because messagepack doesn't have a duration type
// vmihailenco/msgpack EncodeDuration method
// encodes durations as int64 values.
// this means that the duration is lost during
// encoding and there is no way of knowing that
// an int64 is a duration during decoding.
// to avoid that, we create a custom duration type.
err := e.enc.EncodeExtHeader(DurationType, 8)
if err != nil {
return err
}
d := uint64(v.V.(time.Duration))
var buf [8]byte
buf[0] = byte(d >> 56)
buf[1] = byte(d >> 48)
buf[2] = byte(d >> 40)
buf[3] = byte(d >> 32)
buf[4] = byte(d >> 24)
buf[5] = byte(d >> 16)
buf[6] = byte(d >> 8)
buf[7] = byte(d)
_, err = e.enc.Writer().Write(buf[:])
return err
}
return e.enc.Encode(v.V)
@@ -228,36 +195,6 @@ func (d *Decoder) DecodeValue() (v document.Value, err error) {
return
}
// decode custom codes
if codes.IsExt(c) {
var tp int8
tp, _, err = d.dec.DecodeExtHeader()
if err != nil {
return
}
if tp != DurationType {
panic(fmt.Sprintf("unknown custom code %d", tp))
}
var buf [8]byte
err = d.dec.ReadFull(buf[:])
if err != nil {
return
}
n := (uint64(buf[0]) << 56) |
(uint64(buf[1]) << 48) |
(uint64(buf[2]) << 40) |
(uint64(buf[3]) << 32) |
(uint64(buf[4]) << 24) |
(uint64(buf[5]) << 16) |
(uint64(buf[6]) << 8) |
uint64(buf[7])
v.V = time.Duration(n)
v.Type = document.DurationValue
return
}
// decode the rest
switch c {
case codes.Nil:

View File

@@ -65,7 +65,6 @@ func TestScan(t *testing.T) {
Add("foo", document.NewTextValue("foo")).
Add("bar", document.NewTextValue("bar")),
)).
Add("o", document.NewDurationValue(10*time.Nanosecond)).
Add("p", document.NewTextValue(now.Format(time.RFC3339Nano))).
Add("r", document.NewDocumentValue(codec.NewDocument(buf.Bytes())))
@@ -89,11 +88,10 @@ func TestScan(t *testing.T) {
var l *foo = new(foo)
var m *foo
var n map[string]string
var o time.Duration
var p time.Time
var r map[string]interface{}
err = document.Scan(doc, &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &r)
err = document.Scan(doc, &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &p, &r)
require.NoError(t, err)
require.Equal(t, a, []byte("foo"))
require.Equal(t, b, "bar")
@@ -110,7 +108,6 @@ func TestScan(t *testing.T) {
require.Equal(t, &foo{Foo: "foo", Pub: &bar}, l)
require.Equal(t, &foo{Foo: "foo", Pub: &bar}, m)
require.Equal(t, map[string]string{"foo": "foo", "bar": "bar"}, n)
require.Equal(t, 10*time.Nanosecond, o)
require.Equal(t, now.Format(time.RFC3339Nano), p.Format(time.RFC3339Nano))
require.Equal(t, map[string]interface{}{
"foo": map[string]interface{}{
@@ -136,14 +133,14 @@ func TestScan(t *testing.T) {
m := make(map[string]interface{})
err := document.MapScan(doc, m)
require.NoError(t, err)
require.Len(t, m, 17)
require.Len(t, m, 16)
})
t.Run("MapPtr", func(t *testing.T) {
var m map[string]interface{}
err := document.MapScan(doc, &m)
require.NoError(t, err)
require.Len(t, m, 17)
require.Len(t, m, 16)
})
t.Run("Small Slice", func(t *testing.T) {

View File

@@ -7,7 +7,6 @@ import (
"fmt"
"math"
"strconv"
"time"
"github.com/buger/jsonparser"
)
@@ -16,7 +15,6 @@ var (
boolZeroValue = NewZeroValue(BoolValue)
integerZeroValue = NewZeroValue(IntegerValue)
doubleZeroValue = NewZeroValue(DoubleValue)
durationZeroValue = NewZeroValue(DurationValue)
blobZeroValue = NewZeroValue(BlobValue)
textZeroValue = NewZeroValue(TextValue)
arrayZeroValue = NewZeroValue(ArrayValue)
@@ -50,9 +48,6 @@ const (
// double family: 0xA0 to 0xAF
DoubleValue ValueType = 0xA0
// time family: 0xB0 to 0xBF
DurationValue ValueType = 0xB0
// string family: 0xC0 to 0xCF
TextValue ValueType = 0xC0
@@ -76,8 +71,6 @@ func (t ValueType) String() string {
return "integer"
case DoubleValue:
return "double"
case DurationValue:
return "duration"
case BlobValue:
return "blob"
case TextValue:
@@ -134,14 +127,6 @@ func NewDoubleValue(x float64) Value {
}
}
// NewDurationValue returns a value of type Duration.
func NewDurationValue(d time.Duration) Value {
return Value{
Type: DurationValue,
V: d,
}
}
// NewBlobValue encodes x and returns a value.
func NewBlobValue(x []byte) Value {
return Value{
@@ -186,8 +171,6 @@ func NewZeroValue(t ValueType) Value {
return NewIntegerValue(0)
case DoubleValue:
return NewDoubleValue(0)
case DurationValue:
return NewDurationValue(0)
case BlobValue:
return NewBlobValue(nil)
case TextValue:
@@ -221,8 +204,6 @@ func (v Value) IsZeroValue() (bool, error) {
return v.V == integerZeroValue.V, nil
case DoubleValue:
return v.V == doubleZeroValue.V, nil
case DurationValue:
return v.V == durationZeroValue.V, nil
case BlobValue:
return bytes.Compare(v.V.([]byte), blobZeroValue.V.([]byte)) == 0, nil
case TextValue:
@@ -278,8 +259,6 @@ func (v Value) MarshalJSON() ([]byte, error) {
}
return strconv.AppendFloat(nil, v.V.(float64), fmt, -1, 64), nil
case DurationValue:
return []byte(strconv.Quote(v.V.(time.Duration).String())), nil
case TextValue:
return []byte(strconv.Quote(v.V.(string))), nil
case BlobValue:
@@ -305,7 +284,7 @@ func (v Value) String() string {
return "NULL"
case TextValue:
return strconv.Quote(v.V.(string))
case BlobValue, DurationValue:
case BlobValue:
return fmt.Sprintf("%v", v.V)
}
@@ -375,18 +354,6 @@ func calculateValues(a, b Value, operator byte) (res Value, err error) {
return NewNullValue(), nil
}
if a.Type == DurationValue && b.Type == DurationValue {
res, err = calculateIntegers(a, b, operator)
if err != nil {
return
}
if operator != '&' && operator != '|' && operator != '^' {
return NewDurationValue(time.Duration(res.V.(int64))), nil
}
return
}
if a.Type.IsNumber() && b.Type.IsNumber() {
if a.Type == DoubleValue || b.Type == DoubleValue {
return calculateFloats(a, b, operator)
@@ -415,8 +382,6 @@ func convertNumberToInt64(v Value) (int64, error) {
return 0, errors.New(`cannot convert "double" value to "integer" without loss of precision`)
}
i = int64(f)
case DurationValue:
return int64(v.V.(time.Duration)), nil
}
return i, nil

View File

@@ -23,7 +23,6 @@ func TestValueString(t *testing.T) {
{"double", document.NewDoubleValue(10.1), "10.1"},
{"document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), "{\"a\": 10}"},
{"array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), "[10]"},
{"duration", document.NewDurationValue(10 * time.Nanosecond), "10ns"},
}
for _, test := range tests {
@@ -74,7 +73,6 @@ func TestNewValue(t *testing.T) {
{"null", nil, nil},
{"document", document.NewFieldBuffer().Add("a", document.NewIntegerValue(10)), document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))},
{"array", document.NewValueBuffer(document.NewIntegerValue(10)), document.NewValueBuffer(document.NewIntegerValue(10))},
{"duration", 10 * time.Nanosecond, 10 * time.Nanosecond},
{"time", now, now.Format(time.RFC3339Nano)},
{"bytes", myBytes("bar"), []byte("bar")},
{"string", myString("bar"), "bar"},
@@ -119,7 +117,6 @@ func TestValueAdd(t *testing.T) {
{"text('120')+text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document+document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array+array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(1ns)+duration(1ms)", document.NewDurationValue(time.Nanosecond), document.NewDurationValue(time.Millisecond), document.NewDurationValue(time.Nanosecond + time.Millisecond), false},
}
for _, test := range tests {
@@ -156,7 +153,6 @@ func TestValueSub(t *testing.T) {
{"text('120')-text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document-document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array-array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(1ns)-duration(1ms)", document.NewDurationValue(time.Nanosecond), document.NewDurationValue(time.Millisecond), document.NewDurationValue(time.Nanosecond - time.Millisecond), false},
}
for _, test := range tests {
@@ -191,7 +187,6 @@ func TestValueMult(t *testing.T) {
{"text('120')*text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document*document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array*array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(10ns)*duration(1ms)", document.NewDurationValue(10 * time.Nanosecond), document.NewDurationValue(time.Millisecond), document.NewDurationValue(10 * time.Nanosecond * time.Millisecond), false},
}
for _, test := range tests {
@@ -227,7 +222,6 @@ func TestValueDiv(t *testing.T) {
{"text('120')/text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document/document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array/array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(10ns)/duration(1ms)", document.NewDurationValue(10 * time.Nanosecond), document.NewDurationValue(time.Millisecond), document.NewDurationValue(10 * time.Nanosecond / time.Millisecond), false},
}
for _, test := range tests {
@@ -265,7 +259,6 @@ func TestValueMod(t *testing.T) {
{"text('120')%text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document%document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array%array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(10ns)%duration(1ms)", document.NewDurationValue(10 * time.Nanosecond), document.NewDurationValue(time.Millisecond), document.NewDurationValue(10 * time.Nanosecond % time.Millisecond), false},
}
for _, test := range tests {
@@ -300,7 +293,6 @@ func TestValueBitwiseAnd(t *testing.T) {
{"text('120')&text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document&document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array&array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(10ns)&duration(1ms)", document.NewDurationValue(10 * time.Nanosecond), document.NewDurationValue(time.Microsecond), document.NewIntegerValue(8), false},
}
for _, test := range tests {
@@ -334,7 +326,6 @@ func TestValueBitwiseOr(t *testing.T) {
{"text('120')|text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document|document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array|array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(10ns)|duration(1ms)", document.NewDurationValue(10 * time.Nanosecond), document.NewDurationValue(time.Microsecond), document.NewIntegerValue(1002), false},
}
for _, test := range tests {
@@ -367,7 +358,6 @@ func TestValueBitwiseXor(t *testing.T) {
{"text('120')^text('120')", document.NewTextValue("120"), document.NewTextValue("120"), document.NewNullValue(), false},
{"document^document", document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewDocumentValue(document.NewFieldBuffer().Add("a", document.NewIntegerValue(10))), document.NewNullValue(), false},
{"array^array", document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewArrayValue(document.NewValueBuffer(document.NewIntegerValue(10))), document.NewNullValue(), false},
{"duration(10ns)^duration(1ms)", document.NewDurationValue(10 * time.Nanosecond), document.NewDurationValue(time.Microsecond), document.NewIntegerValue(994), false},
}
for _, test := range tests {

View File

@@ -1,14 +1,8 @@
package document
import (
"time"
)
// NewValue creates a value from x. It only supports a few type and doesn't rely on reflection.
func NewValue(x interface{}) (Value, error) {
switch v := x.(type) {
case time.Duration:
return NewDurationValue(v), nil
case nil:
return NewNullValue(), nil
case Document:

View File

@@ -20,7 +20,6 @@ var valueTypes = []document.ValueType{
document.NullValue,
document.BoolValue,
document.DoubleValue,
document.DurationValue,
document.TextValue,
document.BlobValue,
document.ArrayValue,

View File

@@ -13,7 +13,6 @@ import (
"encoding/binary"
"errors"
"math"
"time"
"github.com/genjidb/genji/document"
)
@@ -196,8 +195,6 @@ func decodeValue(data []byte, delim, end byte) (document.Value, int, error) {
i++
case document.DoubleValue:
i += 16
case document.DurationValue:
i += 8
case document.BlobValue, document.TextValue:
for i < len(data) && data[i] != delim && data[i] != end {
i++
@@ -352,8 +349,6 @@ func AppendValue(buf []byte, v document.Value) ([]byte, error) {
return AppendBool(buf, v.V.(bool)), nil
case document.IntegerValue, document.DoubleValue:
return AppendNumber(buf, v)
case document.DurationValue:
return AppendInt64(buf, int64(v.V.(time.Duration))), nil
case document.NullValue:
return buf, nil
case document.ArrayValue:
@@ -398,12 +393,6 @@ func DecodeValue(data []byte) (document.Value, error) {
return document.Value{}, err
}
return document.NewDoubleValue(x), nil
case document.DurationValue:
x, err := DecodeInt64(data)
if err != nil {
return document.Value{}, err
}
return document.NewDurationValue(time.Duration(x)), nil
case document.NullValue:
return document.NewNullValue(), nil
case document.ArrayValue:
@@ -437,8 +426,6 @@ func Append(buf []byte, t document.ValueType, v interface{}) ([]byte, error) {
return AppendInt64(buf, v.(int64)), nil
case document.DoubleValue:
return AppendFloat64(buf, v.(float64)), nil
case document.DurationValue:
return AppendInt64(buf, int64(v.(time.Duration))), nil
case document.NullValue:
return buf, nil
case document.ArrayValue:
@@ -472,12 +459,6 @@ func Decode(t document.ValueType, data []byte) (document.Value, error) {
return document.Value{}, err
}
return document.NewDoubleValue(x), nil
case document.DurationValue:
x, err := DecodeInt64(data)
if err != nil {
return document.Value{}, err
}
return document.NewDurationValue(time.Duration(x)), nil
case document.NullValue:
return document.NewNullValue(), nil
case document.ArrayValue:

View File

@@ -5,7 +5,6 @@ import (
"math"
"sort"
"testing"
"time"
"github.com/genjidb/genji/document"
"github.com/stretchr/testify/require"
@@ -22,7 +21,6 @@ func TestAppendDecode(t *testing.T) {
{"double", document.NewDoubleValue(-3.14)},
{"text", document.NewTextValue("foo")},
{"blob", document.NewBlobValue([]byte("bar"))},
{"duration", document.NewDurationValue(10 * time.Second)},
{"array", document.NewArrayValue(document.NewValueBuffer(
document.NewBoolValue(true),
document.NewIntegerValue(55),
@@ -89,7 +87,6 @@ func TestAppendValueDecodeValue(t *testing.T) {
{"double", document.NewDoubleValue(-3.14)},
{"text", document.NewTextValue("foo")},
{"blob", document.NewBlobValue([]byte("bar"))},
{"duration", document.NewDurationValue(10 * time.Second)},
{"array", document.NewArrayValue(document.NewValueBuffer(
document.NewBoolValue(true),
document.NewIntegerValue(55),

View File

@@ -101,13 +101,12 @@ func TestParserCreateTable(t *testing.T) {
},
}, false},
{"With all supported variable size data types",
"CREATE TABLE test(i integer, du duration, b blob, byt bytes, t text, a array, d document)",
"CREATE TABLE test(i integer, b blob, byt bytes, t text, a array, d document)",
query.CreateTableStmt{
TableName: "test",
Info: database.TableInfo{
FieldConstraints: []database.FieldConstraint{
{Path: parsePath(t, "i"), Type: document.IntegerValue},
{Path: parsePath(t, "du"), Type: document.DurationValue},
{Path: parsePath(t, "b"), Type: document.BlobValue},
{Path: parsePath(t, "byt"), Type: document.BlobValue},
{Path: parsePath(t, "t"), Type: document.TextValue},

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"strconv"
"strings"
"time"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/sql/query/expr"
@@ -195,12 +194,6 @@ func (p *Parser) parseUnaryExpr() (expr.Expr, error) {
return expr.BoolValue(tok == scanner.TRUE), nil
case scanner.NULL:
return expr.NullValue(), nil
case scanner.DURATION:
d, err := time.ParseDuration(lit)
if err != nil {
return nil, &ParseError{Message: "unable to parse duration", Pos: pos}
}
return expr.DurationValue(d), nil
case scanner.LBRACKET:
p.Unscan()
e, err := p.parseDocument()
@@ -293,8 +286,6 @@ func (p *Parser) parseType() document.ValueType {
return document.BlobValue
case scanner.TYPEDOCUMENT:
return document.DocumentValue
case scanner.TYPEDURATION:
return document.DurationValue
case scanner.TYPEDOUBLE:
return document.DoubleValue
case scanner.TYPEINTEGER:

View File

@@ -3,7 +3,6 @@ package parser
import (
"strings"
"testing"
"time"
"github.com/genjidb/genji/document"
"github.com/genjidb/genji/sql/query/expr"
@@ -42,11 +41,6 @@ func TestParserExpr(t *testing.T) {
{"+float64", "10.0", expr.DoubleValue(10), false},
{"-float64", "-10.0", expr.DoubleValue(-10), false},
// durations
{"+duration", "150ms", expr.DurationValue(150 * time.Millisecond), false},
{"-duration", "-150ms", expr.DurationValue(-150 * time.Millisecond), false},
{"bad duration", "-150xs", expr.DurationValue(0), true},
// strings
{"double quoted string", `"10.0"`, expr.TextValue("10.0"), false},
{"single quoted string", "'-10.0'", expr.TextValue("-10.0"), false},

View File

@@ -85,8 +85,7 @@ func TestCreateTable(t *testing.T) {
t.Run("with variable size data types", func(t *testing.T) {
err = db.Exec(`
CREATE TABLE test1(
foo.bar[1].hello bytes PRIMARY KEY, foo.a[1][2] TEXT NOT NULL, bar[4][0].bat integer,
du duration, b blob, t text, a array, d document
foo.bar[1].hello bytes PRIMARY KEY, foo.a[1][2] TEXT NOT NULL, bar[4][0].bat integer, b blob, t text, a array, d document
)
`)
require.NoError(t, err)
@@ -105,7 +104,6 @@ func TestCreateTable(t *testing.T) {
{Path: parsePath(t, "foo.bar[1].hello"), Type: document.BlobValue, IsPrimaryKey: true},
{Path: parsePath(t, "foo.a[1][2]"), Type: document.TextValue, IsNotNull: true},
{Path: parsePath(t, "bar[4][0].bat"), Type: document.IntegerValue},
{Path: parsePath(t, "du"), Type: document.DurationValue},
{Path: parsePath(t, "b"), Type: document.BlobValue},
{Path: parsePath(t, "t"), Type: document.TextValue},
{Path: parsePath(t, "a"), Type: document.ArrayValue},

View File

@@ -3,7 +3,6 @@ package expr
import (
"fmt"
"strings"
"time"
"github.com/genjidb/genji/document"
)
@@ -52,11 +51,6 @@ func DoubleValue(v float64) LiteralValue {
return LiteralValue(document.NewDoubleValue(v))
}
// DurationValue creates a litteral value of type Duration.
func DurationValue(v time.Duration) LiteralValue {
return LiteralValue(document.NewDurationValue(v))
}
// NullValue creates a litteral value of type Null.
func NullValue() LiteralValue {
return LiteralValue(document.NewNullValue())

View File

@@ -141,7 +141,7 @@ func TestInsertStmt(t *testing.T) {
err = db.Exec(`CREATE TABLE test(
b bool, db double,
i integer, du duration, bb blob, byt bytes,
i integer, bb blob, byt bytes,
t text, a array, d document
)`)
require.NoError(t, err)
@@ -150,7 +150,7 @@ func TestInsertStmt(t *testing.T) {
INSERT INTO test
VALUES {
i: 10000000000, db: 21.21, b: true,
du: 127ns, bb: "YmxvYlZhbHVlCg==", byt: "Ynl0ZXNWYWx1ZQ==",
bb: "YmxvYlZhbHVlCg==", byt: "Ynl0ZXNWYWx1ZQ==",
t: "text", a: [1, "foo", true], d: {"foo": "bar"}
}`)
require.NoError(t, err)
@@ -166,7 +166,6 @@ func TestInsertStmt(t *testing.T) {
"i": 10000000000,
"db": 21.21,
"b": true,
"du": "127ns",
"bb": "YmxvYlZhbHVlCg==",
"byt": "Ynl0ZXNWYWx1ZQ==",
"t": "text",
@@ -200,10 +199,6 @@ func TestInsertStmt(t *testing.T) {
{"document / not null with type constraint", "DOCUMENT NOT NULL", `{}`},
{"document / not null with non-respected type constraint ", "DOCUMENT NOT NULL", `{a: false}`},
{"duration", "DURATION", `{a: "foo"}`},
{"duration / not null with type constraint", "DURATION NOT NULL", `{}`},
{"duration / not null with non-respected type constraint ", "DURATION NOT NULL", `{a: [1,2,3]}`},
{"double", "DOUBLE", `{a: "foo"}`},
{"double / not null with type constraint", "DOUBLE NOT NULL", `{}`},
{"double / not null with non-respected type constraint ", "DOUBLE NOT NULL", `{a: [1,2,3]}`},

View File

@@ -50,7 +50,7 @@ func (s *Scanner) unbuffer() string {
}
// Scan returns the next token and position from the underlying reader.
// Also returns the literal text read for strings, numbers, and duration tokens
// Also returns the literal text read for strings, and number tokens
// since these token types can have different literal representations.
func (s *Scanner) Scan() TokenInfo {
// Read next code point.
@@ -354,32 +354,7 @@ func (s *Scanner) scanNumber() TokenInfo {
s.unread()
}
// Read as a duration or integer if it doesn't have a fractional part.
if !isDecimal {
// If the next rune is a letter then this is a duration token.
if ch0, _ := s.read(); isLetter(ch0) || ch0 == 'µ' {
_, _ = buf.WriteRune(ch0)
for {
ch1, _ := s.read()
if !isLetter(ch1) && ch1 != 'µ' {
s.unread()
break
}
_, _ = buf.WriteRune(ch1)
}
// Continue reading digits and letters as part of this token.
for {
if ch0, _ := s.read(); isLetter(ch0) || ch0 == 'µ' || isDigit(ch0) {
_, _ = buf.WriteRune(ch0)
} else {
s.unread()
break
}
}
return TokenInfo{DURATION, pos, buf.String(), s.unbuffer()}
}
s.unread()
return TokenInfo{INTEGER, pos, buf.String(), s.unbuffer()}
}
return TokenInfo{NUMBER, pos, buf.String(), s.unbuffer()}

View File

@@ -115,17 +115,6 @@ func TestScanner_Scan(t *testing.T) {
{s: `10.3s`, tok: scanner.NUMBER, lit: `10.3`, raw: `10.3`},
{s: `-10.3`, tok: scanner.NUMBER, lit: `-10.3`, raw: `-10.3`},
// Durations
{s: `10u`, tok: scanner.DURATION, lit: `10u`, raw: `10u`},
{s: `10µ`, tok: scanner.DURATION, lit: `10µ`, raw: `10µ`},
{s: `10ms`, tok: scanner.DURATION, lit: `10ms`, raw: `10ms`},
{s: `1s`, tok: scanner.DURATION, lit: `1s`, raw: `1s`},
{s: `10m`, tok: scanner.DURATION, lit: `10m`, raw: `10m`},
{s: `10h`, tok: scanner.DURATION, lit: `10h`, raw: `10h`},
{s: `10d`, tok: scanner.DURATION, lit: `10d`, raw: `10d`},
{s: `10w`, tok: scanner.DURATION, lit: `10w`, raw: `10w`},
{s: `10x`, tok: scanner.DURATION, lit: `10x`, raw: `10x`}, // non-duration unit, but scanned as a duration value
// Keywords
{s: `ALTER`, tok: scanner.ALTER, raw: `ALTER`},
{s: `AS`, tok: scanner.AS, raw: `AS`},

View File

@@ -22,7 +22,6 @@ const (
POSITIONALPARAM // ?
NUMBER // 12345.67
INTEGER // 12345
DURATION // 13h
STRING // "abc"
BADSTRING // "abc
BADESCAPE // \q
@@ -122,7 +121,6 @@ const (
TYPEBYTES
TYPEDOCUMENT
TYPEDOUBLE
TYPEDURATION
TYPEINTEGER
TYPETEXT
@@ -137,7 +135,6 @@ var tokens = [...]string{
IDENT: "IDENT",
POSITIONALPARAM: "?",
NUMBER: "NUMBER",
DURATION: "DURATIONVAL",
STRING: "STRING",
BADSTRING: "BADSTRING",
BADESCAPE: "BADESCAPE",
@@ -230,7 +227,6 @@ var tokens = [...]string{
TYPEBYTES: "BYTES",
TYPEDOCUMENT: "DOCUMENT",
TYPEDOUBLE: "DOUBLE",
TYPEDURATION: "DURATION",
TYPEINTEGER: "INTEGER",
TYPETEXT: "TEXT",
}