mirror of
https://github.com/MontFerret/ferret.git
synced 2025-11-06 08:39:09 +02:00
New type system (#232)
* New type system * Fixed dot notation for HTML elements
This commit is contained in:
@@ -10,7 +10,7 @@ import (
|
||||
type (
|
||||
SortDirection int
|
||||
|
||||
Comparator func(ctx context.Context, first, second *core.Scope) (int, error)
|
||||
Comparator func(ctx context.Context, first, second *core.Scope) (int64, error)
|
||||
|
||||
Sorter struct {
|
||||
fn Comparator
|
||||
@@ -136,7 +136,7 @@ func (iterator *SortIterator) sort(ctx context.Context, scope *core.Scope) ([]*c
|
||||
break
|
||||
}
|
||||
|
||||
eq = eq * int(comp.direction)
|
||||
eq = eq * int64(comp.direction)
|
||||
|
||||
if eq == -1 {
|
||||
out = true
|
||||
|
||||
@@ -35,7 +35,7 @@ func TestSort(t *testing.T) {
|
||||
}
|
||||
|
||||
s, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
return first.MustGetVariable(collections.DefaultValueVar).Compare(second.MustGetVariable(collections.DefaultValueVar)), nil
|
||||
},
|
||||
collections.SortDirectionAsc,
|
||||
@@ -72,7 +72,7 @@ func TestSort(t *testing.T) {
|
||||
}
|
||||
|
||||
s, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
return first.MustGetVariable(collections.DefaultValueVar).Compare(second.MustGetVariable(collections.DefaultValueVar)), nil
|
||||
},
|
||||
collections.SortDirectionDesc,
|
||||
@@ -120,7 +120,7 @@ func TestSort(t *testing.T) {
|
||||
}
|
||||
|
||||
s1, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
|
||||
@@ -130,7 +130,7 @@ func TestSort(t *testing.T) {
|
||||
)
|
||||
|
||||
s2, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
|
||||
@@ -183,7 +183,7 @@ func TestSort(t *testing.T) {
|
||||
}
|
||||
|
||||
s1, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
|
||||
@@ -193,7 +193,7 @@ func TestSort(t *testing.T) {
|
||||
)
|
||||
|
||||
s2, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
|
||||
@@ -246,7 +246,7 @@ func TestSort(t *testing.T) {
|
||||
}
|
||||
|
||||
s1, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
|
||||
@@ -256,7 +256,7 @@ func TestSort(t *testing.T) {
|
||||
)
|
||||
|
||||
s2, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
|
||||
@@ -309,7 +309,7 @@ func TestSort(t *testing.T) {
|
||||
}
|
||||
|
||||
s1, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("one")
|
||||
|
||||
@@ -319,7 +319,7 @@ func TestSort(t *testing.T) {
|
||||
)
|
||||
|
||||
s2, _ := collections.NewSorter(
|
||||
func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
o1, _ := first.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
o2, _ := second.MustGetVariable(collections.DefaultValueVar).(*values.Object).Get("two")
|
||||
|
||||
|
||||
@@ -24,17 +24,14 @@ func TestSourceError(t *testing.T) {
|
||||
|
||||
func TestTypeError(t *testing.T) {
|
||||
Convey("Should match", t, func() {
|
||||
e := core.TypeError(core.BooleanType)
|
||||
e := core.TypeError(TypeA{})
|
||||
So(e, ShouldNotBeNil)
|
||||
|
||||
e = core.TypeError(core.BooleanType, core.BooleanType)
|
||||
e = core.TypeError(TypeA{}, TypeB{})
|
||||
So(e, ShouldNotBeNil)
|
||||
|
||||
e = core.TypeError(core.BooleanType, core.BooleanType, core.IntType, core.FloatType)
|
||||
So(e, ShouldNotBeNil)
|
||||
|
||||
cause := errors.New("invalid type: expected none or boolean or int or float, but got none")
|
||||
e = core.TypeError(core.NoneType, core.NoneType, core.BooleanType, core.IntType, core.FloatType)
|
||||
cause := errors.New("invalid type: expected type_b or type_c, but got type_a")
|
||||
e = core.TypeError(TypeA{}, TypeB{}, TypeC{})
|
||||
So(e.Error(), ShouldEqual, cause.Error())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -160,39 +160,55 @@ func BenchmarkScope(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
type TestCloser struct {
|
||||
closed bool
|
||||
type (
|
||||
TestCloserType struct{}
|
||||
|
||||
TestCloserValue struct {
|
||||
closed bool
|
||||
}
|
||||
)
|
||||
|
||||
func (tct TestCloserType) ID() int64 {
|
||||
return 99
|
||||
}
|
||||
|
||||
func (tc *TestCloser) MarshalJSON() ([]byte, error) {
|
||||
func (tct TestCloserType) String() string {
|
||||
return "TestCloser"
|
||||
}
|
||||
|
||||
func (tct TestCloserType) Equals(other core.Type) bool {
|
||||
return other.ID() == tct.ID()
|
||||
}
|
||||
|
||||
func (tc *TestCloserValue) MarshalJSON() ([]byte, error) {
|
||||
return nil, core.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (tc *TestCloser) Type() core.Type {
|
||||
return core.NoneType
|
||||
func (tc *TestCloserValue) Type() core.Type {
|
||||
return TestCloserType{}
|
||||
}
|
||||
|
||||
func (tc *TestCloser) String() string {
|
||||
func (tc *TestCloserValue) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (tc *TestCloser) Compare(other core.Value) int {
|
||||
func (tc *TestCloserValue) Compare(other core.Value) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (tc *TestCloser) Unwrap() interface{} {
|
||||
func (tc *TestCloserValue) Unwrap() interface{} {
|
||||
return tc
|
||||
}
|
||||
|
||||
func (tc *TestCloser) Hash() uint64 {
|
||||
func (tc *TestCloserValue) Hash() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (tc *TestCloser) Copy() core.Value {
|
||||
return &TestCloser{}
|
||||
func (tc *TestCloserValue) Copy() core.Value {
|
||||
return &TestCloserValue{}
|
||||
}
|
||||
|
||||
func (tc *TestCloser) Close() error {
|
||||
func (tc *TestCloserValue) Close() error {
|
||||
if tc.closed {
|
||||
return core.Error(core.ErrInvalidOperation, "already closed")
|
||||
}
|
||||
@@ -206,7 +222,7 @@ func TestCloseFunc(t *testing.T) {
|
||||
Convey("Should close root scope and close all io.Closer values", t, func() {
|
||||
rs, cf := core.NewRootScope()
|
||||
|
||||
tc := &TestCloser{}
|
||||
tc := &TestCloserValue{}
|
||||
|
||||
rs.SetVariable("disposable", tc)
|
||||
So(tc.closed, ShouldBeFalse)
|
||||
@@ -220,7 +236,7 @@ func TestCloseFunc(t *testing.T) {
|
||||
Convey("Should return error if it's already closed", t, func() {
|
||||
rs, cf := core.NewRootScope()
|
||||
|
||||
tc := &TestCloser{}
|
||||
tc := &TestCloserValue{}
|
||||
|
||||
rs.SetVariable("disposable", tc)
|
||||
So(tc.closed, ShouldBeFalse)
|
||||
|
||||
83
pkg/runtime/core/type.go
Normal file
83
pkg/runtime/core/type.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// Type represents runtime type with id for quick type check
|
||||
// and Name for error messages
|
||||
|
||||
//revive:disable-next-line:redefines-builtin-id
|
||||
type (
|
||||
Type interface {
|
||||
ID() int64
|
||||
String() string
|
||||
Equals(other Type) bool
|
||||
}
|
||||
|
||||
BaseType struct {
|
||||
id int64
|
||||
name string
|
||||
}
|
||||
)
|
||||
|
||||
func NewType(name string) Type {
|
||||
return BaseType{rand.Int63(), name}
|
||||
}
|
||||
|
||||
func (t BaseType) ID() int64 {
|
||||
return t.id
|
||||
}
|
||||
|
||||
func (t BaseType) String() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
func (t BaseType) Equals(other Type) bool {
|
||||
return t.id == other.ID()
|
||||
}
|
||||
|
||||
// IsTypeOf return true when value's type
|
||||
// is equal to check type.
|
||||
// Returns false, otherwise.
|
||||
func IsTypeOf(value Value, check Type) bool {
|
||||
return value.Type().ID() == check.ID()
|
||||
}
|
||||
|
||||
// ValidateType checks the match of
|
||||
// value's type and required types.
|
||||
func ValidateType(value Value, required ...Type) error {
|
||||
var valid bool
|
||||
tid := value.Type().ID()
|
||||
|
||||
for _, t := range required {
|
||||
if tid == t.ID() {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return TypeError(value.Type(), required...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateValueTypePairs validate pairs of
|
||||
// Values and Types.
|
||||
// Returns error when type didn't match
|
||||
func ValidateValueTypePairs(pairs ...PairValueType) error {
|
||||
var err error
|
||||
|
||||
for idx, pair := range pairs {
|
||||
err = ValidateType(pair.Value, pair.Types...)
|
||||
|
||||
if err != nil {
|
||||
return errors.Errorf("pair %d: %v", idx, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
109
pkg/runtime/core/type_test.go
Normal file
109
pkg/runtime/core/type_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package core_test
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type (
|
||||
Value struct {
|
||||
type_ core.Type
|
||||
}
|
||||
|
||||
TypeA struct{}
|
||||
|
||||
TypeB struct{}
|
||||
|
||||
TypeC struct{}
|
||||
)
|
||||
|
||||
func (t Value) MarshalJSON() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (t Value) Type() core.Type {
|
||||
return t.type_
|
||||
}
|
||||
|
||||
func (t Value) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t Value) Compare(other core.Value) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (t Value) Unwrap() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t Value) Hash() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (t Value) Copy() core.Value {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t TypeA) ID() int64 {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (t TypeA) String() string {
|
||||
return "type_a"
|
||||
}
|
||||
|
||||
func (t TypeA) Equals(other core.Type) bool {
|
||||
return t.ID() == other.ID()
|
||||
}
|
||||
|
||||
func (t TypeB) ID() int64 {
|
||||
return 2
|
||||
}
|
||||
|
||||
func (t TypeB) String() string {
|
||||
return "type_b"
|
||||
}
|
||||
|
||||
func (t TypeB) Equals(other core.Type) bool {
|
||||
return t.ID() == other.ID()
|
||||
}
|
||||
|
||||
func (t TypeC) ID() int64 {
|
||||
return 3
|
||||
}
|
||||
|
||||
func (t TypeC) String() string {
|
||||
return "type_c"
|
||||
}
|
||||
|
||||
func (t TypeC) Equals(other core.Type) bool {
|
||||
return t.ID() == other.ID()
|
||||
}
|
||||
|
||||
func TestType(t *testing.T) {
|
||||
typeA := TypeA{}
|
||||
typeB := TypeB{}
|
||||
|
||||
Convey("IsTypeOf", t, func() {
|
||||
Convey("Should return 'false' when types are different", func() {
|
||||
vA := Value{typeA}
|
||||
|
||||
So(core.IsTypeOf(vA, typeB), ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidateType(t *testing.T) {
|
||||
typeA := TypeA{}
|
||||
typeB := TypeB{}
|
||||
|
||||
Convey("Should validate types", t, func() {
|
||||
vA := Value{typeA}
|
||||
vB := Value{typeB}
|
||||
|
||||
So(core.ValidateType(vA, typeA), ShouldBeNil)
|
||||
So(core.ValidateType(vB, typeA), ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
@@ -1,120 +1,41 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//revive:disable-next-line:redefines-builtin-id
|
||||
type Type int64
|
||||
type (
|
||||
// Value represents an interface of
|
||||
// any type that needs to be used during runtime
|
||||
Value interface {
|
||||
json.Marshaler
|
||||
Type() Type
|
||||
String() string
|
||||
Compare(other Value) int64
|
||||
Unwrap() interface{}
|
||||
Hash() uint64
|
||||
Copy() Value
|
||||
}
|
||||
|
||||
const (
|
||||
NoneType Type = 0
|
||||
BooleanType Type = 1
|
||||
IntType Type = 2
|
||||
FloatType Type = 3
|
||||
StringType Type = 4
|
||||
DateTimeType Type = 5
|
||||
ArrayType Type = 6
|
||||
ObjectType Type = 7
|
||||
HTMLElementType Type = 8
|
||||
HTMLDocumentType Type = 9
|
||||
BinaryType Type = 10
|
||||
CustomType Type = 99
|
||||
// Getter represents an interface of
|
||||
// complex types that needs to be used to read values by path.
|
||||
// The interface is created to let user-defined types be used in dot notation data access.
|
||||
Getter interface {
|
||||
GetIn(ctx context.Context, path []Value) (Value, error)
|
||||
}
|
||||
|
||||
// Setter represents an interface of
|
||||
// complex types that needs to be used to write values by path.
|
||||
// The interface is created to let user-defined types be used in dot notation assignment.
|
||||
Setter interface {
|
||||
SetIn(ctx context.Context, path []Value, value Value) error
|
||||
}
|
||||
|
||||
// PairValueType is a supporting
|
||||
// structure that used in validateValueTypePairs.
|
||||
PairValueType struct {
|
||||
Value Value
|
||||
Types []Type
|
||||
}
|
||||
)
|
||||
|
||||
var typestr = map[Type]string{
|
||||
NoneType: "none",
|
||||
BooleanType: "boolean",
|
||||
IntType: "int",
|
||||
FloatType: "float",
|
||||
StringType: "string",
|
||||
DateTimeType: "datetime",
|
||||
ArrayType: "array",
|
||||
ObjectType: "object",
|
||||
HTMLElementType: "HTMLElement",
|
||||
HTMLDocumentType: "HTMLDocument",
|
||||
BinaryType: "BinaryType",
|
||||
CustomType: "CustomType",
|
||||
}
|
||||
|
||||
func (t Type) String() string {
|
||||
return typestr[t]
|
||||
}
|
||||
|
||||
// Value represents an interface of
|
||||
// any type that needs to be used during runtime
|
||||
type Value interface {
|
||||
json.Marshaler
|
||||
Type() Type
|
||||
String() string
|
||||
Compare(other Value) int
|
||||
Unwrap() interface{}
|
||||
Hash() uint64
|
||||
Copy() Value
|
||||
}
|
||||
|
||||
// Getter represents an interface of
|
||||
// complex types that needs to be used to read values by path.
|
||||
// The interface is created to let user-defined types be used in dot notation data access.
|
||||
type Getter interface {
|
||||
GetIn(path []Value) (Value, error)
|
||||
}
|
||||
|
||||
// Setter represents an interface of
|
||||
// complex types that needs to be used to write values by path.
|
||||
// The interface is created to let user-defined types be used in dot notation assignment.
|
||||
type Setter interface {
|
||||
SetIn(path []Value, value Value) error
|
||||
}
|
||||
|
||||
// IsTypeOf return true when value's type
|
||||
// is equal to check type.
|
||||
// Returns false, otherwise.
|
||||
func IsTypeOf(value Value, check Type) bool {
|
||||
return value.Type() == check
|
||||
}
|
||||
|
||||
// ValidateType checks the match of
|
||||
// value's type and required types.
|
||||
func ValidateType(value Value, required ...Type) error {
|
||||
var valid bool
|
||||
ct := value.Type()
|
||||
|
||||
for _, t := range required {
|
||||
if ct == t {
|
||||
valid = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return TypeError(value.Type(), required...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PairValueType is a supporting
|
||||
// structure that used in validateValueTypePairs.
|
||||
type PairValueType struct {
|
||||
Value Value
|
||||
Types []Type
|
||||
}
|
||||
|
||||
// ValidateValueTypePairs validate pairs of
|
||||
// Values and Types.
|
||||
// Returns error when type didn't match
|
||||
func ValidateValueTypePairs(pairs ...PairValueType) error {
|
||||
var err error
|
||||
|
||||
for idx, pair := range pairs {
|
||||
err = ValidateType(pair.Value, pair.Types...)
|
||||
if err != nil {
|
||||
return errors.Errorf("pair %d: %v", idx, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package core_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/drivers/http"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestTypeString(t *testing.T) {
|
||||
Convey("The string representation of the type should match this type", t, func() {
|
||||
So(core.Type(0).String(), ShouldEqual, "none")
|
||||
So(core.Type(1).String(), ShouldEqual, "boolean")
|
||||
So(core.Type(2).String(), ShouldEqual, "int")
|
||||
So(core.Type(3).String(), ShouldEqual, "float")
|
||||
So(core.Type(4).String(), ShouldEqual, "string")
|
||||
So(core.Type(5).String(), ShouldEqual, "datetime")
|
||||
So(core.Type(6).String(), ShouldEqual, "array")
|
||||
So(core.Type(7).String(), ShouldEqual, "object")
|
||||
So(core.Type(8).String(), ShouldEqual, "HTMLElement")
|
||||
So(core.Type(9).String(), ShouldEqual, "HTMLDocument")
|
||||
So(core.Type(10).String(), ShouldEqual, "BinaryType")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsTypeOf(t *testing.T) {
|
||||
Convey("Check type by value", t, func() {
|
||||
|
||||
So(core.IsTypeOf(values.None, core.NoneType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewBoolean(true), core.BooleanType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewInt(1), core.IntType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewFloat(1.1), core.FloatType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewString("test"), core.StringType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewDateTime(time.Now()), core.DateTimeType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewArray(1), core.ArrayType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewObject(), core.ObjectType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(&http.HTMLElement{}, core.HTMLElementType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(&http.HTMLDocument{}, core.HTMLDocumentType), ShouldBeTrue)
|
||||
So(core.IsTypeOf(values.NewBinary([]byte{}), core.BinaryType), ShouldBeTrue)
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidateType(t *testing.T) {
|
||||
Convey("Value should match type", t, func() {
|
||||
|
||||
So(core.ValidateType(values.None, core.NoneType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewBoolean(true), core.BooleanType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewInt(1), core.IntType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewFloat(1.1), core.FloatType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewString("test"), core.StringType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewDateTime(time.Now()), core.DateTimeType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewArray(1), core.ArrayType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewObject(), core.ObjectType), ShouldBeNil)
|
||||
So(core.ValidateType(&http.HTMLElement{}, core.HTMLElementType), ShouldBeNil)
|
||||
So(core.ValidateType(&http.HTMLDocument{}, core.HTMLDocumentType), ShouldBeNil)
|
||||
So(core.ValidateType(values.NewBinary([]byte{}), core.BinaryType), ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Value should not match type", t, func() {
|
||||
|
||||
So(core.ValidateType(values.None, core.BooleanType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewBoolean(true), core.IntType, core.NoneType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewInt(1), core.NoneType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewFloat(1.1), core.StringType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewString("test"), core.IntType, core.FloatType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewDateTime(time.Now()), core.BooleanType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewArray(1), core.StringType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewObject(), core.BooleanType), ShouldBeError)
|
||||
So(core.ValidateType(&http.HTMLElement{}, core.ArrayType), ShouldBeError)
|
||||
So(core.ValidateType(&http.HTMLDocument{}, core.HTMLElementType), ShouldBeError)
|
||||
So(core.ValidateType(values.NewBinary([]byte{}), core.NoneType), ShouldBeError)
|
||||
})
|
||||
}
|
||||
@@ -2,9 +2,11 @@ package clauses
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type CollectIterator struct {
|
||||
@@ -59,7 +61,7 @@ func NewCollectIterator(
|
||||
}
|
||||
|
||||
func newGroupSorter(selector *CollectSelector) (*collections.Sorter, error) {
|
||||
return collections.NewSorter(func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
return collections.NewSorter(func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
f, err := selector.expression.Exec(ctx, first)
|
||||
|
||||
if err != nil {
|
||||
@@ -213,7 +215,7 @@ func (iterator *CollectIterator) group(ctx context.Context, scope *core.Scope) (
|
||||
arr, ok := groupValue.(*values.Array)
|
||||
|
||||
if !ok {
|
||||
return nil, core.TypeError(groupValue.Type(), core.IntType)
|
||||
return nil, core.TypeError(groupValue.Type(), types.Int)
|
||||
}
|
||||
|
||||
value, err := proj.selector.expression.Exec(ctx, dataSourceScope)
|
||||
@@ -235,7 +237,7 @@ func (iterator *CollectIterator) group(ctx context.Context, scope *core.Scope) (
|
||||
counter, ok := groupValue.(values.Int)
|
||||
|
||||
if !ok {
|
||||
return nil, core.TypeError(groupValue.Type(), core.IntType)
|
||||
return nil, core.TypeError(groupValue.Type(), types.Int)
|
||||
}
|
||||
|
||||
groupValue = counter + 1
|
||||
|
||||
@@ -2,8 +2,10 @@ package clauses
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type LimitClause struct {
|
||||
@@ -71,13 +73,13 @@ func (clause *LimitClause) Iterate(ctx context.Context, scope *core.Scope) (coll
|
||||
}
|
||||
|
||||
func (clause *LimitClause) parseValue(val core.Value) (int, error) {
|
||||
if val.Type() == core.IntType {
|
||||
if val.Type() == types.Int {
|
||||
return val.Unwrap().(int), nil
|
||||
}
|
||||
|
||||
if val.Type() == core.FloatType {
|
||||
if val.Type() == types.Float {
|
||||
return int(val.Unwrap().(float64)), nil
|
||||
}
|
||||
|
||||
return -1, core.TypeError(val.Type(), core.IntType, core.FloatType)
|
||||
return -1, core.TypeError(val.Type(), types.Int, types.Float)
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ func (clause *SortClause) Iterate(ctx context.Context, scope *core.Scope) (colle
|
||||
}
|
||||
|
||||
func newSorter(srt *SorterExpression) (*collections.Sorter, error) {
|
||||
return collections.NewSorter(func(ctx context.Context, first, second *core.Scope) (int, error) {
|
||||
return collections.NewSorter(func(ctx context.Context, first, second *core.Scope) (int64, error) {
|
||||
f, err := srt.expression.Exec(ctx, first)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -2,9 +2,11 @@ package expressions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/collections"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type DataSource struct {
|
||||
@@ -44,11 +46,11 @@ func (ds *DataSource) Iterate(ctx context.Context, scope *core.Scope) (collectio
|
||||
}
|
||||
|
||||
switch data.Type() {
|
||||
case core.ArrayType:
|
||||
case types.Array:
|
||||
return collections.NewIndexedIterator(ds.valVariable, ds.keyVariable, data.(collections.IndexedCollection))
|
||||
case core.ObjectType:
|
||||
case types.Object:
|
||||
return collections.NewKeyedIterator(ds.valVariable, ds.keyVariable, data.(collections.KeyedCollection))
|
||||
case core.HTMLElementType, core.HTMLDocumentType:
|
||||
case types.HTMLElement, types.HTMLDocument:
|
||||
return collections.NewHTMLNodeIterator(ds.valVariable, ds.keyVariable, data.(values.HTMLNode))
|
||||
default:
|
||||
// fallback to user defined types
|
||||
@@ -69,10 +71,10 @@ func (ds *DataSource) Iterate(ctx context.Context, scope *core.Scope) (collectio
|
||||
default:
|
||||
return nil, core.TypeError(
|
||||
data.Type(),
|
||||
core.ArrayType,
|
||||
core.ObjectType,
|
||||
core.HTMLDocumentType,
|
||||
core.HTMLElementType,
|
||||
types.Array,
|
||||
types.Object,
|
||||
types.HTMLDocument,
|
||||
types.HTMLElement,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
var testIterableCollectionType = core.NewType("TestIterableCollection")
|
||||
|
||||
type (
|
||||
testIterableCollection struct {
|
||||
values collections.IndexedCollection
|
||||
@@ -32,12 +34,12 @@ func (c *testIterableCollection) MarshalJSON() ([]byte, error) {
|
||||
return nil, core.ErrInvalidOperation
|
||||
}
|
||||
func (c *testIterableCollection) Type() core.Type {
|
||||
return core.Type(11)
|
||||
return testIterableCollectionType
|
||||
}
|
||||
func (c *testIterableCollection) String() string {
|
||||
return ""
|
||||
}
|
||||
func (c *testIterableCollection) Compare(other core.Value) int {
|
||||
func (c *testIterableCollection) Compare(other core.Value) int64 {
|
||||
return 1
|
||||
}
|
||||
func (c *testIterableCollection) Unwrap() interface{} {
|
||||
|
||||
@@ -2,8 +2,10 @@ package literals
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -49,8 +51,8 @@ func (l *ObjectLiteral) Exec(ctx context.Context, scope *core.Scope) (core.Value
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
if name.Type() != core.StringType {
|
||||
return values.None, core.TypeError(name.Type(), core.StringType)
|
||||
if name.Type() != types.String {
|
||||
return values.None, core.TypeError(name.Type(), types.String)
|
||||
}
|
||||
|
||||
obj.Set(name.(values.String), val)
|
||||
|
||||
@@ -2,6 +2,7 @@ package expressions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
)
|
||||
@@ -46,7 +47,7 @@ func (e *MemberExpression) Exec(ctx context.Context, scope *core.Scope) (core.Va
|
||||
strPath[idx] = segment
|
||||
}
|
||||
|
||||
out, err := values.GetIn(val, strPath)
|
||||
out, err := values.GetIn(ctx, val, strPath)
|
||||
|
||||
if err != nil {
|
||||
return values.None, core.SourceError(e.src, err)
|
||||
|
||||
@@ -2,8 +2,10 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -88,7 +90,7 @@ func (operator *ArrayOperator) Exec(ctx context.Context, scope *core.Scope) (cor
|
||||
}
|
||||
|
||||
func (operator *ArrayOperator) Eval(ctx context.Context, left, right core.Value) (core.Value, error) {
|
||||
err := core.ValidateType(left, core.ArrayType)
|
||||
err := core.ValidateType(left, types.Array)
|
||||
|
||||
if err != nil {
|
||||
// TODO: Return the error? AQL just returns false
|
||||
|
||||
@@ -2,6 +2,7 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type InOperator struct {
|
||||
@@ -45,7 +47,7 @@ func (operator *InOperator) Exec(ctx context.Context, scope *core.Scope) (core.V
|
||||
}
|
||||
|
||||
func (operator *InOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) {
|
||||
err := core.ValidateType(right, core.ArrayType)
|
||||
err := core.ValidateType(right, types.Array)
|
||||
|
||||
if err != nil {
|
||||
// TODO: Return the error? AQL just returns false
|
||||
|
||||
@@ -2,8 +2,10 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -70,7 +72,7 @@ func (operator *LogicalOperator) Exec(ctx context.Context, scope *core.Scope) (c
|
||||
leftBool := values.ToBoolean(left)
|
||||
|
||||
if operator.value == LogicalOperatorTypeAnd && leftBool == values.False {
|
||||
if left.Type() == core.BooleanType {
|
||||
if left.Type() == types.Boolean {
|
||||
return values.False, nil
|
||||
}
|
||||
|
||||
@@ -98,7 +100,7 @@ func (operator *LogicalOperator) Eval(_ context.Context, left, right core.Value)
|
||||
leftBool := values.ToBoolean(left)
|
||||
|
||||
if operator.value == LogicalOperatorTypeAnd && leftBool == values.False {
|
||||
if left.Type() == core.BooleanType {
|
||||
if left.Type() == types.Boolean {
|
||||
return values.False, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -89,15 +91,15 @@ func Not(left, _ core.Value) core.Value {
|
||||
// Adds numbers
|
||||
// Concats strings
|
||||
func Add(left, right core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if right.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Int)
|
||||
|
||||
return l + r
|
||||
}
|
||||
|
||||
if right.Type() == core.FloatType {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Float)
|
||||
|
||||
@@ -105,15 +107,15 @@ func Add(left, right core.Value) core.Value {
|
||||
}
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if right.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Float)
|
||||
|
||||
return l + r
|
||||
}
|
||||
|
||||
if right.Type() == core.IntType {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Int)
|
||||
|
||||
@@ -125,15 +127,15 @@ func Add(left, right core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Subtract(left, right core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if right.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Int)
|
||||
|
||||
return l - r
|
||||
}
|
||||
|
||||
if right.Type() == core.FloatType {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Float)
|
||||
|
||||
@@ -141,15 +143,15 @@ func Subtract(left, right core.Value) core.Value {
|
||||
}
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if right.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Float)
|
||||
|
||||
return l - r
|
||||
}
|
||||
|
||||
if right.Type() == core.IntType {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Int)
|
||||
|
||||
@@ -161,15 +163,15 @@ func Subtract(left, right core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Multiply(left, right core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if right.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Int)
|
||||
|
||||
return l * r
|
||||
}
|
||||
|
||||
if right.Type() == core.FloatType {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Float)
|
||||
|
||||
@@ -177,15 +179,15 @@ func Multiply(left, right core.Value) core.Value {
|
||||
}
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if right.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Float)
|
||||
|
||||
return l * r
|
||||
}
|
||||
|
||||
if right.Type() == core.IntType {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Int)
|
||||
|
||||
@@ -197,15 +199,15 @@ func Multiply(left, right core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Divide(left, right core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if right.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Int)
|
||||
|
||||
return l / r
|
||||
}
|
||||
|
||||
if right.Type() == core.FloatType {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Float)
|
||||
|
||||
@@ -213,15 +215,15 @@ func Divide(left, right core.Value) core.Value {
|
||||
}
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if right.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Float)
|
||||
|
||||
return l / r
|
||||
}
|
||||
|
||||
if right.Type() == core.IntType {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Int)
|
||||
|
||||
@@ -233,15 +235,15 @@ func Divide(left, right core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Modulus(left, right core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if right.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Int)
|
||||
|
||||
return l % r
|
||||
}
|
||||
|
||||
if right.Type() == core.FloatType {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Int)
|
||||
r := right.(values.Float)
|
||||
|
||||
@@ -249,15 +251,15 @@ func Modulus(left, right core.Value) core.Value {
|
||||
}
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if right.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
if right.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Float)
|
||||
|
||||
return values.Int(l) % values.Int(r)
|
||||
}
|
||||
|
||||
if right.Type() == core.IntType {
|
||||
if right.Type() == types.Int {
|
||||
l := left.(values.Float)
|
||||
r := right.(values.Int)
|
||||
|
||||
@@ -269,13 +271,13 @@ func Modulus(left, right core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Increment(left, _ core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
|
||||
return l + 1
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
|
||||
return l + 1
|
||||
@@ -285,13 +287,13 @@ func Increment(left, _ core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Decrement(left, _ core.Value) core.Value {
|
||||
if left.Type() == core.IntType {
|
||||
if left.Type() == types.Int {
|
||||
l := left.(values.Int)
|
||||
|
||||
return l - 1
|
||||
}
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
l := left.(values.Float)
|
||||
|
||||
return l - 1
|
||||
@@ -301,13 +303,13 @@ func Decrement(left, _ core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Negative(value, _ core.Value) core.Value {
|
||||
err := core.ValidateType(value, core.IntType, core.FloatType)
|
||||
err := core.ValidateType(value, types.Int, types.Float)
|
||||
|
||||
if err != nil {
|
||||
return values.ZeroInt
|
||||
}
|
||||
|
||||
if value.Type() == core.IntType {
|
||||
if value.Type() == types.Int {
|
||||
return -value.(values.Int)
|
||||
}
|
||||
|
||||
@@ -315,13 +317,13 @@ func Negative(value, _ core.Value) core.Value {
|
||||
}
|
||||
|
||||
func Positive(value, _ core.Value) core.Value {
|
||||
err := core.ValidateType(value, core.IntType, core.FloatType)
|
||||
err := core.ValidateType(value, types.Int, types.Float)
|
||||
|
||||
if err != nil {
|
||||
return values.ZeroInt
|
||||
}
|
||||
|
||||
if value.Type() == core.IntType {
|
||||
if value.Type() == types.Int {
|
||||
return +value.(values.Int)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type RangeOperator struct {
|
||||
@@ -43,13 +45,13 @@ func (operator *RangeOperator) Exec(ctx context.Context, scope *core.Scope) (cor
|
||||
}
|
||||
|
||||
func (operator *RangeOperator) Eval(_ context.Context, left, right core.Value) (core.Value, error) {
|
||||
err := core.ValidateType(left, core.IntType, core.FloatType)
|
||||
err := core.ValidateType(left, types.Int, types.Float)
|
||||
|
||||
if err != nil {
|
||||
return values.None, core.SourceError(operator.src, err)
|
||||
}
|
||||
|
||||
err = core.ValidateType(right, core.IntType, core.FloatType)
|
||||
err = core.ValidateType(right, types.Int, types.Float)
|
||||
|
||||
if err != nil {
|
||||
return values.None, core.SourceError(operator.src, err)
|
||||
@@ -58,13 +60,13 @@ func (operator *RangeOperator) Eval(_ context.Context, left, right core.Value) (
|
||||
var start int
|
||||
var end int
|
||||
|
||||
if left.Type() == core.FloatType {
|
||||
if left.Type() == types.Float {
|
||||
start = int(left.(values.Float))
|
||||
} else {
|
||||
start = int(left.(values.Int))
|
||||
}
|
||||
|
||||
if right.Type() == core.FloatType {
|
||||
if right.Type() == types.Float {
|
||||
end = int(right.(values.Float))
|
||||
} else {
|
||||
end = int(right.(values.Int))
|
||||
|
||||
@@ -2,6 +2,7 @@ package operators
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package expressions_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
"testing"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
@@ -41,7 +42,7 @@ func TestParameterExpressionExec(t *testing.T) {
|
||||
value, err := existExp.Exec(ctx, &core.Scope{})
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(value.Type(), ShouldEqual, core.IntType)
|
||||
So(value.Type().Equals(types.Int), ShouldBeTrue)
|
||||
So(value.String(), ShouldEqual, "1")
|
||||
})
|
||||
|
||||
@@ -57,6 +58,6 @@ func TestParameterExpressionExec(t *testing.T) {
|
||||
|
||||
So(err, ShouldNotBeNil)
|
||||
So(err, ShouldHaveSameTypeAs, core.ErrNotFound)
|
||||
So(value.Type(), ShouldEqual, core.NoneType)
|
||||
So(value.Type().Equals(types.None), ShouldBeTrue)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -32,7 +33,7 @@ func (t *Array) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t *Array) Type() core.Type {
|
||||
return core.ArrayType
|
||||
return types.Array
|
||||
}
|
||||
|
||||
func (t *Array) String() string {
|
||||
@@ -45,22 +46,23 @@ func (t *Array) String() string {
|
||||
return string(marshaled)
|
||||
}
|
||||
|
||||
func (t *Array) Compare(other core.Value) int {
|
||||
switch other.Type() {
|
||||
case core.ArrayType:
|
||||
func (t *Array) Compare(other core.Value) int64 {
|
||||
if other.Type() == types.Array {
|
||||
other := other.(*Array)
|
||||
|
||||
if t.Length() == 0 && other.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if t.Length() < other.Length() {
|
||||
return -1
|
||||
}
|
||||
|
||||
if t.Length() > other.Length() {
|
||||
return 1
|
||||
}
|
||||
|
||||
var res = 0
|
||||
var res int64
|
||||
var val core.Value
|
||||
|
||||
other.ForEach(func(otherVal core.Value, idx int) bool {
|
||||
@@ -71,11 +73,9 @@ func (t *Array) Compare(other core.Value) int {
|
||||
})
|
||||
|
||||
return res
|
||||
case core.ObjectType:
|
||||
return -1
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
|
||||
return types.Compare(types.Array, other.Type())
|
||||
}
|
||||
|
||||
func (t *Array) Unwrap() interface{} {
|
||||
@@ -216,9 +216,13 @@ func (t *Array) Clone() core.Cloneable {
|
||||
var value core.Value
|
||||
for idx := NewInt(0); idx < t.Length(); idx++ {
|
||||
value = t.Get(idx)
|
||||
if IsCloneable(value) {
|
||||
value = value.(core.Cloneable).Clone()
|
||||
|
||||
cloneable, ok := value.(core.Cloneable)
|
||||
|
||||
if ok {
|
||||
value = cloneable.Clone()
|
||||
}
|
||||
|
||||
cloned.Push(value)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package values_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
"testing"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
@@ -56,7 +57,7 @@ func TestArray(t *testing.T) {
|
||||
Convey("Should return type", func() {
|
||||
arr := values.NewArray(1)
|
||||
|
||||
So(arr.Type(), ShouldEqual, core.ArrayType)
|
||||
So(arr.Type().Equals(types.Array), ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type Binary []byte
|
||||
@@ -30,17 +31,16 @@ func (b Binary) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (b Binary) Type() core.Type {
|
||||
return core.BinaryType
|
||||
return types.Binary
|
||||
}
|
||||
|
||||
func (b Binary) String() string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (b Binary) Compare(other core.Value) int {
|
||||
// TODO: Lame comparison, need to think more about it
|
||||
switch other.Type() {
|
||||
case core.BooleanType:
|
||||
func (b Binary) Compare(other core.Value) int64 {
|
||||
if other.Type() == types.Binary {
|
||||
// TODO: Lame comparison, need to think more about it
|
||||
b2 := other.(*Binary)
|
||||
|
||||
if b2.Length() == b.Length() {
|
||||
@@ -52,9 +52,9 @@ func (b Binary) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return -1
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
|
||||
return types.Compare(types.Binary, other.Type())
|
||||
}
|
||||
|
||||
func (b Binary) Unwrap() interface{} {
|
||||
|
||||
@@ -6,12 +6,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type Boolean bool
|
||||
|
||||
var False = Boolean(false)
|
||||
var True = Boolean(true)
|
||||
const (
|
||||
False = Boolean(false)
|
||||
True = Boolean(true)
|
||||
)
|
||||
|
||||
func NewBoolean(input bool) Boolean {
|
||||
return Boolean(input)
|
||||
@@ -60,7 +63,7 @@ func (t Boolean) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t Boolean) Type() core.Type {
|
||||
return core.BooleanType
|
||||
return types.Boolean
|
||||
}
|
||||
|
||||
func (t Boolean) String() string {
|
||||
@@ -71,11 +74,10 @@ func (t Boolean) String() string {
|
||||
return "false"
|
||||
}
|
||||
|
||||
func (t Boolean) Compare(other core.Value) int {
|
||||
func (t Boolean) Compare(other core.Value) int64 {
|
||||
raw := bool(t)
|
||||
|
||||
switch other.Type() {
|
||||
case core.BooleanType:
|
||||
if types.Boolean.Equals(other.Type()) {
|
||||
i := other.Unwrap().(bool)
|
||||
|
||||
if raw == i {
|
||||
@@ -87,11 +89,9 @@ func (t Boolean) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return +1
|
||||
case core.NoneType:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
|
||||
return types.Compare(types.Boolean, other.Type())
|
||||
}
|
||||
|
||||
func (t Boolean) Unwrap() interface{} {
|
||||
|
||||
@@ -3,6 +3,7 @@ package values_test
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
@@ -21,7 +22,7 @@ func TestBoolean(t *testing.T) {
|
||||
|
||||
Convey(".Type", t, func() {
|
||||
Convey("Should return a type", func() {
|
||||
So(values.True.Type(), ShouldEqual, core.BooleanType)
|
||||
So(values.True.Type().Equals(types.Boolean), ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
const DefaultTimeLayout = time.RFC3339
|
||||
@@ -59,16 +60,15 @@ func (t DateTime) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t DateTime) Type() core.Type {
|
||||
return core.DateTimeType
|
||||
return types.DateTime
|
||||
}
|
||||
|
||||
func (t DateTime) String() string {
|
||||
return t.Time.String()
|
||||
}
|
||||
|
||||
func (t DateTime) Compare(other core.Value) int {
|
||||
switch other.Type() {
|
||||
case core.DateTimeType:
|
||||
func (t DateTime) Compare(other core.Value) int64 {
|
||||
if other.Type() == types.DateTime {
|
||||
other := other.(DateTime)
|
||||
|
||||
if t.After(other.Time) {
|
||||
@@ -80,13 +80,9 @@ func (t DateTime) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return 0
|
||||
default:
|
||||
if other.Type() > core.DateTimeType {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
return types.Compare(types.DateTime, other.Type())
|
||||
}
|
||||
|
||||
func (t DateTime) Unwrap() interface{} {
|
||||
|
||||
@@ -9,11 +9,12 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type Float float64
|
||||
|
||||
var ZeroFloat = Float(0.0)
|
||||
const ZeroFloat = Float(0.0)
|
||||
|
||||
func NewFloat(input float64) Float {
|
||||
return Float(input)
|
||||
@@ -75,18 +76,18 @@ func (t Float) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t Float) Type() core.Type {
|
||||
return core.FloatType
|
||||
return types.Float
|
||||
}
|
||||
|
||||
func (t Float) String() string {
|
||||
return fmt.Sprintf("%f", t)
|
||||
}
|
||||
|
||||
func (t Float) Compare(other core.Value) int {
|
||||
func (t Float) Compare(other core.Value) int64 {
|
||||
otherType := other.Type()
|
||||
raw := float64(t)
|
||||
|
||||
switch other.Type() {
|
||||
case core.FloatType:
|
||||
if otherType == types.Float {
|
||||
f := other.Unwrap().(float64)
|
||||
|
||||
if raw == f {
|
||||
@@ -98,7 +99,9 @@ func (t Float) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return +1
|
||||
case core.IntType:
|
||||
}
|
||||
|
||||
if otherType == types.Int {
|
||||
i := other.Unwrap().(int)
|
||||
f := float64(i)
|
||||
|
||||
@@ -111,11 +114,9 @@ func (t Float) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return +1
|
||||
case core.BooleanType, core.NoneType:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
|
||||
return types.Compare(types.Float, otherType)
|
||||
}
|
||||
|
||||
func (t Float) Unwrap() interface{} {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package values
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"hash/fnv"
|
||||
@@ -9,9 +10,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
func GetIn(from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
func GetIn(ctx context.Context, from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
if byPath == nil || len(byPath) == 0 {
|
||||
return None, nil
|
||||
}
|
||||
@@ -27,32 +29,32 @@ func GetIn(from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
segmentType := segment.Type()
|
||||
|
||||
switch result.Type() {
|
||||
case core.ObjectType:
|
||||
case types.Object:
|
||||
obj := result.(*Object)
|
||||
|
||||
if segmentType != core.StringType {
|
||||
return nil, core.TypeError(segmentType, core.StringType)
|
||||
if segmentType != types.String {
|
||||
return nil, core.TypeError(segmentType, types.String)
|
||||
}
|
||||
|
||||
result, _ = obj.Get(segment.(String))
|
||||
|
||||
break
|
||||
case core.ArrayType:
|
||||
case types.Array:
|
||||
arr := result.(*Array)
|
||||
|
||||
if segmentType != core.IntType {
|
||||
return nil, core.TypeError(segmentType, core.IntType)
|
||||
if segmentType != types.Int {
|
||||
return nil, core.TypeError(segmentType, types.Int)
|
||||
}
|
||||
|
||||
result = arr.Get(segment.(Int))
|
||||
|
||||
break
|
||||
case core.HTMLElementType, core.HTMLDocumentType:
|
||||
case types.HTMLElement, types.HTMLDocument:
|
||||
el := result.(HTMLNode)
|
||||
|
||||
if segmentType == core.IntType {
|
||||
if segmentType == types.Int {
|
||||
result = el.GetChildNode(segment.(Int))
|
||||
} else if segmentType == core.StringType {
|
||||
} else if segmentType == types.String {
|
||||
strSegment := segment.(String)
|
||||
|
||||
switch strSegment {
|
||||
@@ -73,7 +75,7 @@ func GetIn(from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
case "length":
|
||||
result = el.Length()
|
||||
case "url":
|
||||
if result.Type() == core.HTMLDocumentType {
|
||||
if result.Type() == types.HTMLDocument {
|
||||
doc, ok := result.(HTMLDocument)
|
||||
|
||||
if ok {
|
||||
@@ -88,22 +90,22 @@ func GetIn(from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
return None, err
|
||||
}
|
||||
} else {
|
||||
return nil, core.TypeError(segmentType, core.IntType, core.StringType)
|
||||
return nil, core.TypeError(segmentType, types.Int, types.String)
|
||||
}
|
||||
|
||||
default:
|
||||
getter, ok := result.(core.Getter)
|
||||
|
||||
if ok {
|
||||
return getter.GetIn(byPath[i:])
|
||||
return getter.GetIn(ctx, byPath[i:])
|
||||
}
|
||||
|
||||
return None, core.TypeError(
|
||||
from.Type(),
|
||||
core.ArrayType,
|
||||
core.ObjectType,
|
||||
core.HTMLDocumentType,
|
||||
core.HTMLElementType,
|
||||
types.Array,
|
||||
types.Object,
|
||||
types.HTMLDocument,
|
||||
types.HTMLElement,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -111,7 +113,7 @@ func GetIn(from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func SetIn(to core.Value, byPath []core.Value, value core.Value) error {
|
||||
func SetIn(ctx context.Context, to core.Value, byPath []core.Value, value core.Value) error {
|
||||
if byPath == nil || len(byPath) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -126,11 +128,11 @@ func SetIn(to core.Value, byPath []core.Value, value core.Value) error {
|
||||
segmentType := segment.Type()
|
||||
|
||||
switch parent.Type() {
|
||||
case core.ObjectType:
|
||||
case types.Object:
|
||||
parent := parent.(*Object)
|
||||
|
||||
if segmentType != core.StringType {
|
||||
return core.TypeError(segmentType, core.StringType)
|
||||
if segmentType != types.String {
|
||||
return core.TypeError(segmentType, types.String)
|
||||
}
|
||||
|
||||
if isTarget == false {
|
||||
@@ -140,9 +142,9 @@ func SetIn(to core.Value, byPath []core.Value, value core.Value) error {
|
||||
}
|
||||
|
||||
break
|
||||
case core.ArrayType:
|
||||
if segmentType != core.IntType {
|
||||
return core.TypeError(segmentType, core.IntType)
|
||||
case types.Array:
|
||||
if segmentType != types.Int {
|
||||
return core.TypeError(segmentType, types.Int)
|
||||
}
|
||||
|
||||
parent := parent.(*Array)
|
||||
@@ -160,19 +162,19 @@ func SetIn(to core.Value, byPath []core.Value, value core.Value) error {
|
||||
setter, ok := parent.(core.Setter)
|
||||
|
||||
if ok {
|
||||
return setter.SetIn(byPath[idx:], value)
|
||||
return setter.SetIn(ctx, byPath[idx:], value)
|
||||
}
|
||||
|
||||
// redefine parent
|
||||
isArray := segmentType == core.IntType
|
||||
isArray := segmentType == types.Int
|
||||
|
||||
// it's not an index
|
||||
if isArray == false {
|
||||
obj := NewObject()
|
||||
parent = obj
|
||||
|
||||
if segmentType != core.StringType {
|
||||
return core.TypeError(segmentType, core.StringType)
|
||||
if segmentType != types.String {
|
||||
return core.TypeError(segmentType, types.String)
|
||||
}
|
||||
|
||||
if isTarget {
|
||||
@@ -190,7 +192,7 @@ func SetIn(to core.Value, byPath []core.Value, value core.Value) error {
|
||||
}
|
||||
|
||||
// set new parent
|
||||
if err := SetIn(to, byPath[0:idx-1], parent); err != nil {
|
||||
if err := SetIn(ctx, to, byPath[0:idx-1], parent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -302,9 +304,9 @@ func Unmarshal(value json.RawMessage) (core.Value, error) {
|
||||
|
||||
func IsCloneable(value core.Value) Boolean {
|
||||
switch value.Type() {
|
||||
case core.ArrayType:
|
||||
case types.Array:
|
||||
return NewBoolean(true)
|
||||
case core.ObjectType:
|
||||
case types.Object:
|
||||
return NewBoolean(true)
|
||||
default:
|
||||
return NewBoolean(false)
|
||||
@@ -313,15 +315,15 @@ func IsCloneable(value core.Value) Boolean {
|
||||
|
||||
func ToBoolean(input core.Value) core.Value {
|
||||
switch input.Type() {
|
||||
case core.BooleanType:
|
||||
case types.Boolean:
|
||||
return input
|
||||
case core.NoneType:
|
||||
case types.None:
|
||||
return False
|
||||
case core.StringType:
|
||||
case types.String:
|
||||
return NewBoolean(input.String() != "")
|
||||
case core.IntType:
|
||||
case types.Int:
|
||||
return NewBoolean(input.(Int) != 0)
|
||||
case core.FloatType:
|
||||
case types.Float:
|
||||
return NewBoolean(input.(Float) != 0)
|
||||
default:
|
||||
return True
|
||||
@@ -330,15 +332,15 @@ func ToBoolean(input core.Value) core.Value {
|
||||
|
||||
func ToArray(input core.Value) core.Value {
|
||||
switch input.Type() {
|
||||
case core.BooleanType,
|
||||
core.IntType,
|
||||
core.FloatType,
|
||||
core.StringType,
|
||||
core.DateTimeType:
|
||||
case types.Boolean,
|
||||
types.Int,
|
||||
types.Float,
|
||||
types.String,
|
||||
types.DateTime:
|
||||
|
||||
return NewArrayWith(input)
|
||||
case core.HTMLElementType,
|
||||
core.HTMLDocumentType:
|
||||
case types.HTMLElement,
|
||||
types.HTMLDocument:
|
||||
val := input.(HTMLNode)
|
||||
attrs := val.GetAttributes()
|
||||
|
||||
@@ -357,9 +359,9 @@ func ToArray(input core.Value) core.Value {
|
||||
})
|
||||
|
||||
return obj
|
||||
case core.ArrayType:
|
||||
case types.Array:
|
||||
return input.Copy()
|
||||
case core.ObjectType:
|
||||
case types.Object:
|
||||
obj, ok := input.(*Object)
|
||||
|
||||
if !ok {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package values_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"testing"
|
||||
@@ -8,39 +9,41 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
type CustomType struct {
|
||||
var CustomType = core.NewType("custom")
|
||||
|
||||
type CustomValue struct {
|
||||
properties map[core.Value]core.Value
|
||||
}
|
||||
|
||||
func (t *CustomType) MarshalJSON() ([]byte, error) {
|
||||
func (t *CustomValue) MarshalJSON() ([]byte, error) {
|
||||
return nil, core.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (t *CustomType) Type() core.Type {
|
||||
return core.CustomType
|
||||
func (t *CustomValue) Type() core.Type {
|
||||
return CustomType
|
||||
}
|
||||
|
||||
func (t *CustomType) String() string {
|
||||
func (t *CustomValue) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t *CustomType) Compare(other core.Value) int {
|
||||
func (t *CustomValue) Compare(other core.Value) int64 {
|
||||
return other.Compare(t) * -1
|
||||
}
|
||||
|
||||
func (t *CustomType) Unwrap() interface{} {
|
||||
func (t *CustomValue) Unwrap() interface{} {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *CustomType) Hash() uint64 {
|
||||
func (t *CustomValue) Hash() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (t *CustomType) Copy() core.Value {
|
||||
func (t *CustomValue) Copy() core.Value {
|
||||
return values.None
|
||||
}
|
||||
|
||||
func (t *CustomType) GetIn(path []core.Value) (core.Value, error) {
|
||||
func (t *CustomValue) GetIn(ctx context.Context, path []core.Value) (core.Value, error) {
|
||||
if path == nil || len(path) == 0 {
|
||||
return values.None, nil
|
||||
}
|
||||
@@ -56,10 +59,10 @@ func (t *CustomType) GetIn(path []core.Value) (core.Value, error) {
|
||||
return propValue, nil
|
||||
}
|
||||
|
||||
return values.GetIn(propValue, path[1:])
|
||||
return values.GetIn(ctx, propValue, path[1:])
|
||||
}
|
||||
|
||||
func (t *CustomType) SetIn(path []core.Value, value core.Value) error {
|
||||
func (t *CustomValue) SetIn(ctx context.Context, path []core.Value, value core.Value) error {
|
||||
if path == nil || len(path) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -77,17 +80,17 @@ func (t *CustomType) SetIn(path []core.Value, value core.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return values.SetIn(propValue, path[1:], value)
|
||||
return values.SetIn(ctx, propValue, path[1:], value)
|
||||
}
|
||||
|
||||
func TestHelpers(t *testing.T) {
|
||||
Convey("Helpers", t, func() {
|
||||
Convey("Getter", func() {
|
||||
Convey("It should get a value by a given path", func() {
|
||||
ct := &CustomType{
|
||||
ct := &CustomValue{
|
||||
properties: map[core.Value]core.Value{
|
||||
values.NewString("foo"): values.NewInt(1),
|
||||
values.NewString("bar"): &CustomType{
|
||||
values.NewString("bar"): &CustomValue{
|
||||
properties: map[core.Value]core.Value{
|
||||
values.NewString("qaz"): values.NewInt(2),
|
||||
},
|
||||
@@ -95,14 +98,16 @@ func TestHelpers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
foo, err := values.GetIn(ct, []core.Value{
|
||||
ctx := context.Background()
|
||||
|
||||
foo, err := values.GetIn(ctx, ct, []core.Value{
|
||||
values.NewString("foo"),
|
||||
})
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(foo, ShouldEqual, values.NewInt(1))
|
||||
|
||||
qaz, err := values.GetIn(ct, []core.Value{
|
||||
qaz, err := values.GetIn(ctx, ct, []core.Value{
|
||||
values.NewString("bar"),
|
||||
values.NewString("qaz"),
|
||||
})
|
||||
@@ -114,10 +119,10 @@ func TestHelpers(t *testing.T) {
|
||||
|
||||
Convey("Setter", func() {
|
||||
Convey("It should get a value by a given path", func() {
|
||||
ct := &CustomType{
|
||||
ct := &CustomValue{
|
||||
properties: map[core.Value]core.Value{
|
||||
values.NewString("foo"): values.NewInt(1),
|
||||
values.NewString("bar"): &CustomType{
|
||||
values.NewString("bar"): &CustomValue{
|
||||
properties: map[core.Value]core.Value{
|
||||
values.NewString("qaz"): values.NewInt(2),
|
||||
},
|
||||
@@ -125,21 +130,23 @@ func TestHelpers(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
err := values.SetIn(ct, []core.Value{
|
||||
ctx := context.Background()
|
||||
|
||||
err := values.SetIn(ctx, ct, []core.Value{
|
||||
values.NewString("foo"),
|
||||
}, values.NewInt(2))
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(ct.properties[values.NewString("foo")], ShouldEqual, values.NewInt(2))
|
||||
|
||||
err = values.SetIn(ct, []core.Value{
|
||||
err = values.SetIn(ctx, ct, []core.Value{
|
||||
values.NewString("bar"),
|
||||
values.NewString("qaz"),
|
||||
}, values.NewString("foobar"))
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
qaz, err := values.GetIn(ct, []core.Value{
|
||||
qaz, err := values.GetIn(ctx, ct, []core.Value{
|
||||
values.NewString("bar"),
|
||||
values.NewString("qaz"),
|
||||
})
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type Int int64
|
||||
|
||||
var ZeroInt = Int(0)
|
||||
const ZeroInt = Int(0)
|
||||
|
||||
func NewInt(input int) Int {
|
||||
return Int(int64(input))
|
||||
@@ -65,16 +66,17 @@ func (t Int) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t Int) Type() core.Type {
|
||||
return core.IntType
|
||||
return types.Int
|
||||
}
|
||||
|
||||
func (t Int) String() string {
|
||||
return strconv.Itoa(int(t))
|
||||
}
|
||||
|
||||
func (t Int) Compare(other core.Value) int {
|
||||
switch other.Type() {
|
||||
case core.IntType:
|
||||
func (t Int) Compare(other core.Value) int64 {
|
||||
otherType := other.Type()
|
||||
|
||||
if otherType == types.Int {
|
||||
i := other.(Int)
|
||||
|
||||
if t == i {
|
||||
@@ -86,7 +88,9 @@ func (t Int) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return +1
|
||||
case core.FloatType:
|
||||
}
|
||||
|
||||
if otherType == types.Float {
|
||||
f := other.(Float)
|
||||
f2 := Float(t)
|
||||
|
||||
@@ -99,11 +103,9 @@ func (t Int) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return +1
|
||||
case core.BooleanType, core.NoneType:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
|
||||
return types.Compare(types.Int, otherType)
|
||||
}
|
||||
|
||||
func (t Int) Unwrap() interface{} {
|
||||
|
||||
@@ -2,6 +2,7 @@ package values
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type none struct{}
|
||||
@@ -13,20 +14,19 @@ func (t *none) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t *none) Type() core.Type {
|
||||
return core.NoneType
|
||||
return types.None
|
||||
}
|
||||
|
||||
func (t *none) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (t *none) Compare(other core.Value) int {
|
||||
switch other.Type() {
|
||||
case core.NoneType:
|
||||
func (t *none) Compare(other core.Value) int64 {
|
||||
if other.Type() == types.None {
|
||||
return 0
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func (t *none) Unwrap() interface{} {
|
||||
|
||||
@@ -7,14 +7,17 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type (
|
||||
ObjectPredicate = func(value core.Value, key string) bool
|
||||
ObjectProperty struct {
|
||||
|
||||
ObjectProperty struct {
|
||||
key string
|
||||
value core.Value
|
||||
}
|
||||
|
||||
Object struct {
|
||||
value map[string]core.Value
|
||||
}
|
||||
@@ -43,7 +46,7 @@ func (t *Object) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t *Object) Type() core.Type {
|
||||
return core.ObjectType
|
||||
return types.Object
|
||||
}
|
||||
|
||||
func (t *Object) String() string {
|
||||
@@ -59,22 +62,23 @@ func (t *Object) String() string {
|
||||
// Compare compares the source object with other core.Value
|
||||
// The behavior of the Compare is similar
|
||||
// to the comparison of objects in ArangoDB
|
||||
func (t *Object) Compare(other core.Value) int {
|
||||
switch other.Type() {
|
||||
case core.ObjectType:
|
||||
func (t *Object) Compare(other core.Value) int64 {
|
||||
if other.Type() == t.Type() {
|
||||
other := other.(*Object)
|
||||
|
||||
if t.Length() == 0 && other.Length() == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if t.Length() < other.Length() {
|
||||
return -1
|
||||
}
|
||||
|
||||
if t.Length() > other.Length() {
|
||||
return 1
|
||||
}
|
||||
|
||||
var res = 0
|
||||
var res int64
|
||||
|
||||
sortedT := sort.StringSlice(t.Keys())
|
||||
sortedT.Sort()
|
||||
@@ -92,6 +96,7 @@ func (t *Object) Compare(other core.Value) int {
|
||||
tVal, _ = t.Get(NewString(tKey))
|
||||
otherVal, _ = other.Get(NewString(tKey))
|
||||
res = tVal.Compare(otherVal)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -105,9 +110,9 @@ func (t *Object) Compare(other core.Value) int {
|
||||
}
|
||||
|
||||
return res
|
||||
default:
|
||||
return 1
|
||||
}
|
||||
|
||||
return types.Compare(types.Object, other.Type())
|
||||
}
|
||||
|
||||
func (t *Object) Unwrap() interface{} {
|
||||
@@ -201,10 +206,6 @@ func (t *Object) Get(key String) (core.Value, Boolean) {
|
||||
return None, NewBoolean(found)
|
||||
}
|
||||
|
||||
func (t *Object) GetIn(path []core.Value) (core.Value, error) {
|
||||
return GetIn(t, path)
|
||||
}
|
||||
|
||||
func (t *Object) Set(key String, value core.Value) {
|
||||
if value != nil {
|
||||
t.value[string(key)] = value
|
||||
@@ -217,20 +218,20 @@ func (t *Object) Remove(key String) {
|
||||
delete(t.value, string(key))
|
||||
}
|
||||
|
||||
func (t *Object) SetIn(path []core.Value, value core.Value) error {
|
||||
return SetIn(t, path, value)
|
||||
}
|
||||
|
||||
func (t *Object) Clone() core.Cloneable {
|
||||
cloned := NewObject()
|
||||
|
||||
var value core.Value
|
||||
var keyString String
|
||||
|
||||
for key := range t.value {
|
||||
keyString = NewString(key)
|
||||
value, _ = t.Get(keyString)
|
||||
if IsCloneable(value) {
|
||||
value = value.(core.Cloneable).Clone()
|
||||
|
||||
cloneable, ok := value.(core.Cloneable)
|
||||
|
||||
if ok {
|
||||
value = cloneable.Clone()
|
||||
}
|
||||
cloned.Set(keyString, value)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package values_test
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
"testing"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
@@ -63,7 +64,7 @@ func TestObject(t *testing.T) {
|
||||
Convey("Should return type", func() {
|
||||
obj := values.NewObject()
|
||||
|
||||
So(obj.Type(), ShouldEqual, core.ObjectType)
|
||||
So(obj.Type().Equals(types.Object), ShouldBeTrue)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
)
|
||||
|
||||
type String string
|
||||
|
||||
var EmptyString = String("")
|
||||
var SpaceString = String(" ")
|
||||
const (
|
||||
EmptyString = String("")
|
||||
SpaceString = String(" ")
|
||||
)
|
||||
|
||||
func NewString(input string) String {
|
||||
if input == "" {
|
||||
@@ -69,24 +72,19 @@ func (t String) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t String) Type() core.Type {
|
||||
return core.StringType
|
||||
return types.String
|
||||
}
|
||||
|
||||
func (t String) String() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
func (t String) Compare(other core.Value) int {
|
||||
switch other.Type() {
|
||||
case core.StringType:
|
||||
return strings.Compare(string(t), other.Unwrap().(string))
|
||||
default:
|
||||
if other.Type() > core.DateTimeType {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 1
|
||||
func (t String) Compare(other core.Value) int64 {
|
||||
if other.Type() == types.String {
|
||||
return int64(strings.Compare(string(t), other.Unwrap().(string)))
|
||||
}
|
||||
|
||||
return types.Compare(types.String, other.Type())
|
||||
}
|
||||
|
||||
func (t String) Unwrap() interface{} {
|
||||
|
||||
44
pkg/runtime/values/types/helpers.go
Normal file
44
pkg/runtime/values/types/helpers.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package types
|
||||
|
||||
import "github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
|
||||
// Comparison table of builtin types
|
||||
var typeComparisonTable = map[core.Type]uint64{
|
||||
None: 0,
|
||||
Boolean: 1,
|
||||
Int: 2,
|
||||
Float: 3,
|
||||
String: 4,
|
||||
DateTime: 5,
|
||||
Array: 6,
|
||||
Object: 7,
|
||||
HTMLElement: 8,
|
||||
HTMLDocument: 9,
|
||||
Binary: 10,
|
||||
}
|
||||
|
||||
func Compare(first, second core.Type) int64 {
|
||||
f, ok := typeComparisonTable[first]
|
||||
|
||||
// custom type
|
||||
if !ok {
|
||||
return -1
|
||||
}
|
||||
|
||||
s, ok := typeComparisonTable[second]
|
||||
|
||||
// custom type
|
||||
if !ok {
|
||||
return 1
|
||||
}
|
||||
|
||||
if f == s {
|
||||
return 0
|
||||
}
|
||||
|
||||
if f > s {
|
||||
return 1
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
176
pkg/runtime/values/types/helpers_test.go
Normal file
176
pkg/runtime/values/types/helpers_test.go
Normal file
@@ -0,0 +1,176 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHelpers(t *testing.T) {
|
||||
Convey("Compare", t, func() {
|
||||
typesList := []core.Type{
|
||||
types.None,
|
||||
types.Boolean,
|
||||
types.Int,
|
||||
types.Float,
|
||||
types.String,
|
||||
types.DateTime,
|
||||
types.Array,
|
||||
types.Object,
|
||||
types.Binary,
|
||||
}
|
||||
|
||||
Convey("None", func() {
|
||||
So(types.Compare(types.None, types.None), ShouldEqual, 0)
|
||||
|
||||
for _, t := range typesList[1:] {
|
||||
So(types.Compare(types.None, t), ShouldEqual, -1)
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Boolean", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.Boolean, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.Boolean, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.Boolean, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Int", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.Int, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.Int, t), ShouldEqual, 1)
|
||||
case types.Int.ID():
|
||||
So(types.Compare(types.Int, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.Int, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Float", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.Float, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.Float, t), ShouldEqual, 1)
|
||||
case types.Int.ID():
|
||||
So(types.Compare(types.Float, t), ShouldEqual, 1)
|
||||
case types.Float.ID():
|
||||
So(types.Compare(types.Float, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.Float, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("String", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.String, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.String, t), ShouldEqual, 1)
|
||||
case types.Int.ID():
|
||||
So(types.Compare(types.String, t), ShouldEqual, 1)
|
||||
case types.Float.ID():
|
||||
So(types.Compare(types.String, t), ShouldEqual, 1)
|
||||
case types.String.ID():
|
||||
So(types.Compare(types.String, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.String, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("DateTime", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, 1)
|
||||
case types.Int.ID():
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, 1)
|
||||
case types.Float.ID():
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, 1)
|
||||
case types.String.ID():
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, 1)
|
||||
case types.DateTime.ID():
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.DateTime, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Array", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 1)
|
||||
case types.Int.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 1)
|
||||
case types.Float.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 1)
|
||||
case types.String.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 1)
|
||||
case types.DateTime.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 1)
|
||||
case types.Array.ID():
|
||||
So(types.Compare(types.Array, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.Array, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Object", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.None.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.Boolean.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.Int.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.Float.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.String.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.DateTime.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.Array.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 1)
|
||||
case types.Object.ID():
|
||||
So(types.Compare(types.Object, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.Object, t), ShouldEqual, -1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Binary", func() {
|
||||
for _, t := range typesList {
|
||||
switch t.ID() {
|
||||
case types.Binary.ID():
|
||||
So(types.Compare(types.Binary, t), ShouldEqual, 0)
|
||||
default:
|
||||
So(types.Compare(types.Binary, t), ShouldEqual, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
17
pkg/runtime/values/types/types.go
Normal file
17
pkg/runtime/values/types/types.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package types
|
||||
|
||||
import "github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
|
||||
var (
|
||||
None = core.NewType("none")
|
||||
Boolean = core.NewType("boolean")
|
||||
Int = core.NewType("int")
|
||||
Float = core.NewType("float")
|
||||
String = core.NewType("string")
|
||||
DateTime = core.NewType("date_time")
|
||||
Array = core.NewType("array")
|
||||
Object = core.NewType("object")
|
||||
Binary = core.NewType("binary")
|
||||
HTMLElement = core.NewType("HTMLElement")
|
||||
HTMLDocument = core.NewType("HTMLDocument")
|
||||
)
|
||||
84
pkg/runtime/values/types/types_test.go
Normal file
84
pkg/runtime/values/types/types_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values/types"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TestValue struct {
|
||||
t core.Type
|
||||
}
|
||||
|
||||
func (v TestValue) MarshalJSON() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (v TestValue) Type() core.Type {
|
||||
return v.t
|
||||
}
|
||||
|
||||
func (v TestValue) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (v TestValue) Compare(other core.Value) int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (v TestValue) Unwrap() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v TestValue) Hash() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (v TestValue) Copy() core.Value {
|
||||
return v
|
||||
}
|
||||
|
||||
func TestType(t *testing.T) {
|
||||
Convey(".Name", t, func() {
|
||||
So(types.None.String(), ShouldEqual, "none")
|
||||
So(types.Boolean.String(), ShouldEqual, "boolean")
|
||||
So(types.Int.String(), ShouldEqual, "int")
|
||||
So(types.Float.String(), ShouldEqual, "float")
|
||||
So(types.String.String(), ShouldEqual, "string")
|
||||
So(types.DateTime.String(), ShouldEqual, "date_time")
|
||||
So(types.Array.String(), ShouldEqual, "array")
|
||||
So(types.Object.String(), ShouldEqual, "object")
|
||||
So(types.Binary.String(), ShouldEqual, "binary")
|
||||
})
|
||||
|
||||
Convey("==", t, func() {
|
||||
typesList := []core.Type{
|
||||
types.None,
|
||||
types.Boolean,
|
||||
types.Int,
|
||||
types.Float,
|
||||
types.String,
|
||||
types.DateTime,
|
||||
types.Array,
|
||||
types.Object,
|
||||
types.Binary,
|
||||
}
|
||||
|
||||
valuesList := []core.Value{
|
||||
TestValue{types.None},
|
||||
TestValue{types.Boolean},
|
||||
TestValue{types.Int},
|
||||
TestValue{types.Float},
|
||||
TestValue{types.String},
|
||||
TestValue{types.DateTime},
|
||||
TestValue{types.Array},
|
||||
TestValue{types.Object},
|
||||
TestValue{types.Binary},
|
||||
}
|
||||
|
||||
for i, t := range typesList {
|
||||
So(t == valuesList[i].Type(), ShouldBeTrue)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user