1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-02-21 19:50:09 +02:00

New type system (#232)

* New type system

* Fixed dot notation for HTML elements
This commit is contained in:
Tim Voronov 2019-02-13 12:31:18 -05:00 committed by GitHub
parent b3bcbda3b9
commit 1af8b37a0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
185 changed files with 1379 additions and 820 deletions

View File

@ -2,6 +2,7 @@ package compiler
import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
type (
@ -35,13 +36,13 @@ func (s *scope) GetVariable(name string) (core.Type, error) {
parents, err := s.parent.GetVariable(name)
if err != nil {
return core.NoneType, err
return types.None, err
}
return parents, nil
}
return core.NoneType, core.Error(ErrVariableNotFound, name)
return types.None, core.Error(ErrVariableNotFound, name)
}
func (s *scope) SetVariable(name string) error {
@ -52,7 +53,7 @@ func (s *scope) SetVariable(name string) error {
}
// TODO: add type detection
s.vars[name] = core.NoneType
s.vars[name] = types.None
return nil
}

View File

@ -3,7 +3,6 @@ package cdp
import (
"context"
"fmt"
"github.com/mafredri/cdp/protocol/dom"
"hash/fnv"
"sync"
"time"
@ -13,7 +12,9 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/logging"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/protocol/dom"
"github.com/mafredri/cdp/protocol/input"
"github.com/mafredri/cdp/protocol/page"
"github.com/mafredri/cdp/rpcc"
@ -142,7 +143,7 @@ func (doc *HTMLDocument) MarshalJSON() ([]byte, error) {
}
func (doc *HTMLDocument) Type() core.Type {
return core.HTMLDocumentType
return types.HTMLDocument
}
func (doc *HTMLDocument) String() string {
@ -176,22 +177,17 @@ func (doc *HTMLDocument) Copy() core.Value {
return values.None
}
func (doc *HTMLDocument) Compare(other core.Value) int {
func (doc *HTMLDocument) Compare(other core.Value) int64 {
doc.Lock()
defer doc.Unlock()
switch other.Type() {
case core.HTMLDocumentType:
if other.Type() == types.HTMLDocument {
other := other.(*HTMLDocument)
return doc.url.Compare(other.url)
default:
if other.Type() > core.HTMLDocumentType {
return -1
}
return 1
}
return types.Compare(other.Type(), types.HTMLDocument)
}
func (doc *HTMLDocument) Close() error {
@ -399,7 +395,7 @@ func (doc *HTMLDocument) ClickBySelector(selector values.String) (values.Boolean
return values.False, err
}
if res.Type() == core.BooleanType {
if res.Type() == types.Boolean {
return res.(values.Boolean), nil
}
@ -431,7 +427,7 @@ func (doc *HTMLDocument) ClickBySelectorAll(selector values.String) (values.Bool
return values.False, err
}
if res.Type() == core.BooleanType {
if res.Type() == types.Boolean {
return res.(values.Boolean), nil
}
@ -461,7 +457,7 @@ func (doc *HTMLDocument) InputBySelector(selector values.String, value core.Valu
return values.False, err
}
if res.Type() == core.BooleanType && res.(values.Boolean) == values.False {
if res.Type() == types.Boolean && res.(values.Boolean) == values.False {
return values.False, nil
}
@ -531,7 +527,7 @@ func (doc *HTMLDocument) SelectBySelector(selector values.String, value *values.
return arr, nil
}
return nil, core.TypeError(core.ArrayType, res.Type())
return nil, core.TypeError(types.Array, res.Type())
}
func (doc *HTMLDocument) HoverBySelector(selector values.String) error {

View File

@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/gofrs/uuid"
"hash/fnv"
"strconv"
"strings"
@ -16,6 +15,8 @@ import (
"github.com/MontFerret/ferret/pkg/drivers/common"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
"github.com/gofrs/uuid"
"github.com/mafredri/cdp"
"github.com/mafredri/cdp/protocol/dom"
"github.com/mafredri/cdp/protocol/input"
@ -195,7 +196,7 @@ func (el *HTMLElement) Close() error {
}
func (el *HTMLElement) Type() core.Type {
return core.HTMLElementType
return types.HTMLElement
}
func (el *HTMLElement) MarshalJSON() ([]byte, error) {
@ -212,9 +213,8 @@ func (el *HTMLElement) String() string {
return el.InnerHTML().String()
}
func (el *HTMLElement) Compare(other core.Value) int {
switch other.Type() {
case core.HTMLDocumentType:
func (el *HTMLElement) Compare(other core.Value) int64 {
if other.Type() == types.HTMLElement {
other := other.(*HTMLElement)
id := int(el.id.backendID)
@ -229,13 +229,9 @@ func (el *HTMLElement) Compare(other core.Value) int {
}
return -1
default:
if other.Type() > core.HTMLElementType {
return -1
}
return 1
}
return types.Compare(other.Type(), types.HTMLElement)
}
func (el *HTMLElement) Unwrap() interface{} {
@ -711,7 +707,7 @@ func (el *HTMLElement) WaitForClass(class values.String, timeout values.Int) err
func() (core.Value, error) {
current := el.GetAttribute("class")
if current.Type() != core.StringType {
if current.Type() != types.String {
return values.None, nil
}
@ -850,7 +846,7 @@ func (el *HTMLElement) Select(value *values.Array) (*values.Array, error) {
return arr, nil
}
return nil, core.TypeError(core.ArrayType, res.Type())
return nil, core.TypeError(types.Array, res.Type())
}
func (el *HTMLElement) ScrollIntoView() error {

View File

@ -4,6 +4,10 @@ import (
"bytes"
"context"
"errors"
"golang.org/x/sync/errgroup"
"math"
"strings"
"github.com/MontFerret/ferret/pkg/drivers/cdp/eval"
"github.com/MontFerret/ferret/pkg/drivers/cdp/events"
"github.com/MontFerret/ferret/pkg/drivers/common"
@ -13,9 +17,6 @@ import (
"github.com/mafredri/cdp/protocol/dom"
"github.com/mafredri/cdp/protocol/page"
"github.com/mafredri/cdp/protocol/runtime"
"golang.org/x/sync/errgroup"
"math"
"strings"
)
type (

View File

@ -2,9 +2,10 @@ package drivers
import (
"context"
"io"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"io"
)
type (

View File

@ -3,6 +3,7 @@ package http
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/PuerkitoBio/goquery"
)
@ -33,22 +34,17 @@ func NewHTMLDocument(
}
func (doc *HTMLDocument) Type() core.Type {
return core.HTMLDocumentType
return types.HTMLDocument
}
func (doc *HTMLDocument) Compare(other core.Value) int {
switch other.Type() {
case core.HTMLDocumentType:
func (doc *HTMLDocument) Compare(other core.Value) int64 {
if other.Type() == types.HTMLDocument {
otherDoc := other.(values.HTMLDocument)
return doc.url.Compare(otherDoc.URL())
default:
if other.Type() > core.HTMLDocumentType {
return -1
}
return 1
}
return types.Compare(other.Type(), types.HTMLDocument)
}
func (doc *HTMLDocument) URL() core.Value {

View File

@ -3,11 +3,11 @@ package http
import (
"bytes"
"context"
"github.com/MontFerret/ferret/pkg/runtime/logging"
"net/http"
"net/url"
"github.com/MontFerret/ferret/pkg/drivers/common"
"github.com/MontFerret/ferret/pkg/runtime/logging"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/PuerkitoBio/goquery"
"github.com/corpix/uarand"

View File

@ -7,6 +7,7 @@ import (
"github.com/MontFerret/ferret/pkg/drivers/common"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
"github.com/PuerkitoBio/goquery"
)
@ -29,25 +30,20 @@ func (el *HTMLElement) MarshalJSON() ([]byte, error) {
}
func (el *HTMLElement) Type() core.Type {
return core.HTMLElementType
return types.HTMLElement
}
func (el *HTMLElement) String() string {
return el.InnerHTML().String()
}
func (el *HTMLElement) Compare(other core.Value) int {
switch other.Type() {
case core.HTMLElementType:
func (el *HTMLElement) Compare(other core.Value) int64 {
if other.Type() == types.HTMLElement {
// TODO: complete the comparison
return -1
default:
if other.Type() > core.HTMLElementType {
return -1
}
return 1
}
return types.Compare(other.Type(), types.HTMLElement)
}
func (el *HTMLElement) Unwrap() interface{} {

View File

@ -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

View File

@ -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")

View File

@ -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())
})
}

View File

@ -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
View 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
}

View 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)
})
}

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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

View File

@ -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)
}

View File

@ -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 {

View File

@ -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,
)
}
}

View File

@ -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{} {

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -2,6 +2,7 @@ package operators
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
)

View File

@ -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

View File

@ -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
}

View File

@ -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)
}

View File

@ -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))

View File

@ -2,6 +2,7 @@ package operators
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
)

View File

@ -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)
})
}

View File

@ -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)
}

View File

@ -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)
})
})

View File

@ -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{} {

View File

@ -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{} {

View File

@ -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)
})
})

View File

@ -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{} {

View File

@ -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{} {

View File

@ -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 {

View File

@ -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"),
})

View File

@ -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{} {

View File

@ -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{} {

View File

@ -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)
}

View File

@ -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)
})
})

View File

@ -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{} {

View 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
}

View 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)
}
}
})
})
}

View 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")
)

View 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)
}
})
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Append appends a new item to an array and returns a new array with a given element.
@ -19,7 +20,7 @@ func Append(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -30,7 +31,7 @@ func Append(_ context.Context, args ...core.Value) (core.Value, error) {
unique := values.False
if len(args) > 2 {
err = core.ValidateType(args[2], core.BooleanType)
err = core.ValidateType(args[2], types.Boolean)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// First returns a first element from a given array.
@ -17,7 +18,7 @@ func First(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, nil

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Flatten turn an array of arrays into a flat array.
@ -22,7 +23,7 @@ func Flatten(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -32,7 +33,7 @@ func Flatten(_ context.Context, args ...core.Value) (core.Value, error) {
level := 1
if len(args) > 1 {
err = core.ValidateType(args[1], core.IntType)
err = core.ValidateType(args[1], types.Int)
if err != nil {
return values.None, err
@ -49,7 +50,7 @@ func Flatten(_ context.Context, args ...core.Value) (core.Value, error) {
currentLevel++
input.ForEach(func(value core.Value, idx int) bool {
if value.Type() != core.ArrayType || currentLevel > level {
if value.Type() != types.Array || currentLevel > level {
result.Push(value)
} else {
unwrap(value.(*values.Array))

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Intersection return the intersection of all arrays specified.
@ -27,7 +28,7 @@ func sections(args []core.Value, count int) (core.Value, error) {
capacity := len(args)
for _, i := range args {
err := core.ValidateType(i, core.ArrayType)
err := core.ValidateType(i, types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Last returns the last element of an array.
@ -17,7 +18,7 @@ func Last(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, nil

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Minus return the difference of all arrays specified.
@ -22,7 +23,7 @@ func Minus(_ context.Context, args ...core.Value) (core.Value, error) {
capacity := values.NewInt(0)
for idx, i := range args {
err := core.ValidateType(i, core.ArrayType)
err := core.ValidateType(i, types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Nth returns the element of an array at a given position.
@ -20,13 +21,13 @@ func Nth(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.IntType)
err = core.ValidateType(args[1], types.Int)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Pop returns a new array without last element.
@ -17,7 +18,7 @@ func Pop(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Position returns a value indicating whether an element is contained in array. Optionally returns its position.
@ -18,7 +19,7 @@ func Position(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -29,7 +30,7 @@ func Position(_ context.Context, args ...core.Value) (core.Value, error) {
retIdx := false
if len(args) > 2 {
err = core.ValidateType(args[2], core.BooleanType)
err = core.ValidateType(args[2], types.Boolean)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Push create a new array with appended value.
@ -19,7 +20,7 @@ func Push(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -30,7 +31,7 @@ func Push(_ context.Context, args ...core.Value) (core.Value, error) {
uniq := false
if len(args) > 2 {
err = core.ValidateType(args[2], core.BooleanType)
err = core.ValidateType(args[2], types.Boolean)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// RemoveNth returns a new array without an element by a given position.
@ -18,13 +19,13 @@ func RemoveNth(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.IntType)
err = core.ValidateType(args[1], types.Int)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// RemoveValue returns a new array with removed all occurrences of value in a given array.
@ -20,7 +21,7 @@ func RemoveValue(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -31,7 +32,7 @@ func RemoveValue(_ context.Context, args ...core.Value) (core.Value, error) {
limit := -1
if len(args) > 2 {
err = core.ValidateType(args[2], core.IntType)
err = core.ValidateType(args[2], types.Int)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// RemoveValues returns a new array with removed all occurrences of values in a given array.
@ -18,13 +19,13 @@ func RemoveValues(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.ArrayType)
err = core.ValidateType(args[1], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Reverse return a new array with its elements reversed.
@ -17,7 +18,7 @@ func Reverse(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Shift returns a new array without the first element.
@ -17,7 +18,7 @@ func Shift(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Slice returns a new sliced array.
@ -19,13 +20,13 @@ func Slice(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.IntType)
err = core.ValidateType(args[1], types.Int)
if err != nil {
return values.None, err
@ -36,7 +37,7 @@ func Slice(_ context.Context, args ...core.Value) (core.Value, error) {
length := values.NewInt(int(arr.Length()))
if len(args) > 2 {
if args[2].Type() == core.IntType {
if args[2].Type() == types.Int {
arg2 := args[2].(values.Int)
if arg2 > 0 {

View File

@ -2,8 +2,10 @@ package arrays
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Sorted sorts all elements in anyArray.
@ -17,7 +19,7 @@ func Sorted(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// SortedUnique sorts all elements in anyArray.
@ -19,7 +20,7 @@ func SortedUnique(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Union returns the union of all passed arrays.
@ -17,7 +18,7 @@ func Union(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -27,7 +28,7 @@ func Union(_ context.Context, args ...core.Value) (core.Value, error) {
result := values.NewArray(len(args) * int(firstArrLen))
for _, arg := range args {
err := core.ValidateType(arg, core.ArrayType)
err := core.ValidateType(arg, types.Array)
if err != nil {
return values.None, err

View File

@ -2,8 +2,10 @@ package arrays
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
func UnionDistinct(_ context.Context, args ...core.Value) (core.Value, error) {
@ -13,7 +15,7 @@ func UnionDistinct(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -24,7 +26,7 @@ func UnionDistinct(_ context.Context, args ...core.Value) (core.Value, error) {
hashes := make(map[uint64]bool)
for _, arg := range args {
err := core.ValidateType(arg, core.ArrayType)
err := core.ValidateType(arg, types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Unique returns all unique elements from a given array.
@ -17,7 +18,7 @@ func Unique(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Unshift prepends value to a given array.
@ -20,7 +21,7 @@ func Unshift(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.ArrayType)
err = core.ValidateType(args[0], types.Array)
if err != nil {
return values.None, err
@ -31,7 +32,7 @@ func Unshift(_ context.Context, args ...core.Value) (core.Value, error) {
uniq := values.False
if len(args) > 2 {
err = core.ValidateType(args[2], core.BooleanType)
err = core.ValidateType(args[2], types.Boolean)
if err != nil {
return values.None, err

View File

@ -2,9 +2,11 @@ package collections
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"
)
func Length(_ context.Context, inputs ...core.Value) (core.Value, error) {
@ -15,19 +17,20 @@ func Length(_ context.Context, inputs ...core.Value) (core.Value, error) {
}
value := inputs[0]
err = core.ValidateType(
value,
core.StringType,
core.ArrayType,
core.ObjectType,
core.HTMLElementType,
core.HTMLDocumentType,
core.BinaryType,
)
if err != nil {
return values.None, err
c, ok := value.(collections.Collection)
if !ok {
return values.None, core.TypeError(value.Type(),
types.String,
types.Array,
types.Object,
types.HTMLElement,
types.HTMLDocument,
types.Binary,
core.NewType("Collection"),
)
}
return value.(collections.Collection).Length(), nil
return c.Length(), nil
}

View File

@ -5,12 +5,13 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
var (
sliceDateTime = []core.Type{core.DateTimeType}
sliceIntType = []core.Type{core.IntType}
sliceStringType = []core.Type{core.StringType}
sliceDateTime = []core.Type{types.DateTime}
sliceIntType = []core.Type{types.Int}
sliceStringType = []core.Type{types.String}
emptyDateTime values.DateTime
emptyInt values.Int

View File

@ -1,12 +1,12 @@
package datetime
import (
"github.com/pkg/errors"
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
"github.com/pkg/errors"
)
// DateCompare check if two partial dates match.
@ -36,7 +36,7 @@ func DateCompare(_ context.Context, args ...core.Value) (core.Value, error) {
rangeEnd := values.NewString("millisecond")
if len(args) == 4 {
if err = core.ValidateType(args[3], core.StringType); err != nil {
if err = core.ValidateType(args[3], types.String); err != nil {
return values.None, err
}
rangeEnd = args[3].(values.String)

View File

@ -6,6 +6,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Date convert RFC3339 date time string to DateTime object.
@ -17,7 +18,7 @@ func Date(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.StringType)
err = core.ValidateType(args[0], types.String)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateDay returns the day of date as a number.
@ -16,7 +17,7 @@ func DateDay(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -3,9 +3,9 @@ package datetime
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateDayOfWeek returns number of the weekday from the date. Sunday is the 0th day of week.
@ -17,7 +17,7 @@ func DateDayOfWeek(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -3,9 +3,9 @@ package datetime
import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateDayOfYear returns the day of year number of date.
@ -18,7 +18,7 @@ func DateDayOfYear(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -6,6 +6,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
var daysCount = map[time.Month]int{
@ -32,7 +33,7 @@ func DateDaysInMonth(_ context.Context, args ...core.Value) (core.Value, error)
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateDiff returns the difference between two dates in given time unit.
@ -34,7 +35,7 @@ func DateDiff(_ context.Context, args ...core.Value) (core.Value, error) {
isFloat := values.NewBoolean(false)
if len(args) == 4 {
err = core.ValidateType(args[3], core.BooleanType)
err = core.ValidateType(args[3], types.Boolean)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateFormat format date according to the given format string.
@ -16,12 +17,12 @@ func DateFormat(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err
}

View File

@ -31,24 +31,28 @@ func (tc *testCase) Do(t *testing.T, fn core.Function) {
So(err, ShouldBeNil)
}
So(actual.Type(), ShouldEqual, expected.Type())
So(actual.Type().Equals(expected.Type()), ShouldBeTrue)
So(actual.Compare(expected), ShouldEqual, 0)
})
}
func mustDefaultLayoutDt(timeString string) values.DateTime {
dt, err := defaultLayoutDt(timeString)
if err != nil {
panic(err)
}
return dt
}
func mustLayoutDt(layout, value string) values.DateTime {
dt, err := layoutDt(layout, value)
if err != nil {
panic(err)
}
return dt
}
@ -58,8 +62,10 @@ func defaultLayoutDt(timeString string) (values.DateTime, error) {
func layoutDt(layout, value string) (values.DateTime, error) {
t, err := time.Parse(layout, value)
if err != nil {
return values.DateTime{}, err
}
return values.NewDateTime(t), nil
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateHour returns the hour of date as a number.
@ -16,7 +17,7 @@ func DateHour(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateLeapYear returns true if date is in a leap year else false.
@ -16,7 +17,7 @@ func DateLeapYear(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateMillisecond returns the millisecond of date as a number.
@ -16,7 +17,7 @@ func DateMillisecond(_ context.Context, args ...core.Value) (core.Value, error)
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateMinute returns the minute of date as a number.
@ -16,7 +17,7 @@ func DateMinute(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateMonth returns the month of date as a number.
@ -16,7 +17,7 @@ func DateMonth(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -6,6 +6,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateQuarter returns which quarter date belongs to.
@ -17,7 +18,7 @@ func DateQuarter(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateSecond returns the second of date as a number.
@ -16,7 +17,7 @@ func DateSecond(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// DateYear returns the year extracted from the given date.
@ -16,7 +17,7 @@ func DateYear(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.DateTimeType)
err = core.ValidateType(args[0], types.DateTime)
if err != nil {
return values.None, err
}

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Click dispatches click event on a given element
@ -21,7 +22,7 @@ func Click(_ context.Context, args ...core.Value) (core.Value, error) {
if len(args) == 1 {
arg1 := args[0]
err := core.ValidateType(arg1, core.HTMLElementType)
err := core.ValidateType(arg1, types.HTMLElement)
if err != nil {
return values.False, err
@ -40,7 +41,7 @@ func Click(_ context.Context, args ...core.Value) (core.Value, error) {
arg1 := args[0]
selector := args[1].String()
err = core.ValidateType(arg1, core.HTMLDocumentType)
err = core.ValidateType(arg1, types.HTMLDocument)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// ClickAll dispatches click event on all matched element
@ -21,7 +22,7 @@ func ClickAll(_ context.Context, args ...core.Value) (core.Value, error) {
arg1 := args[0]
selector := args[1].String()
err = core.ValidateType(arg1, core.HTMLDocumentType)
err = core.ValidateType(arg1, types.HTMLDocument)
if err != nil {
return values.None, err

View File

@ -2,10 +2,12 @@ package html
import (
"context"
"time"
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"time"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
type DocumentLoadParams struct {
@ -29,7 +31,7 @@ func Document(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.StringType)
err = core.ValidateType(args[0], types.String)
if err != nil {
return values.None, err
@ -83,11 +85,11 @@ func newDefaultDocLoadParams() DocumentLoadParams {
func newDocLoadParams(arg core.Value) (DocumentLoadParams, error) {
res := newDefaultDocLoadParams()
if err := core.ValidateType(arg, core.BooleanType, core.ObjectType); err != nil {
if err := core.ValidateType(arg, types.Boolean, types.Object); err != nil {
return res, err
}
if arg.Type() == core.BooleanType {
if arg.Type() == types.Boolean {
res.Dynamic = arg.(values.Boolean)
return res, nil
@ -98,7 +100,7 @@ func newDocLoadParams(arg core.Value) (DocumentLoadParams, error) {
isDynamic, exists := obj.Get(values.NewString("dynamic"))
if exists {
if err := core.ValidateType(isDynamic, core.BooleanType); err != nil {
if err := core.ValidateType(isDynamic, types.Boolean); err != nil {
return res, err
}
@ -108,7 +110,7 @@ func newDocLoadParams(arg core.Value) (DocumentLoadParams, error) {
timeout, exists := obj.Get(values.NewString("timeout"))
if exists {
if err := core.ValidateType(timeout, core.IntType); err != nil {
if err := core.ValidateType(timeout, types.Int); err != nil {
return res, err
}

View File

@ -7,6 +7,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Download a resource from the given URL.
@ -20,7 +21,7 @@ func Download(_ context.Context, args ...core.Value) (core.Value, error) {
}
arg1 := args[0]
err = core.ValidateType(arg1, core.StringType)
err = core.ValidateType(arg1, types.String)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Element finds an element by a given CSS selector.
@ -29,13 +30,13 @@ func queryArgs(args []core.Value) (values.HTMLNode, values.String, error) {
return nil, values.EmptyString, err
}
err = core.ValidateType(args[0], core.HTMLDocumentType, core.HTMLElementType)
err = core.ValidateType(args[0], types.HTMLDocument, types.HTMLElement)
if err != nil {
return nil, values.EmptyString, err
}
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return nil, values.EmptyString, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// Hover fetches an element with selector, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element.
@ -19,14 +20,14 @@ func Hover(_ context.Context, args ...core.Value) (core.Value, error) {
}
// document or element
err = core.ValidateType(args[0], core.HTMLDocumentType, core.HTMLElementType)
err = core.ValidateType(args[0], types.HTMLDocument, types.HTMLElement)
if err != nil {
return values.None, err
}
if len(args) == 2 {
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// InnerHTML Returns inner HTML string of a given or matched by CSS selector element
@ -18,7 +19,7 @@ func InnerHTML(_ context.Context, args ...core.Value) (core.Value, error) {
return values.EmptyString, err
}
err = core.ValidateType(args[0], core.HTMLDocumentType, core.HTMLElementType)
err = core.ValidateType(args[0], types.HTMLDocument, types.HTMLElement)
if err != nil {
return values.None, err
@ -30,7 +31,7 @@ func InnerHTML(_ context.Context, args ...core.Value) (core.Value, error) {
return node.InnerHTML(), nil
}
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// InnerHTMLAll returns an array of inner HTML strings of matched elements.
@ -18,13 +19,13 @@ func InnerHTMLAll(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.HTMLDocumentType, core.HTMLElementType)
err = core.ValidateType(args[0], types.HTMLDocument, types.HTMLElement)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// InnerText returns inner text string of a given or matched by CSS selector element
@ -18,7 +19,7 @@ func InnerText(_ context.Context, args ...core.Value) (core.Value, error) {
return values.EmptyString, err
}
err = core.ValidateType(args[0], core.HTMLDocumentType, core.HTMLElementType)
err = core.ValidateType(args[0], types.HTMLDocument, types.HTMLElement)
if err != nil {
return values.None, err
@ -30,7 +31,7 @@ func InnerText(_ context.Context, args ...core.Value) (core.Value, error) {
return node.InnerText(), nil
}
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err

View File

@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/runtime/values/types"
)
// InnerTextAll returns an array of inner text of matched elements.
@ -18,13 +19,13 @@ func InnerTextAll(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, err
}
err = core.ValidateType(args[0], core.HTMLDocumentType, core.HTMLElementType)
err = core.ValidateType(args[0], types.HTMLDocument, types.HTMLElement)
if err != nil {
return values.None, err
}
err = core.ValidateType(args[1], core.StringType)
err = core.ValidateType(args[1], types.String)
if err != nil {
return values.None, err

Some files were not shown because too many files have changed in this diff Show More