Add ‘fncs’ package for all sql function commands

This commit is contained in:
Tobie Morgan Hitchcock 2017-11-16 20:31:20 +00:00
parent af00a45721
commit 08cf03f98b
42 changed files with 4119 additions and 0 deletions

237
util/fncs/args.go Normal file
View file

@ -0,0 +1,237 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"fmt"
"math"
"strconv"
"time"
"github.com/abcum/surreal/sql"
)
var defaultTime = time.Unix(0, 0)
func outputFloat(val float64) (interface{}, error) {
switch {
case math.IsNaN(val):
return nil, nil
case math.IsInf(val, 0):
return nil, nil
default:
return val, nil
}
}
func ensureString(val interface{}) (out string, ok bool) {
switch val := val.(type) {
case string:
return val, true
case nil:
return "", true
default:
return fmt.Sprint(val), true
}
}
func ensureBytes(val interface{}) (out []byte, ok bool) {
switch val := val.(type) {
case []byte:
return val, true
case string:
return []byte(val), true
case nil:
return []byte(""), true
default:
return []byte(fmt.Sprint(val)), true
}
}
func ensureBool(val interface{}) (out bool, ok bool) {
switch val := val.(type) {
case bool:
return val, true
case string:
if val, err := strconv.ParseBool(val); err == nil {
return val, true
}
}
return false, false
}
func ensureInt(val interface{}) (out int64, ok bool) {
switch val := val.(type) {
case int:
return int64(val), true
case int64:
return int64(val), true
case uint:
return int64(val), true
case uint64:
return int64(val), true
case float32:
return int64(val), true
case float64:
return int64(val), true
case string:
if val, err := strconv.ParseFloat(val, 64); err == nil {
return int64(val), true
}
}
return 0, false
}
func ensureFloat(val interface{}) (out float64, ok bool) {
switch val := val.(type) {
case int:
return float64(val), true
case int64:
return float64(val), true
case uint:
return float64(val), true
case uint64:
return float64(val), true
case float32:
return float64(val), true
case float64:
return float64(val), true
case string:
if val, err := strconv.ParseFloat(val, 64); err == nil {
return float64(val), true
}
}
return 0, false
}
func ensureTime(val interface{}) (out time.Time, ok bool) {
switch val := val.(type) {
case time.Time:
return val, true
}
return defaultTime, false
}
func ensurePoint(val interface{}) (out *sql.Point, ok bool) {
switch val := val.(type) {
case *sql.Point:
return val, true
}
return nil, false
}
func ensureCircle(val interface{}) (out *sql.Circle, ok bool) {
switch val := val.(type) {
case *sql.Circle:
return val, true
}
return nil, false
}
func ensurePolygon(val interface{}) (out *sql.Polygon, ok bool) {
switch val := val.(type) {
case *sql.Polygon:
return val, true
}
return nil, false
}
func ensureGeometry(val interface{}) (out sql.Expr, ok bool) {
switch val := val.(type) {
case *sql.Point:
return val, true
case *sql.Circle:
return val, true
case *sql.Polygon:
return val, true
}
return nil, false
}
func ensureDuration(val interface{}) (out time.Duration, ok bool) {
switch val := val.(type) {
case time.Duration:
return val, true
}
return 0, false
}
func ensureSlice(args interface{}) (out []interface{}, ok bool) {
if i, ok := args.([]interface{}); ok {
out = i
} else {
out = []interface{}{args}
}
return out, true
}
func ensureObject(args interface{}) (out map[string]interface{}, ok bool) {
if i, ok := args.(map[string]interface{}); ok {
out = i
} else {
out = map[string]interface{}{}
}
return out, true
}
func ensureInts(args interface{}) (out []int64) {
arr, _ := ensureSlice(args)
for _, val := range arr {
switch val := val.(type) {
case int:
out = append(out, int64(val))
case int64:
out = append(out, int64(val))
case uint:
out = append(out, int64(val))
case uint64:
out = append(out, int64(val))
case float32:
out = append(out, int64(val))
case float64:
out = append(out, int64(val))
case string:
if val, err := strconv.ParseFloat(val, 64); err == nil {
out = append(out, int64(val))
}
}
}
return
}
func ensureFloats(args interface{}) (out []float64) {
arr, _ := ensureSlice(args)
for _, val := range arr {
switch val := val.(type) {
case int:
out = append(out, float64(val))
case int64:
out = append(out, float64(val))
case uint:
out = append(out, float64(val))
case uint64:
out = append(out, float64(val))
case float32:
out = append(out, float64(val))
case float64:
out = append(out, float64(val))
case string:
if val, err := strconv.ParseFloat(val, 64); err == nil {
out = append(out, float64(val))
}
}
}
return
}

167
util/fncs/args_test.go Normal file
View file

@ -0,0 +1,167 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"testing"
"time"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestArgs(t *testing.T) {
now := time.Now()
args := []interface{}{
int(1),
int64(1),
uint(1),
uint64(1),
float32(1.5),
float64(1.5),
string("1"),
string("1.5"),
string("test"),
[]byte("test"),
map[string]interface{}{"test": true},
}
good := args[0:8]
oops := args[8:11]
Convey("An argument will convert to string if possible", t, func() {
for _, arg := range args {
val, ok := ensureString(arg)
So(ok, ShouldEqual, true)
So(val, ShouldHaveSameTypeAs, string(""))
}
})
Convey("An argument will convert to []byte if possible", t, func() {
for _, arg := range args {
val, ok := ensureBytes(arg)
So(ok, ShouldEqual, true)
So(val, ShouldHaveSameTypeAs, []byte(""))
}
})
Convey("An argument will convert to int64 if possible", t, func() {
for _, arg := range good {
val, ok := ensureInt(arg)
So(ok, ShouldEqual, true)
So(val, ShouldHaveSameTypeAs, int64(0))
}
for _, arg := range oops {
val, ok := ensureInt(arg)
So(ok, ShouldEqual, false)
So(val, ShouldHaveSameTypeAs, int64(0))
}
})
Convey("An argument will convert to float64 if possible", t, func() {
for _, arg := range good {
val, ok := ensureFloat(arg)
So(ok, ShouldEqual, true)
So(val, ShouldHaveSameTypeAs, float64(0))
}
for _, arg := range oops {
val, ok := ensureFloat(arg)
So(ok, ShouldEqual, false)
So(val, ShouldHaveSameTypeAs, float64(0))
}
})
Convey("An argument will convert to time.Time if possible", t, func() {
res, ok := ensureTime("test")
So(ok, ShouldEqual, false)
So(res, ShouldEqual, time.Unix(0, 0))
one, ok := ensureTime(now)
So(ok, ShouldEqual, true)
So(one, ShouldEqual, now)
})
Convey("An argument will convert to *sql.Point if possible", t, func() {
res, ok := ensurePoint("test")
So(ok, ShouldEqual, false)
So(res, ShouldEqual, nil)
one, ok := ensurePoint(&sql.Point{})
So(ok, ShouldEqual, true)
So(one, ShouldResemble, &sql.Point{})
})
Convey("An argument will convert to *sql.Circle if possible", t, func() {
res, ok := ensureCircle("test")
So(ok, ShouldEqual, false)
So(res, ShouldEqual, nil)
one, ok := ensureCircle(&sql.Circle{})
So(ok, ShouldEqual, true)
So(one, ShouldResemble, &sql.Circle{})
})
Convey("An argument will convert to *sql.Polygon if possible", t, func() {
res, ok := ensurePolygon("test")
So(ok, ShouldEqual, false)
So(res, ShouldEqual, nil)
one, ok := ensurePolygon(&sql.Polygon{})
So(ok, ShouldEqual, true)
So(one, ShouldResemble, &sql.Polygon{})
})
Convey("An argument will convert to *sql.Polygon if possible", t, func() {
res, ok := ensureGeometry("test")
So(ok, ShouldEqual, false)
So(res, ShouldEqual, nil)
one, ok := ensureGeometry(&sql.Point{})
So(ok, ShouldEqual, true)
So(one, ShouldResemble, &sql.Point{})
two, ok := ensureGeometry(&sql.Circle{})
So(ok, ShouldEqual, true)
So(two, ShouldResemble, &sql.Circle{})
tre, ok := ensureGeometry(&sql.Polygon{})
So(ok, ShouldEqual, true)
So(tre, ShouldResemble, &sql.Polygon{})
})
Convey("Arguments are converted to []int64 if possible", t, func() {
res := ensureInts(args)
So(res, ShouldHaveSameTypeAs, []int64{})
So(len(res), ShouldEqual, 8)
})
Convey("Arguments are converted to []float64 if possible", t, func() {
res := ensureFloats(args)
So(res, ShouldHaveSameTypeAs, []float64{})
So(len(res), ShouldEqual, 8)
})
Convey("Arguments are converted to []interface{} if possible", t, func() {
for _, arg := range args {
res, _ := ensureSlice(arg)
So(res, ShouldHaveSameTypeAs, []interface{}{})
}
})
Convey("Arguments are converted to map[string]interface{} if possible", t, func() {
for _, arg := range args {
res, _ := ensureObject(arg)
So(res, ShouldHaveSameTypeAs, map[string]interface{}{})
}
})
}

27
util/fncs/batch.go Normal file
View file

@ -0,0 +1,27 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/sql"
)
func batch(ctx context.Context, args ...interface{}) (*sql.Batch, error) {
tb, _ := ensureString(args[0])
id, _ := ensureSlice(args[1])
return sql.NewBatch(tb, id), nil
}

36
util/fncs/batch_test.go Normal file
View file

@ -0,0 +1,36 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestBatch(t *testing.T) {
var res interface{}
Convey("batch() works properly", t, func() {
res, _ = Run(context.Background(), "batch", 1, []interface{}{1, 2, 3})
So(res, ShouldResemble, sql.NewBatch("1", []interface{}{1, 2, 3}))
res, _ = Run(context.Background(), "batch", "test", []interface{}{1, 2, 3})
So(res, ShouldResemble, sql.NewBatch("test", []interface{}{1, 2, 3}))
})
}

40
util/fncs/bcrypt.go Normal file
View file

@ -0,0 +1,40 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"golang.org/x/crypto/bcrypt"
)
func bcryptCompare(ctx context.Context, args ...interface{}) (bool, error) {
if h, ok := ensureString(args[0]); ok {
if s, ok := ensureString(args[1]); ok {
e := bcrypt.CompareHashAndPassword([]byte(h), []byte(s))
if e == nil {
return true, nil
}
}
}
return false, nil
}
func bcryptGenerate(ctx context.Context, args ...interface{}) ([]byte, error) {
s, _ := ensureString(args[0])
p := []byte(s)
o := bcrypt.DefaultCost
return bcrypt.GenerateFromPassword(p, o)
}

41
util/fncs/bcrypt_test.go Normal file
View file

@ -0,0 +1,41 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestBcrypt(t *testing.T) {
Convey("bcrypt.compare(a, b) works properly", t, func() {
res, _ := Run(context.Background(), "bcrypt.compare", "$2y$10$XPMT7nWucHJK113jjomfJ.xa64/jhH7sYrRJ9/0Q2CjzBTGwejUx.", "test")
So(res, ShouldEqual, true)
})
Convey("bcrypt.compare(a, b) errors properly", t, func() {
res, _ := Run(context.Background(), "bcrypt.compare", "$2y$10$XPMT7nWucHJK113jjomfJ.xa64/jhH7sYrRJ9/0Q2CjzBTGwejUx.", "wrong")
So(res, ShouldEqual, false)
})
Convey("bcrypt.generate(a) works properly", t, func() {
res, _ := Run(context.Background(), "bcrypt.generate", "test")
So(res, ShouldHaveSameTypeAs, []byte("test"))
})
}

49
util/fncs/count.go Normal file
View file

@ -0,0 +1,49 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
)
func count(ctx context.Context, args ...interface{}) (out float64, err error) {
arr, _ := ensureSlice(args[0])
for _, v := range arr {
if v != nil {
out++
}
}
return
}
func countIf(ctx context.Context, args ...interface{}) (out float64, err error) {
arr, _ := ensureSlice(args[0])
for _, v := range arr {
if v == args[1] {
out++
}
}
return
}
func countNot(ctx context.Context, args ...interface{}) (out float64, err error) {
arr, _ := ensureSlice(args[0])
for _, v := range arr {
if v != args[1] {
out++
}
}
return
}

57
util/fncs/count_test.go Normal file
View file

@ -0,0 +1,57 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestCount(t *testing.T) {
var res interface{}
var test = []interface{}{int(1), int(2), nil, float64(3.5), float64(4.5), float64(3.5)}
Convey("count() works properly", t, func() {
res, _ = Run(context.Background(), "count", "test")
So(res, ShouldEqual, 1)
res, _ = Run(context.Background(), "count", 10)
So(res, ShouldEqual, 1)
res, _ = Run(context.Background(), "count", test)
So(res, ShouldEqual, 5)
})
Convey("count.if() works properly", t, func() {
res, _ = Run(context.Background(), "count.if", "test", 3.5)
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "count.if", 10, 3.5)
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "count.if", test, 3.5)
So(res, ShouldEqual, 2)
})
Convey("count.not() works properly", t, func() {
res, _ = Run(context.Background(), "count.not", "test", 3.5)
So(res, ShouldEqual, 1)
res, _ = Run(context.Background(), "count.not", 10, 3.5)
So(res, ShouldEqual, 1)
res, _ = Run(context.Background(), "count.not", test, 3.5)
So(res, ShouldEqual, 4)
})
}

43
util/fncs/email.go Normal file
View file

@ -0,0 +1,43 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"strings"
"github.com/asaskevich/govalidator"
)
func emailUser(ctx context.Context, args ...interface{}) (string, error) {
v, _ := ensureString(args[0])
if p := strings.LastIndexByte(v, '@'); p > 0 {
return v[:p], nil
}
return "", nil
}
func emailDomain(ctx context.Context, args ...interface{}) (string, error) {
v, _ := ensureString(args[0])
if p := strings.LastIndexByte(v, '@'); p > 0 {
return v[p+1:], nil
}
return "", nil
}
func emailValid(ctx context.Context, args ...interface{}) (bool, error) {
v, _ := ensureString(args[0])
return govalidator.IsEmail(v), nil
}

60
util/fncs/email_test.go Normal file
View file

@ -0,0 +1,60 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestEmail(t *testing.T) {
Convey("email.user(a) works properly", t, func() {
res, _ := Run(context.Background(), "email.user", "tobie@abcum.com")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "tobie")
})
Convey("email.user(a) errors properly", t, func() {
res, _ := Run(context.Background(), "email.user", "test")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "")
})
Convey("email.domain(a) works properly", t, func() {
res, _ := Run(context.Background(), "email.domain", "tobie@abcum.com")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "abcum.com")
})
Convey("email.domain(a) errors properly", t, func() {
res, _ := Run(context.Background(), "email.domain", "test")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "")
})
Convey("email.valid(a) works properly", t, func() {
res, _ := Run(context.Background(), "email.valid", "tobie@abcum.com")
So(res, ShouldEqual, true)
})
Convey("email.valid(a) errors properly", t, func() {
res, _ := Run(context.Background(), "email.valid", "test")
So(res, ShouldEqual, false)
})
}

325
util/fncs/fnc.go Normal file
View file

@ -0,0 +1,325 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import "context"
func Run(ctx context.Context, name string, args ...interface{}) (interface{}, error) {
switch name {
case "batch":
return batch(ctx, args...)
case "difference":
return difference(ctx, args...)
case "distinct":
return distinct(ctx, args...)
case "get":
return get(ctx, args...)
case "if":
return ifel(ctx, args...)
case "intersect":
return intersect(ctx, args...)
case "model":
return model(ctx, args...)
case "table":
return table(ctx, args...)
case "thing":
return thing(ctx, args...)
case "union":
return union(ctx, args...)
// Count implementation
case "count":
return count(ctx, args...)
case "count.if":
return countIf(ctx, args...)
case "count.not":
return countNot(ctx, args...)
// Json implementation
case "json.decode":
return jsonDecode(ctx, args...)
case "json.encode":
return jsonEncode(ctx, args...)
// Geo implementation
case "geo.point":
return geoPoint(ctx, args...)
case "geo.circle":
return geoCircle(ctx, args...)
case "geo.polygon":
return geoPolygon(ctx, args...)
case "geo.distance":
return geoDistance(ctx, args...)
case "geo.inside":
return geoInside(ctx, args...)
case "geo.intersects":
return geoIntersects(ctx, args...)
case "geo.hash.decode":
return geoHashDecode(ctx, args...)
case "geo.hash.encode":
return geoHashEncode(ctx, args...)
// Http implementation
case "http.head":
return httpHead(ctx, args...)
case "http.get":
return httpGet(ctx, args...)
case "http.put":
return httpPut(ctx, args...)
case "http.post":
return httpPost(ctx, args...)
case "http.patch":
return httpPatch(ctx, args...)
case "http.delete":
return httpDelete(ctx, args...)
case "http.async.head":
return httpAsyncHead(ctx, args...)
case "http.async.get":
return httpAsyncGet(ctx, args...)
case "http.async.put":
return httpAsyncPut(ctx, args...)
case "http.async.post":
return httpAsyncPost(ctx, args...)
case "http.async.patch":
return httpAsyncPatch(ctx, args...)
case "http.async.delete":
return httpAsyncDelete(ctx, args...)
// Math implementation
case "math.abs", "abs":
return mathAbs(ctx, args...)
case "math.bottom", "bottom":
return mathBottom(ctx, args...)
case "math.ceil", "ceil":
return mathCeil(ctx, args...)
case "math.correlation", "correlation":
return mathCorrelation(ctx, args...)
case "math.covariance", "covariance":
return mathCovariance(ctx, args...)
case "math.floor", "floor":
return mathFloor(ctx, args...)
case "math.geometricmean", "geometricmean":
return mathGeometricmean(ctx, args...)
case "math.harmonicmean", "harmonicmean":
return mathHarmonicmean(ctx, args...)
case "math.interquartile", "interquartile":
return mathInterquartile(ctx, args...)
case "math.max", "max":
return mathMax(ctx, args...)
case "math.mean", "mean":
return mathMean(ctx, args...)
case "math.median", "median":
return mathMedian(ctx, args...)
case "math.midhinge", "midhinge":
return mathMidhinge(ctx, args...)
case "math.min", "min":
return mathMin(ctx, args...)
case "math.mode", "mode":
return mathMode(ctx, args...)
case "math.percentile", "percentile":
return mathPercentile(ctx, args...)
case "math.round", "round":
return mathRound(ctx, args...)
case "math.sample", "sample":
return mathSample(ctx, args...)
case "math.spread", "spread":
return mathSpread(ctx, args...)
case "math.stddev", "stddev":
return mathStddev(ctx, args...)
case "math.sum", "sum":
return mathSum(ctx, args...)
case "math.top", "top":
return mathTop(ctx, args...)
case "math.trimean", "trimean":
return mathTrimean(ctx, args...)
case "math.variance", "variance":
return mathVariance(ctx, args...)
// String implementation
case "string.concat":
return stringConcat(ctx, args...)
case "string.contains":
return stringContains(ctx, args...)
case "string.endsWith":
return stringEndsWith(ctx, args...)
case "string.format":
return stringFormat(ctx, args...)
case "string.includes":
return stringIncludes(ctx, args...)
case "string.join":
return stringJoin(ctx, args...)
case "string.length":
return stringLength(ctx, args...)
case "string.levenshtein":
return stringLevenshtein(ctx, args...)
case "string.lowercase":
return stringLowercase(ctx, args...)
case "string.repeat":
return stringRepeat(ctx, args...)
case "string.replace":
return stringReplace(ctx, args...)
case "string.reverse":
return stringReverse(ctx, args...)
case "string.search":
return stringSearch(ctx, args...)
case "string.slice":
return stringSlice(ctx, args...)
case "string.split":
return stringSplit(ctx, args...)
case "string.startsWith":
return stringStartsWith(ctx, args...)
case "string.substr":
return stringSubstr(ctx, args...)
case "string.trim":
return stringTrim(ctx, args...)
case "string.uppercase":
return stringUppercase(ctx, args...)
case "string.words":
return stringWords(ctx, args...)
// Hash implementation
case "hash.md5":
return hashMd5(ctx, args...)
case "hash.sha1":
return hashSha1(ctx, args...)
case "hash.sha256":
return hashSha256(ctx, args...)
case "hash.sha512":
return hashSha512(ctx, args...)
// Time implementation
case "time.now":
return timeNow(ctx, args...)
case "time.add":
return timeAdd(ctx, args...)
case "time.age":
return timeAge(ctx, args...)
case "time.floor":
return timeFloor(ctx, args...)
case "time.round":
return timeRound(ctx, args...)
case "time.day":
return timeDay(ctx, args...)
case "time.hour":
return timeHour(ctx, args...)
case "time.mins":
return timeMins(ctx, args...)
case "time.month":
return timeMonth(ctx, args...)
case "time.nano":
return timeNano(ctx, args...)
case "time.secs":
return timeSecs(ctx, args...)
case "time.unix":
return timeUnix(ctx, args...)
case "time.year":
return timeYear(ctx, args...)
// Email implementation
case "email.user":
return emailUser(ctx, args...)
case "email.domain":
return emailDomain(ctx, args...)
case "email.valid":
return emailValid(ctx, args...)
// Bcrypt implementation
case "bcrypt.compare":
return bcryptCompare(ctx, args...)
case "bcrypt.generate":
return bcryptGenerate(ctx, args...)
// Scrypt implementation
case "scrypt.compare":
return scryptCompare(ctx, args...)
case "scrypt.generate":
return scryptGenerate(ctx, args...)
// Rand implementation
case "rand":
return rand(ctx, args...)
case "uuid":
return randUuid(ctx, args...)
case "rand.bool":
return randBool(ctx, args...)
case "rand.uuid":
return randUuid(ctx, args...)
case "rand.enum":
return randEnum(ctx, args...)
case "rand.time":
return randTime(ctx, args...)
case "rand.string":
return randString(ctx, args...)
case "rand.integer":
return randInteger(ctx, args...)
case "rand.decimal":
return randDecimal(ctx, args...)
case "rand.word":
return randWord(ctx, args...)
case "rand.sentence":
return randSentence(ctx, args...)
case "rand.paragraph":
return randParagraph(ctx, args...)
case "rand.person.email":
return randPersonEmail(ctx, args...)
case "rand.person.phone":
return randPersonPhone(ctx, args...)
case "rand.person.fullname":
return randPersonFullname(ctx, args...)
case "rand.person.firstname":
return randPersonFirstname(ctx, args...)
case "rand.person.lastname":
return randPersonLastname(ctx, args...)
case "rand.person.username":
return randPersonUsername(ctx, args...)
case "rand.person.jobtitle":
return randPersonJobtitle(ctx, args...)
case "rand.company.name":
return randCompanyName(ctx, args...)
case "rand.company.industry":
return randCompanyIndustry(ctx, args...)
case "rand.location.name":
return randLocationName(ctx, args...)
case "rand.location.address":
return randLocationAddress(ctx, args...)
case "rand.location.street":
return randLocationStreet(ctx, args...)
case "rand.location.city":
return randLocationCity(ctx, args...)
case "rand.location.state":
return randLocationState(ctx, args...)
case "rand.location.county":
return randLocationCounty(ctx, args...)
case "rand.location.zipcode":
return randLocationZipcode(ctx, args...)
case "rand.location.postcode":
return randLocationPostcode(ctx, args...)
case "rand.location.country":
return randLocationCountry(ctx, args...)
case "rand.location.altitude":
return randLocationAltitude(ctx, args...)
case "rand.location.latitude":
return randLocationLatitude(ctx, args...)
case "rand.location.longitude":
return randLocationLongitude(ctx, args...)
default:
return nil, nil // Should never get here
}
}

32
util/fncs/fnc_test.go Normal file
View file

@ -0,0 +1,32 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestNil(t *testing.T) {
Convey("invalid.function() returns nil", t, func() {
res, _ := Run(context.Background(), "invalid.function")
So(res, ShouldHaveSameTypeAs, nil)
So(res, ShouldEqual, nil)
})
}

115
util/fncs/geo.go Normal file
View file

@ -0,0 +1,115 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/sql"
"github.com/abcum/surreal/util/geof"
)
func geoPoint(ctx context.Context, args ...interface{}) (*sql.Point, error) {
switch len(args) {
case 1:
if p, ok := ensurePoint(args[0]); ok {
return p, nil
}
if p := ensureFloats(args[0]); len(p) == 2 {
return sql.NewPoint(p[0], p[1]), nil
}
case 2:
if lat, ok := ensureFloat(args[0]); ok {
if lng, ok := ensureFloat(args[1]); ok {
return sql.NewPoint(lat, lng), nil
}
}
}
return nil, nil
}
func geoCircle(ctx context.Context, args ...interface{}) (*sql.Circle, error) {
if cen, ok := ensurePoint(args[0]); ok {
if rad, ok := ensureFloat(args[1]); ok {
return sql.NewCircle(cen, rad), nil
}
}
if val := ensureFloats(args[0]); len(val) == 2 {
cen, _ := geoPoint(ctx, val[0], val[1])
if rad, ok := ensureFloat(args[1]); ok {
return sql.NewCircle(cen, rad), nil
}
}
return nil, nil
}
func geoPolygon(ctx context.Context, args ...interface{}) (*sql.Polygon, error) {
switch len(args) {
case 0, 1, 2:
// Not enough arguments, so just ignore
default:
var pnts sql.Points
for _, a := range args {
if p, _ := geoPoint(ctx, a); p != nil {
pnts = append(pnts, p)
} else {
return nil, nil
}
}
return sql.NewPolygon(pnts...), nil
}
return nil, nil
}
func geoDistance(ctx context.Context, args ...interface{}) (float64, error) {
if pnt, ok := ensurePoint(args[0]); ok {
if frm, ok := ensurePoint(args[1]); ok {
return geof.Haversine(pnt, frm), nil
}
}
return -1, nil
}
func geoInside(ctx context.Context, args ...interface{}) (bool, error) {
if a, ok := ensureGeometry(args[0]); ok {
if b, ok := ensureGeometry(args[1]); ok {
return geof.Inside(a, b), nil
}
}
return false, nil
}
func geoIntersects(ctx context.Context, args ...interface{}) (bool, error) {
if a, ok := ensureGeometry(args[0]); ok {
if b, ok := ensureGeometry(args[1]); ok {
return geof.Intersects(a, b), nil
}
}
return false, nil
}
func geoHashDecode(ctx context.Context, args ...interface{}) (*sql.Point, error) {
s, _ := ensureString(args[0])
return geof.GeohashDecode(s), nil
}
func geoHashEncode(ctx context.Context, args ...interface{}) (string, error) {
if pnt, ok := ensurePoint(args[0]); ok {
if acc, ok := ensureInt(args[1]); ok {
return geof.GeohashEncode(pnt, acc), nil
}
}
return "", nil
}

90
util/fncs/geo_test.go Normal file
View file

@ -0,0 +1,90 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestGeo(t *testing.T) {
var res interface{}
Convey("geo.point(a, b) works properly", t, func() {
res, _ = Run(context.Background(), "geo.point", "test", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "geo.point", &sql.Point{38.898556, -77.037852})
So(res, ShouldResemble, &sql.Point{38.898556, -77.037852})
res, _ = Run(context.Background(), "geo.point", []interface{}{38.898556, -77.037852})
So(res, ShouldResemble, &sql.Point{38.898556, -77.037852})
res, _ = Run(context.Background(), "geo.point", 38.898556, -77.037852)
So(res, ShouldResemble, &sql.Point{38.898556, -77.037852})
})
Convey("geo.circle(a, b) works properly", t, func() {
res, _ = Run(context.Background(), "geo.circle", "test", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "geo.circle", &sql.Point{38.898556, -77.037852}, 100)
So(res, ShouldResemble, &sql.Circle{&sql.Point{38.898556, -77.037852}, 100})
res, _ = Run(context.Background(), "geo.circle", []interface{}{38.898556, -77.037852}, 100)
So(res, ShouldResemble, &sql.Circle{&sql.Point{38.898556, -77.037852}, 100})
})
Convey("geo.polygon(a, b) works properly", t, func() {
res, _ = Run(context.Background(), "geo.polygon", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "geo.polygon", "test", "test", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "geo.polygon", "test", &sql.Point{}, &sql.Point{}, &sql.Point{})
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "geo.polygon", &sql.Point{}, &sql.Point{}, &sql.Point{}, &sql.Point{})
So(res, ShouldResemble, &sql.Polygon{sql.Points{&sql.Point{}, &sql.Point{}, &sql.Point{}, &sql.Point{}}})
})
Convey("geo.distance(a, b, c, d) works properly", t, func() {
res, _ = Run(context.Background(), "geo.distance", &sql.Point{38.898556, -77.037852}, &sql.Point{38.897147, -77.043934})
So(res, ShouldEqual, 549.1557912048178)
})
Convey("geo.distance(a, b, c, d) errors properly", t, func() {
res, _ = Run(context.Background(), "geo.distance", &sql.Point{38.898556, -77.037852}, "null")
So(res, ShouldEqual, -1)
})
Convey("geo.hash.decode(a) works properly", t, func() {
res, _ = Run(context.Background(), "geo.hash.decode", "dqcjq")
So(res, ShouldResemble, &sql.Point{38.91357421875, -77.05810546875})
res, _ = Run(context.Background(), "geo.hash.decode", "dqcjqcq8x")
So(res, ShouldResemble, &sql.Point{38.9230709412368, -77.06750950572314})
})
Convey("geo.hash.encode(a, b, c) works properly", t, func() {
res, _ = Run(context.Background(), "geo.hash.encode", &sql.Point{38.898556, -77.037852}, 5)
So(res, ShouldEqual, "dqcjq")
res, _ = Run(context.Background(), "geo.hash.encode", &sql.Point{38.898556, -77.037852}, 9)
So(res, ShouldEqual, "dqcjqcq8x")
})
Convey("geo.hash.encode(a, b, c) errors properly", t, func() {
res, _ = Run(context.Background(), "geo.hash.encode", 0, 0, "null")
So(res, ShouldEqual, "")
})
}

33
util/fncs/get.go Normal file
View file

@ -0,0 +1,33 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/sql"
"github.com/abcum/surreal/util/data"
)
func get(ctx context.Context, args ...interface{}) (interface{}, error) {
doc := data.Consume(args[0])
switch fld := args[1].(type) {
case *sql.Value:
return doc.Get(fld.ID).Data(), nil
case string:
return doc.Get(fld).Data(), nil
}
return nil, nil
}

56
util/fncs/get_test.go Normal file
View file

@ -0,0 +1,56 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestGet(t *testing.T) {
var res interface{}
var doc = map[string]interface{}{
"object": map[string]interface{}{
"test": "ok",
},
"string": "test",
"bool": true,
"int": 13,
}
Convey("get(a, b) works properly", t, func() {
res, _ = Run(context.Background(), "get", doc, &sql.Value{"object.test"})
So(res, ShouldEqual, "ok")
res, _ = Run(context.Background(), "get", doc, "object.test")
So(res, ShouldEqual, "ok")
res, _ = Run(context.Background(), "get", doc, "string")
So(res, ShouldEqual, "test")
res, _ = Run(context.Background(), "get", doc, "bool")
So(res, ShouldEqual, true)
res, _ = Run(context.Background(), "get", doc, "int")
So(res, ShouldEqual, 13)
res, _ = Run(context.Background(), "get", doc, "err")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "get", doc, nil)
So(res, ShouldEqual, nil)
})
}

56
util/fncs/hash.go Normal file
View file

@ -0,0 +1,56 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
)
func hashMd5(ctx context.Context, args ...interface{}) (string, error) {
v, _ := ensureString(args[0])
h := md5.New()
h.Write([]byte(v))
s := h.Sum(nil)
return hex.EncodeToString(s), nil
}
func hashSha1(ctx context.Context, args ...interface{}) (string, error) {
v, _ := ensureString(args[0])
h := sha1.New()
h.Write([]byte(v))
s := h.Sum(nil)
return hex.EncodeToString(s), nil
}
func hashSha256(ctx context.Context, args ...interface{}) (string, error) {
v, _ := ensureString(args[0])
h := sha256.New()
h.Write([]byte(v))
s := h.Sum(nil)
return hex.EncodeToString(s), nil
}
func hashSha512(ctx context.Context, args ...interface{}) (string, error) {
v, _ := ensureString(args[0])
h := sha512.New()
h.Write([]byte(v))
s := h.Sum(nil)
return hex.EncodeToString(s), nil
}

50
util/fncs/hash_test.go Normal file
View file

@ -0,0 +1,50 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestHash(t *testing.T) {
Convey("hash.md5(a) works properly", t, func() {
res, _ := Run(context.Background(), "hash.md5", "test")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "098f6bcd4621d373cade4e832627b4f6")
})
Convey("hash.sha1(a) works properly", t, func() {
res, _ := Run(context.Background(), "hash.sha1", "test")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3")
})
Convey("hash.sha256(a) works properly", t, func() {
res, _ := Run(context.Background(), "hash.sha256", "test")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08")
})
Convey("hash.sha512(a) works properly", t, func() {
res, _ := Run(context.Background(), "hash.sha512", "test")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldEqual, "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff")
})
}

210
util/fncs/http.go Normal file
View file

@ -0,0 +1,210 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"bytes"
"context"
"errors"
"io"
"io/ioutil"
"net/http"
"time"
"encoding/json"
"golang.org/x/net/context/ctxhttp"
"github.com/abcum/surreal/util/build"
"github.com/abcum/surreal/util/hook"
)
type opts map[string]interface{}
var version = build.GetInfo().Ver
var httpResponseError = errors.New("HTTP response error")
func httpHead(ctx context.Context, args ...interface{}) (interface{}, error) {
return runSync(ctx, "HEAD", args...)
}
func httpGet(ctx context.Context, args ...interface{}) (interface{}, error) {
return runSync(ctx, "GET", args...)
}
func httpPut(ctx context.Context, args ...interface{}) (interface{}, error) {
return runSync(ctx, "PUT", args...)
}
func httpPost(ctx context.Context, args ...interface{}) (interface{}, error) {
return runSync(ctx, "POST", args...)
}
func httpPatch(ctx context.Context, args ...interface{}) (interface{}, error) {
return runSync(ctx, "PATCH", args...)
}
func httpDelete(ctx context.Context, args ...interface{}) (interface{}, error) {
return runSync(ctx, "DELETE", args...)
}
func httpAsyncHead(ctx context.Context, args ...interface{}) (interface{}, error) {
return runAsync(ctx, "HEAD", args...)
}
func httpAsyncGet(ctx context.Context, args ...interface{}) (interface{}, error) {
return runAsync(ctx, "GET", args...)
}
func httpAsyncPut(ctx context.Context, args ...interface{}) (interface{}, error) {
return runAsync(ctx, "PUT", args...)
}
func httpAsyncPost(ctx context.Context, args ...interface{}) (interface{}, error) {
return runAsync(ctx, "POST", args...)
}
func httpAsyncPatch(ctx context.Context, args ...interface{}) (interface{}, error) {
return runAsync(ctx, "PATCH", args...)
}
func httpAsyncDelete(ctx context.Context, args ...interface{}) (interface{}, error) {
return runAsync(ctx, "DELETE", args...)
}
func runSync(ctx context.Context, met string, args ...interface{}) (interface{}, error) {
url, bdy, opt := httpCnf(met, args...)
out, _ := httpRes(ctx, met, url, bdy, opt)
return out, nil
}
func runAsync(ctx context.Context, met string, args ...interface{}) (interface{}, error) {
url, bdy, opt := httpCnf(met, args...)
ctx = context.Background()
go hook.NewBackoff(5, 5, 10*time.Second).Run(ctx, func() error {
return httpErr(httpReq(ctx, met, url, bdy, opt))
})
return nil, nil
}
func httpCnf(met string, args ...interface{}) (url string, bdy io.Reader, opt opts) {
var bit []byte
switch met {
case "HEAD", "GET", "DELETE":
switch len(args) {
case 1:
url, _ = ensureString(args[0])
case 2:
url, _ = ensureString(args[0])
opt, _ = ensureObject(args[1])
}
case "PUT", "POST", "PATCH":
switch len(args) {
case 1:
url, _ = ensureString(args[0])
case 2:
url, _ = ensureString(args[0])
switch v := args[1].(type) {
case []interface{}, map[string]interface{}:
bit, _ = json.Marshal(v)
default:
bit, _ = ensureBytes(v)
}
case 3:
url, _ = ensureString(args[0])
switch v := args[1].(type) {
case []interface{}, map[string]interface{}:
bit, _ = json.Marshal(v)
default:
bit, _ = ensureBytes(v)
}
opt, _ = ensureObject(args[2])
}
}
return url, bytes.NewReader(bit), opt
}
func httpReq(ctx context.Context, met, url string, body io.Reader, conf opts) (*http.Response, error) {
cli := new(http.Client)
req, err := http.NewRequest(met, url, body)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "SurrealDB HTTP/"+version)
if val, ok := conf["auth"]; ok {
if opt, ok := ensureObject(val); ok {
user, _ := ensureString(opt["user"])
pass, _ := ensureString(opt["pass"])
req.SetBasicAuth(user, pass)
}
}
if val, ok := conf["head"]; ok {
if opt, ok := ensureObject(val); ok {
for key, v := range opt {
head, _ := ensureString(v)
req.Header.Set(key, head)
}
}
}
res, err := ctxhttp.Do(ctx, cli, req)
if err != nil {
return nil, err
}
return res, nil
}
func httpRes(ctx context.Context, met, url string, body io.Reader, conf opts) (interface{}, error) {
var out interface{}
res, err := httpReq(ctx, met, url, body, conf)
if err != nil {
return nil, err
}
bdy, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
err = json.Unmarshal(bdy, &out)
if err != nil {
if len(bdy) != 0 {
return bdy, nil
}
}
return out, nil
}
func httpErr(res *http.Response, err error) error {
if err != nil {
return err
}
if res.StatusCode >= 500 {
return httpResponseError
}
return nil
}

158
util/fncs/http_test.go Normal file
View file

@ -0,0 +1,158 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"fmt"
"io"
"net/http"
"net/http/httptest"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestHttp(t *testing.T) {
var res interface{}
var jsn = `{"test":true, "temp":"text"}`
var obj = map[string]interface{}{"temp": "text", "test": true}
var txt = `<!doctype html><html><head></head><body></body></html>`
var opt = map[string]interface{}{
"auth": map[string]interface{}{"user": "u", "pass": "p"},
"head": map[string]interface{}{"x-test": true},
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "HEAD", "DELETE":
// Return nothing
case "GET":
fmt.Fprint(w, txt)
case "PUT", "POST", "PATCH":
io.Copy(w, r.Body)
}
}))
defer srv.Close()
Convey("http.head(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.head", srv.URL)
So(res, ShouldResemble, nil)
})
Convey("http.get(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.get", srv.URL)
So(res, ShouldResemble, []byte(txt))
res, _ = Run(context.Background(), "http.get", srv.URL, opt)
So(res, ShouldResemble, []byte(txt))
})
Convey("http.put(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.put", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.put", srv.URL, txt)
So(res, ShouldResemble, []byte(txt))
res, _ = Run(context.Background(), "http.put", srv.URL, jsn)
So(res, ShouldResemble, obj)
res, _ = Run(context.Background(), "http.put", srv.URL, jsn, opt)
So(res, ShouldResemble, obj)
})
Convey("http.post(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.post", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.post", srv.URL, txt)
So(res, ShouldResemble, []byte(txt))
res, _ = Run(context.Background(), "http.post", srv.URL, jsn)
So(res, ShouldResemble, obj)
res, _ = Run(context.Background(), "http.post", srv.URL, jsn, opt)
So(res, ShouldResemble, obj)
})
Convey("http.patch(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.patch", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.patch", srv.URL, txt)
So(res, ShouldResemble, []byte(txt))
res, _ = Run(context.Background(), "http.patch", srv.URL, jsn)
So(res, ShouldResemble, obj)
res, _ = Run(context.Background(), "http.patch", srv.URL, jsn, opt)
So(res, ShouldResemble, obj)
})
Convey("http.delete(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.delete", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.delete", srv.URL, opt)
So(res, ShouldResemble, nil)
})
Convey("http.async.head(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.async.head", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.head", srv.URL, opt)
So(res, ShouldResemble, nil)
})
Convey("http.async.get(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.async.get", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.get", srv.URL, opt)
So(res, ShouldResemble, nil)
})
Convey("http.async.put(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.async.put", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.put", srv.URL, txt)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.put", srv.URL, jsn)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.put", srv.URL, jsn, opt)
So(res, ShouldResemble, nil)
})
Convey("http.async.post(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.async.post", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.post", srv.URL, txt)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.post", srv.URL, jsn)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.post", srv.URL, jsn, opt)
So(res, ShouldResemble, nil)
})
Convey("http.async.patch(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.async.patch", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.patch", srv.URL, txt)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.patch", srv.URL, jsn)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.patch", srv.URL, jsn, opt)
So(res, ShouldResemble, nil)
})
Convey("http.async.delete(a) works properly", t, func() {
res, _ = Run(context.Background(), "http.async.delete", srv.URL)
So(res, ShouldResemble, nil)
res, _ = Run(context.Background(), "http.async.delete", srv.URL, opt)
So(res, ShouldResemble, nil)
})
}

26
util/fncs/if.go Normal file
View file

@ -0,0 +1,26 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
)
func ifel(ctx context.Context, args ...interface{}) (interface{}, error) {
if val, ok := ensureBool(args[0]); ok && val {
return args[1], nil
}
return args[2], nil
}

41
util/fncs/if_test.go Normal file
View file

@ -0,0 +1,41 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestIf(t *testing.T) {
var res interface{}
Convey("if(a, b, c) works properly", t, func() {
res, _ = Run(context.Background(), "if", true, "yes", "no")
So(res, ShouldEqual, "yes")
res, _ = Run(context.Background(), "if", "true", "yes", "no")
So(res, ShouldEqual, "yes")
res, _ = Run(context.Background(), "if", false, "yes", "no")
So(res, ShouldEqual, "no")
res, _ = Run(context.Background(), "if", "false", "yes", "no")
So(res, ShouldEqual, "no")
res, _ = Run(context.Background(), "if", "something", "yes", "no")
So(res, ShouldEqual, "no")
})
}

32
util/fncs/json.go Normal file
View file

@ -0,0 +1,32 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"encoding/json"
)
func jsonDecode(ctx context.Context, args ...interface{}) (out interface{}, err error) {
bit, _ := ensureBytes(args[0])
json.Unmarshal(bit, &out)
return
}
func jsonEncode(ctx context.Context, args ...interface{}) (interface{}, error) {
bit, _ := json.Marshal(args[0])
return bit, nil
}

48
util/fncs/json_test.go Normal file
View file

@ -0,0 +1,48 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestJson(t *testing.T) {
var res interface{}
Convey("json.decode(a) works properly", t, func() {
res, _ = Run(context.Background(), "json.decode", "true")
So(res, ShouldResemble, true)
res, _ = Run(context.Background(), "json.decode", "13579")
So(res, ShouldResemble, float64(13579))
res, _ = Run(context.Background(), "json.decode", `{"test":true}`)
So(res, ShouldResemble, map[string]interface{}{
"test": true,
})
})
Convey("json.encode(a) works properly", t, func() {
res, _ = Run(context.Background(), "json.encode", true)
So(res, ShouldResemble, []byte("true"))
res, _ = Run(context.Background(), "json.encode", 13579)
So(res, ShouldResemble, []byte("13579"))
res, _ = Run(context.Background(), "json.encode", map[string]interface{}{"test": true})
So(res, ShouldResemble, []byte(`{"test":true}`))
})
}

163
util/fncs/math.go Normal file
View file

@ -0,0 +1,163 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/util/math"
)
func mathAbs(ctx context.Context, args ...interface{}) (out interface{}, err error) {
if val, ok := ensureFloat(args[0]); ok {
return outputFloat(math.Abs(val))
}
return
}
func mathBottom(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
if take, ok := ensureInt(args[1]); ok {
return math.Bottom(vals, int(take)), nil
}
return
}
func mathCeil(ctx context.Context, args ...interface{}) (out interface{}, err error) {
if val, ok := ensureFloat(args[0]); ok {
return outputFloat(math.Ceil(val))
}
return
}
func mathCorrelation(ctx context.Context, args ...interface{}) (out interface{}, err error) {
a := ensureFloats(args[0])
b := ensureFloats(args[1])
return outputFloat(math.Correlation(a, b))
}
func mathCovariance(ctx context.Context, args ...interface{}) (out interface{}, err error) {
a := ensureFloats(args[0])
b := ensureFloats(args[1])
return outputFloat(math.Covariance(a, b))
}
func mathFloor(ctx context.Context, args ...interface{}) (out interface{}, err error) {
if val, ok := ensureFloat(args[0]); ok {
return outputFloat(math.Floor(val))
}
return
}
func mathGeometricmean(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.GeometricMean(vals))
}
func mathHarmonicmean(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.HarmonicMean(vals))
}
func mathInterquartile(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.InterQuartileRange(vals))
}
func mathMax(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Max(vals))
}
func mathMean(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Mean(vals))
}
func mathMedian(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Median(vals))
}
func mathMidhinge(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Midhinge(vals))
}
func mathMin(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Min(vals))
}
func mathMode(ctx context.Context, args ...interface{}) (out []float64, err error) {
vals := ensureFloats(args[0])
return math.Mode(vals), nil
}
func mathPercentile(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
if perc, ok := ensureFloat(args[1]); ok {
return outputFloat(math.Percentile(vals, perc))
}
return
}
func mathRound(ctx context.Context, args ...interface{}) (out interface{}, err error) {
if val, ok := ensureFloat(args[0]); ok {
return outputFloat(math.Round(val))
}
return
}
func mathSample(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
if take, ok := ensureInt(args[1]); ok {
return math.Sample(vals, int(take)), nil
}
return
}
func mathSpread(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Spread(vals))
}
func mathStddev(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.PopulationStandardDeviation(vals))
}
func mathSum(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Sum(vals))
}
func mathTop(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
if take, ok := ensureInt(args[1]); ok {
return math.Top(vals, int(take)), nil
}
return
}
func mathTrimean(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.Trimean(vals))
}
func mathVariance(ctx context.Context, args ...interface{}) (out interface{}, err error) {
vals := ensureFloats(args[0])
return outputFloat(math.PopulationVariance(vals))
}

264
util/fncs/math_test.go Normal file
View file

@ -0,0 +1,264 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestMath(t *testing.T) {
var res interface{}
var test = []interface{}{int(1), int64(3), float32(4.5), float64(3.5)}
var testA = []interface{}{int(1), int64(3), float32(4.5), float64(3.5)}
var testB = []interface{}{int(5), int64(9), float32(2.5), float64(6.5)}
var testC = []interface{}{int(5), int64(5), float32(2.5), float64(6.5)}
Convey("math.abs() works properly", t, func() {
res, _ = Run(context.Background(), "math.abs", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.abs", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.abs", -1.5)
So(res, ShouldEqual, 1.5)
})
Convey("math.bottom() works properly", t, func() {
res, _ = Run(context.Background(), "math.bottom", "test", 2)
So(res, ShouldHaveLength, 0)
res, _ = Run(context.Background(), "math.bottom", testC, "oops")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.bottom", testC, 2)
So(res, ShouldHaveSameTypeAs, []float64{})
So(res, ShouldContain, 2.5)
So(res, ShouldContain, 5.0)
res, _ = Run(context.Background(), "math.bottom", 13, 2)
So(res, ShouldHaveSameTypeAs, []float64{})
So(res, ShouldContain, 13.0)
})
Convey("math.ceil() works properly", t, func() {
res, _ = Run(context.Background(), "math.ceil", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.ceil", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.ceil", 1.5)
So(res, ShouldEqual, 2)
})
Convey("math.correlation() works properly", t, func() {
res, _ = Run(context.Background(), "math.correlation", "test", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.correlation", 1234, 1234)
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "math.correlation", testA, testB)
So(res, ShouldEqual, -0.24945922497781908)
})
Convey("math.covariance() works properly", t, func() {
res, _ = Run(context.Background(), "math.covariance", "test", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.covariance", 1234, 1234)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.covariance", testA, testB)
So(res, ShouldEqual, -1)
})
Convey("math.floor() works properly", t, func() {
res, _ = Run(context.Background(), "math.floor", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.floor", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.floor", 1.5)
So(res, ShouldEqual, 1)
})
Convey("math.geometricmean() works properly", t, func() {
res, _ = Run(context.Background(), "math.geometricmean", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.geometricmean", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.geometricmean", test)
So(res, ShouldEqual, 2.621805397514041)
})
Convey("math.harmonicmean() works properly", t, func() {
res, _ = Run(context.Background(), "math.harmonicmean", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.harmonicmean", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.harmonicmean", test)
So(res, ShouldEqual, 2.172413793103449)
})
Convey("math.interquartile() works properly", t, func() {
res, _ = Run(context.Background(), "math.interquartile", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.interquartile", 10)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.interquartile", test)
So(res, ShouldEqual, 2)
})
Convey("math.max() works properly", t, func() {
res, _ = Run(context.Background(), "math.max", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.max", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.max", test)
So(res, ShouldEqual, 4.5)
})
Convey("math.mean() works properly", t, func() {
res, _ = Run(context.Background(), "math.mean", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.mean", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.mean", testA, testB)
So(res, ShouldEqual, 3)
})
Convey("math.median() works properly", t, func() {
res, _ = Run(context.Background(), "math.median", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.median", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.median", testA, testB)
So(res, ShouldEqual, 3.25)
})
Convey("math.midhinge() works properly", t, func() {
res, _ = Run(context.Background(), "math.midhinge", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.midhinge", 10)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.midhinge", test)
So(res, ShouldEqual, 3)
})
Convey("math.min() works properly", t, func() {
res, _ = Run(context.Background(), "math.min", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.min", 10)
So(res, ShouldEqual, 10)
res, _ = Run(context.Background(), "math.min", test)
So(res, ShouldEqual, 1)
})
Convey("math.mode() works properly", t, func() {
res, _ = Run(context.Background(), "math.mode", "test")
So(res, ShouldHaveLength, 0)
res, _ = Run(context.Background(), "math.mode", testC)
So(res, ShouldResemble, []float64{5})
res, _ = Run(context.Background(), "math.mode", 1)
So(res, ShouldResemble, []float64{1})
})
Convey("math.percentile() works properly", t, func() {
res, _ = Run(context.Background(), "math.percentile", "test", 90)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.percentile", 10, "oops")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.percentile", 10, 90)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.percentile", test, 90)
So(res, ShouldEqual, 4)
})
Convey("math.round() works properly", t, func() {
res, _ = Run(context.Background(), "math.round", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.round", 1.4)
So(res, ShouldEqual, 1)
res, _ = Run(context.Background(), "math.round", 1.5)
So(res, ShouldEqual, 2)
})
Convey("math.sample() works properly", t, func() {
res, _ = Run(context.Background(), "math.sample", "test", 3)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.sample", 10, "oops")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.sample", 10, 3)
So(res, ShouldResemble, []float64{10})
res, _ = Run(context.Background(), "math.sample", test, 3)
So(res, ShouldHaveLength, 3)
})
Convey("math.spread() works properly", t, func() {
res, _ = Run(context.Background(), "math.spread", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.spread", 10)
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "math.spread", test)
So(res, ShouldEqual, 4.5)
})
Convey("math.stddev() works properly", t, func() {
res, _ = Run(context.Background(), "math.stddev", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.stddev", 10)
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "math.stddev", test)
So(res, ShouldEqual, 1.2747548783981961)
})
Convey("math.sum() works properly", t, func() {
res, _ = Run(context.Background(), "math.sum", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.sum", 1234)
So(res, ShouldEqual, 1234)
res, _ = Run(context.Background(), "math.sum", []interface{}{int(1), int64(3), float32(4.5), float64(3.5)})
So(res, ShouldEqual, 12)
})
Convey("math.top() works properly", t, func() {
res, _ = Run(context.Background(), "math.top", "test", 2)
So(res, ShouldHaveSameTypeAs, []float64{})
So(res, ShouldHaveLength, 0)
res, _ = Run(context.Background(), "math.top", testC, "oops")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.top", testC, 2)
So(res, ShouldHaveSameTypeAs, []float64{})
So(res, ShouldContain, 6.5)
So(res, ShouldContain, 5.0)
res, _ = Run(context.Background(), "math.top", 13, 2)
So(res, ShouldHaveSameTypeAs, []float64{})
So(res, ShouldContain, 13.0)
})
Convey("math.trimean() works properly", t, func() {
res, _ = Run(context.Background(), "math.trimean", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.trimean", 10)
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.trimean", test)
So(res, ShouldEqual, 3.125)
})
Convey("math.variance() works properly", t, func() {
res, _ = Run(context.Background(), "math.variance", "test")
So(res, ShouldEqual, nil)
res, _ = Run(context.Background(), "math.variance", 10)
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "math.variance", test)
So(res, ShouldEqual, 1.625)
})
}

46
util/fncs/model.go Normal file
View file

@ -0,0 +1,46 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/sql"
)
func model(ctx context.Context, args ...interface{}) (*sql.Model, error) {
tb, _ := ensureString(args[0])
switch len(args) {
case 2:
if max, ok := ensureFloat(args[1]); ok {
return sql.NewModel(tb, 0, 0, max), nil
}
case 3:
if min, ok := ensureFloat(args[1]); ok {
if max, ok := ensureFloat(args[2]); ok {
return sql.NewModel(tb, min, 1, max), nil
}
}
case 4:
if min, ok := ensureFloat(args[1]); ok {
if inc, ok := ensureFloat(args[2]); ok {
if max, ok := ensureFloat(args[3]); ok {
return sql.NewModel(tb, min, inc, max), nil
}
}
}
}
return nil, nil
}

55
util/fncs/model_test.go Normal file
View file

@ -0,0 +1,55 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestModel(t *testing.T) {
var res interface{}
Convey("model(a) errors properly", t, func() {
res, _ = Run(context.Background(), "model", "test")
So(res, ShouldBeNil)
})
Convey("model(a, b) works properly", t, func() {
res, _ = Run(context.Background(), "model", 1, 10)
So(res, ShouldResemble, sql.NewModel("1", 0, 0, 10))
res, _ = Run(context.Background(), "model", "test", 10)
So(res, ShouldResemble, sql.NewModel("test", 0, 0, 10))
})
Convey("model(a, b, c) works properly", t, func() {
res, _ = Run(context.Background(), "model", 1, 10, 20)
So(res, ShouldResemble, sql.NewModel("1", 10, 1, 20))
res, _ = Run(context.Background(), "model", "test", 10, 20)
So(res, ShouldResemble, sql.NewModel("test", 10, 1, 20))
})
Convey("model(a, b, c, d) works properly", t, func() {
res, _ = Run(context.Background(), "model", 1, 10, 0.5, 20)
So(res, ShouldResemble, sql.NewModel("1", 10, 0.5, 20))
res, _ = Run(context.Background(), "model", "test", 10, 0.5, 20)
So(res, ShouldResemble, sql.NewModel("test", 10, 0.5, 20))
})
}

207
util/fncs/rand.go Normal file
View file

@ -0,0 +1,207 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"time"
"github.com/abcum/surreal/util/fake"
)
func rand(ctx context.Context, args ...interface{}) (float64, error) {
return fake.DecimalBetween(0, 1), nil
}
func randBool(ctx context.Context, args ...interface{}) (bool, error) {
return fake.Bool(), nil
}
func randUuid(ctx context.Context, args ...interface{}) (string, error) {
return fake.Uuid(), nil
}
func randEnum(ctx context.Context, args ...interface{}) (interface{}, error) {
switch len(args) {
case 0:
return nil, nil
default:
return args[fake.IntegerBetween(0, len(args))], nil
}
}
func randTime(ctx context.Context, args ...interface{}) (time.Time, error) {
switch len(args) {
case 2:
if b, ok := ensureTime(args[0]); ok {
if e, ok := ensureTime(args[1]); ok {
return fake.TimeBetween(b, e), nil
}
}
}
return fake.Time(), nil
}
func randString(ctx context.Context, args ...interface{}) (string, error) {
switch len(args) {
case 1:
if l, ok := ensureInt(args[0]); ok {
return fake.StringLength(int(l)), nil
}
case 2:
if b, ok := ensureInt(args[0]); ok {
if e, ok := ensureInt(args[1]); ok {
return fake.StringBetween(int(b), int(e)), nil
}
}
}
return fake.String(), nil
}
func randInteger(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 2:
if b, ok := ensureInt(args[0]); ok {
if e, ok := ensureInt(args[1]); ok {
return float64(fake.IntegerBetween(int(b), int(e))), nil
}
}
}
return float64(fake.Integer()), nil
}
func randDecimal(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 2:
if b, ok := ensureFloat(args[0]); ok {
if e, ok := ensureFloat(args[1]); ok {
return fake.DecimalBetween(b, e), nil
}
}
}
return fake.Decimal(), nil
}
func randWord(ctx context.Context, args ...interface{}) (string, error) {
return fake.Word(), nil
}
func randSentence(ctx context.Context, args ...interface{}) (string, error) {
switch len(args) {
case 2:
if b, ok := ensureInt(args[0]); ok {
if e, ok := ensureInt(args[1]); ok {
return fake.SentenceBetween(int(b), int(e)), nil
}
}
}
return fake.Sentence(), nil
}
func randParagraph(ctx context.Context, args ...interface{}) (string, error) {
switch len(args) {
case 2:
if b, ok := ensureInt(args[0]); ok {
if e, ok := ensureInt(args[1]); ok {
return fake.ParagraphBetween(int(b), int(e)), nil
}
}
}
return fake.Paragraph(), nil
}
func randPersonEmail(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonEmail(), nil
}
func randPersonPhone(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonPhone(), nil
}
func randPersonFullname(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonFullname(), nil
}
func randPersonFirstname(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonFirstname(), nil
}
func randPersonLastname(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonLastname(), nil
}
func randPersonUsername(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonUsername(), nil
}
func randPersonJobtitle(ctx context.Context, args ...interface{}) (string, error) {
return fake.PersonJobtitle(), nil
}
func randCompanyName(ctx context.Context, args ...interface{}) (string, error) {
return fake.CompanyName(), nil
}
func randCompanyIndustry(ctx context.Context, args ...interface{}) (string, error) {
return fake.CompanyIndustry(), nil
}
func randLocationName(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationName(), nil
}
func randLocationAddress(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationAddress(), nil
}
func randLocationStreet(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationStreet(), nil
}
func randLocationCity(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationCity(), nil
}
func randLocationState(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationState(), nil
}
func randLocationCounty(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationCounty(), nil
}
func randLocationZipcode(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationZipcode(), nil
}
func randLocationPostcode(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationPostcode(), nil
}
func randLocationCountry(ctx context.Context, args ...interface{}) (string, error) {
return fake.LocationCountry(), nil
}
func randLocationAltitude(ctx context.Context, args ...interface{}) (float64, error) {
return fake.LocationAltitude(), nil
}
func randLocationLatitude(ctx context.Context, args ...interface{}) (float64, error) {
return fake.LocationLatitude(), nil
}
func randLocationLongitude(ctx context.Context, args ...interface{}) (float64, error) {
return fake.LocationLongitude(), nil
}

243
util/fncs/rand_test.go Normal file
View file

@ -0,0 +1,243 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestRand(t *testing.T) {
Convey("rand() works properly", t, func() {
res, _ := Run(context.Background(), "rand")
So(res, ShouldHaveSameTypeAs, 36.0)
})
Convey("uuid() works properly", t, func() {
res, _ := Run(context.Background(), "uuid")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldHaveLength, 36)
})
Convey("rand.bool() works properly", t, func() {
res, _ := Run(context.Background(), "rand.bool")
So(res, ShouldHaveSameTypeAs, true)
})
Convey("rand.uuid() works properly", t, func() {
res, _ := Run(context.Background(), "rand.uuid")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldHaveLength, 36)
})
Convey("rand.enum() works properly", t, func() {
res, _ := Run(context.Background(), "rand.enum")
So(res, ShouldHaveSameTypeAs, nil)
})
Convey("rand.enum(a,b,c) works properly", t, func() {
res, _ := Run(context.Background(), "rand.enum", "one", "two", "tre")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldBeIn, []interface{}{"one", "two", "tre"})
})
Convey("rand.time() works properly", t, func() {
res, _ := Run(context.Background(), "rand.time")
So(res, ShouldHaveSameTypeAs, time.Now())
})
Convey("rand.time(a,b) works properly", t, func() {
d, _ := time.ParseDuration("24h")
now := time.Now()
res, _ := Run(context.Background(), "rand.time", now, now.Add(d))
So(res, ShouldHaveSameTypeAs, time.Now())
So(res.(time.Time).UnixNano(), ShouldBeBetween, now.UnixNano(), now.Add(d).UnixNano())
})
Convey("rand.string() works properly", t, func() {
res, _ := Run(context.Background(), "rand.string")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.string(a) works properly", t, func() {
res, _ := Run(context.Background(), "rand.string", int64(12))
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldHaveLength, 12)
})
Convey("rand.string(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "rand.string", int64(12), int64(16))
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.integer() works properly", t, func() {
res, _ := Run(context.Background(), "rand.integer")
So(res, ShouldHaveSameTypeAs, float64(0))
})
Convey("rand.integer(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "rand.integer", int64(12), int64(16))
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldBeBetween, 11, 17)
})
Convey("rand.decimal() works properly", t, func() {
res, _ := Run(context.Background(), "rand.decimal")
So(res, ShouldHaveSameTypeAs, float64(0))
})
Convey("rand.decimal(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "rand.decimal", int64(12), int64(16))
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldBeBetween, 11, 17)
})
Convey("rand.word() works properly", t, func() {
res, _ := Run(context.Background(), "rand.word")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.sentence() works properly", t, func() {
res, _ := Run(context.Background(), "rand.sentence")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.sentence(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "rand.sentence", int64(12), int64(16))
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.paragraph() works properly", t, func() {
res, _ := Run(context.Background(), "rand.paragraph")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.paragraph(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "rand.paragraph", int64(12), int64(16))
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.person.email works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.email")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldContainSubstring, "@")
})
Convey("rand.person.phone works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.phone")
So(res, ShouldHaveSameTypeAs, "test")
So(res, ShouldContainSubstring, " ")
})
Convey("rand.person.fullname works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.fullname")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.person.firstname works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.firstname")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.person.lastname works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.lastname")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.person.username works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.username")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.person.jobtitle works properly", t, func() {
res, _ := Run(context.Background(), "rand.person.jobtitle")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.company.name works properly", t, func() {
res, _ := Run(context.Background(), "rand.company.name")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.company.industry works properly", t, func() {
res, _ := Run(context.Background(), "rand.company.industry")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.name works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.name")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.address works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.address")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.street works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.street")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.city works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.city")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.state works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.state")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.county works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.county")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.zipcode works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.zipcode")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.postcode works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.postcode")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.country works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.country")
So(res, ShouldHaveSameTypeAs, "test")
})
Convey("rand.location.altitude works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.altitude")
So(res, ShouldHaveSameTypeAs, float64(0))
})
Convey("rand.location.latitude works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.latitude")
So(res, ShouldHaveSameTypeAs, float64(0))
})
Convey("rand.location.longitude works properly", t, func() {
res, _ := Run(context.Background(), "rand.location.longitude")
So(res, ShouldHaveSameTypeAs, float64(0))
})
}

40
util/fncs/scrypt.go Normal file
View file

@ -0,0 +1,40 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/elithrar/simple-scrypt"
)
func scryptCompare(ctx context.Context, args ...interface{}) (bool, error) {
if h, ok := ensureString(args[0]); ok {
if s, ok := ensureString(args[1]); ok {
e := scrypt.CompareHashAndPassword([]byte(h), []byte(s))
if e == nil {
return true, nil
}
}
}
return false, nil
}
func scryptGenerate(ctx context.Context, args ...interface{}) ([]byte, error) {
s, _ := ensureString(args[0])
p := []byte(s)
o := scrypt.DefaultParams
return scrypt.GenerateFromPassword(p, o)
}

41
util/fncs/scrypt_test.go Normal file
View file

@ -0,0 +1,41 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestScrypt(t *testing.T) {
Convey("scrypt.compare(a, b) works properly", t, func() {
res, _ := Run(context.Background(), "scrypt.compare", "16384$8$1$8065a3ec98903c86d950840721ef945b$1f23d0d2ff5528f033161fd21ce84911f9332ac9878953139ad30b6a8c2959f2", "test")
So(res, ShouldEqual, true)
})
Convey("scrypt.compare(a, b) errors properly", t, func() {
res, _ := Run(context.Background(), "scrypt.compare", "16384$8$1$8065a3ec98903c86d950840721ef945b$1f23d0d2ff5528f033161fd21ce84911f9332ac9878953139ad30b6a8c2959f2", "wrong")
So(res, ShouldEqual, false)
})
Convey("scrypt.generate(a) works properly", t, func() {
res, _ := Run(context.Background(), "scrypt.generate", "test")
So(res, ShouldHaveSameTypeAs, []byte("test"))
})
}

104
util/fncs/sets.go Normal file
View file

@ -0,0 +1,104 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
)
func difference(ctx context.Context, args ...interface{}) ([]interface{}, error) {
d := make([]interface{}, 0)
c := make(map[interface{}]int)
for _, x := range args {
a, _ := ensureSlice(x)
for _, v := range a {
c[v] += 1
}
}
for k, b := range c {
if b == 1 {
d = append(d, k)
}
}
return d, nil
}
func distinct(ctx context.Context, args ...interface{}) (interface{}, error) {
d := make([]interface{}, 0)
c := make(map[interface{}]bool)
for _, x := range args {
a, _ := ensureSlice(x)
for _, v := range a {
c[v] = true
}
}
for k := range c {
d = append(d, k)
}
return d, nil
}
func intersect(ctx context.Context, args ...interface{}) ([]interface{}, error) {
l := len(args)
d := make([]interface{}, 0)
c := make(map[interface{}]int)
for _, x := range args {
a, _ := ensureSlice(x)
for _, v := range a {
c[v] += 1
}
}
for k, b := range c {
if b == l {
d = append(d, k)
}
}
return d, nil
}
func union(ctx context.Context, args ...interface{}) ([]interface{}, error) {
d := make([]interface{}, 0)
c := make(map[interface{}]bool)
for _, x := range args {
a, _ := ensureSlice(x)
for _, v := range a {
c[v] = true
}
}
for k := range c {
d = append(d, k)
}
return d, nil
}

62
util/fncs/sets_test.go Normal file
View file

@ -0,0 +1,62 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestSets(t *testing.T) {
Convey("difference(a, b, c) works properly", t, func() {
res, _ := Run(context.Background(), "difference", []interface{}{"one"}, []interface{}{"one", "two"}, []interface{}{"one", "two", "tre"})
So(res, ShouldHaveLength, 1)
So(res, ShouldContain, "tre")
})
Convey("distinct(a) works properly", t, func() {
res, _ := Run(context.Background(), "distinct", []interface{}{"one", "two", "two", "tre", "tre", "tre"})
So(res, ShouldHaveLength, 3)
So(res, ShouldContain, "one")
So(res, ShouldContain, "two")
So(res, ShouldContain, "tre")
})
Convey("distinct(a, b, c) works properly", t, func() {
res, _ := Run(context.Background(), "distinct", []interface{}{"one"}, []interface{}{"one", "two"}, []interface{}{"one", "two", "tre"})
So(res, ShouldHaveLength, 3)
So(res, ShouldContain, "one")
So(res, ShouldContain, "two")
So(res, ShouldContain, "tre")
})
Convey("intersect(a, b, c) works properly", t, func() {
res, _ := Run(context.Background(), "intersect", []interface{}{"one"}, []interface{}{"one", "two"}, []interface{}{"one", "two", "tre"})
So(res, ShouldHaveLength, 1)
So(res, ShouldContain, "one")
})
Convey("union(a, b, c) works properly", t, func() {
res, _ := Run(context.Background(), "union", []interface{}{"one"}, []interface{}{"one", "two"}, []interface{}{"one", "two", "tre"})
So(res, ShouldHaveLength, 3)
So(res, ShouldContain, "one")
So(res, ShouldContain, "two")
So(res, ShouldContain, "tre")
})
}

180
util/fncs/string.go Normal file
View file

@ -0,0 +1,180 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"fmt"
"strings"
"github.com/abcum/surreal/util/ints"
"github.com/abcum/surreal/util/text"
)
func stringConcat(ctx context.Context, args ...interface{}) (str string, err error) {
for _, v := range args {
str = str + fmt.Sprint(v)
}
return
}
func stringContains(ctx context.Context, args ...interface{}) (bool, error) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])
return strings.Contains(s, p), nil
}
func stringEndsWith(ctx context.Context, args ...interface{}) (bool, error) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])
return strings.HasSuffix(s, p), nil
}
func stringFormat(ctx context.Context, args ...interface{}) (str string, err error) {
switch len(args) {
case 0, 1:
// Not enough arguments, so just ignore
default:
s, _ := ensureString(args[0])
str = fmt.Sprintf(s, args[1:]...)
}
return
}
func stringIncludes(ctx context.Context, args ...interface{}) (bool, error) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])
return strings.Contains(s, p), nil
}
func stringJoin(ctx context.Context, args ...interface{}) (str string, err error) {
switch len(args) {
case 0, 1:
// Not enough arguments, so just ignore
default:
var a []string
j, _ := ensureString(args[0])
for _, v := range args[1:] {
if v != nil {
a = append(a, fmt.Sprint(v))
}
}
str = strings.Join(a, j)
}
return
}
func stringLength(ctx context.Context, args ...interface{}) (float64, error) {
s, _ := ensureString(args[0])
return float64(len(s)), nil
}
func stringLevenshtein(ctx context.Context, args ...interface{}) (float64, error) {
s, _ := ensureString(args[0])
c, _ := ensureString(args[1])
return float64(text.Levenshtein(s, c)), nil
}
func stringLowercase(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
return strings.ToLower(s), nil
}
func stringRepeat(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
if c, ok := ensureInt(args[1]); ok {
return strings.Repeat(s, int(c)), nil
}
return s, nil
}
func stringReplace(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
o, _ := ensureString(args[1])
n, _ := ensureString(args[2])
return strings.Replace(s, o, n, -1), nil
}
func stringReverse(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
r := []rune(s)
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r), nil
}
func stringSearch(ctx context.Context, args ...interface{}) (float64, error) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])
return float64(strings.Index(s, p)), nil
}
func stringSlice(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
b, bk := ensureInt(args[1])
e, ek := ensureInt(args[2])
f := ints.Min(len(s), int(b+e))
if bk && ek {
return s[b:f], nil
} else if bk {
return s[b:], nil
} else if ek {
return s[:f], nil
}
return s, nil
}
func stringSplit(ctx context.Context, args ...interface{}) ([]string, error) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])
return strings.Split(s, p), nil
}
func stringStartsWith(ctx context.Context, args ...interface{}) (bool, error) {
s, _ := ensureString(args[0])
p, _ := ensureString(args[1])
return strings.HasPrefix(s, p), nil
}
func stringSubstr(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
b, bk := ensureInt(args[1])
e, ek := ensureInt(args[2])
f := ints.Min(len(s), int(e))
if bk && ek {
return s[b:f], nil
} else if bk {
return s[b:], nil
} else if ek {
return s[:f], nil
}
return s, nil
}
func stringTrim(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
return strings.TrimSpace(s), nil
}
func stringUppercase(ctx context.Context, args ...interface{}) (string, error) {
s, _ := ensureString(args[0])
return strings.ToUpper(s), nil
}
func stringWords(ctx context.Context, args ...interface{}) ([]string, error) {
s, _ := ensureString(args[0])
return strings.Fields(s), nil
}

171
util/fncs/string_test.go Normal file
View file

@ -0,0 +1,171 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestString(t *testing.T) {
var res interface{}
var test = "This IS a test"
var spac = " This IS a test "
Convey("string.concat() works properly", t, func() {
res, _ = Run(context.Background(), "string.concat", nil, 1, 1.5, "2", true, false)
So(res, ShouldEqual, "<nil>11.52truefalse")
})
Convey("string.contains() works properly", t, func() {
res, _ = Run(context.Background(), "string.contains", test, "done")
So(res, ShouldEqual, false)
res, _ = Run(context.Background(), "string.contains", test, "test")
So(res, ShouldEqual, true)
})
Convey("string.endsWith() works properly", t, func() {
res, _ = Run(context.Background(), "string.endsWith", test, "done")
So(res, ShouldEqual, false)
res, _ = Run(context.Background(), "string.endsWith", test, "test")
So(res, ShouldEqual, true)
})
Convey("string.format() works properly", t, func() {
res, _ = Run(context.Background(), "string.format", "%.9d", 1)
So(res, ShouldEqual, "000000001")
})
Convey("string.format() errors properly", t, func() {
res, _ = Run(context.Background(), "string.format", "%.9d")
So(res, ShouldEqual, "")
})
Convey("string.includes() works properly", t, func() {
res, _ = Run(context.Background(), "string.includes", test, "done")
So(res, ShouldEqual, false)
res, _ = Run(context.Background(), "string.includes", test, "test")
So(res, ShouldEqual, true)
})
Convey("string.join() works properly", t, func() {
res, _ = Run(context.Background(), "string.join")
So(res, ShouldEqual, "")
res, _ = Run(context.Background(), "string.join", ",")
So(res, ShouldEqual, "")
res, _ = Run(context.Background(), "string.join", ",", nil, 1, 1.5, "2", true, false)
So(res, ShouldEqual, "1,1.5,2,true,false")
})
Convey("string.length() works properly", t, func() {
res, _ = Run(context.Background(), "string.length", test)
So(res, ShouldEqual, 14)
})
Convey("string.levenshtein() works properly", t, func() {
res, _ = Run(context.Background(), "string.levenshtein", "test", "test")
So(res, ShouldEqual, 0)
res, _ = Run(context.Background(), "string.levenshtein", "lawn", "flaw")
So(res, ShouldEqual, 2)
res, _ = Run(context.Background(), "string.levenshtein", "test", "done")
So(res, ShouldEqual, 4)
})
Convey("string.lowercase() works properly", t, func() {
res, _ = Run(context.Background(), "string.lowercase", test)
So(res, ShouldEqual, "this is a test")
})
Convey("string.repeat(a, b) works properly", t, func() {
res, _ = Run(context.Background(), "string.repeat", test, 2)
So(res, ShouldEqual, test+test)
})
Convey("string.repeat(a, b) errors properly", t, func() {
res, _ = Run(context.Background(), "string.repeat", test, "test")
So(res, ShouldEqual, test)
})
Convey("string.replace() works properly", t, func() {
res, _ = Run(context.Background(), "string.replace", test, "test", "note")
So(res, ShouldEqual, "This IS a note")
})
Convey("string.reverse() works properly", t, func() {
res, _ = Run(context.Background(), "string.reverse", test, "test")
So(res, ShouldEqual, "tset a SI sihT")
})
Convey("string.search() works properly", t, func() {
res, _ = Run(context.Background(), "string.search", test, "done")
So(res, ShouldEqual, -1)
res, _ = Run(context.Background(), "string.search", test, "test")
So(res, ShouldEqual, 10)
})
Convey("string.slice() works properly", t, func() {
res, _ = Run(context.Background(), "string.slice", test, "a", "b")
So(res, ShouldEqual, test)
res, _ = Run(context.Background(), "string.slice", test, "2", "b")
So(res, ShouldEqual, test[2:])
res, _ = Run(context.Background(), "string.slice", test, "a", "2")
So(res, ShouldEqual, test[:2])
res, _ = Run(context.Background(), "string.slice", test, "2", "4")
So(res, ShouldEqual, test[2:4+2])
})
Convey("string.split() works properly", t, func() {
res, _ = Run(context.Background(), "string.split", test, " ")
So(res, ShouldResemble, []string{"This", "IS", "a", "test"})
})
Convey("string.startsWith() works properly", t, func() {
res, _ = Run(context.Background(), "string.startsWith", test, "this")
So(res, ShouldEqual, false)
res, _ = Run(context.Background(), "string.startsWith", test, "This")
So(res, ShouldEqual, true)
})
Convey("string.substr() works properly", t, func() {
res, _ = Run(context.Background(), "string.substr", test, "a", "b")
So(res, ShouldEqual, test)
res, _ = Run(context.Background(), "string.substr", test, "2", "b")
So(res, ShouldEqual, test[2:])
res, _ = Run(context.Background(), "string.substr", test, "a", "2")
So(res, ShouldEqual, test[:2])
res, _ = Run(context.Background(), "string.substr", test, "2", "4")
So(res, ShouldEqual, test[2:4])
})
Convey("string.trim() works properly", t, func() {
res, _ = Run(context.Background(), "string.trim", spac)
So(res, ShouldEqual, test)
})
Convey("string.uppercase() works properly", t, func() {
res, _ = Run(context.Background(), "string.uppercase", test)
So(res, ShouldEqual, "THIS IS A TEST")
})
Convey("string.words() works properly", t, func() {
res, _ = Run(context.Background(), "string.words", test)
So(res, ShouldResemble, []string{"This", "IS", "a", "test"})
})
}

26
util/fncs/table.go Normal file
View file

@ -0,0 +1,26 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/sql"
)
func table(ctx context.Context, args ...interface{}) (*sql.Table, error) {
tb, _ := ensureString(args[0])
return sql.NewTable(tb), nil
}

36
util/fncs/table_test.go Normal file
View file

@ -0,0 +1,36 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestTable(t *testing.T) {
var res interface{}
Convey("table() works properly", t, func() {
res, _ = Run(context.Background(), "table", 1)
So(res, ShouldResemble, sql.NewTable("1"))
res, _ = Run(context.Background(), "table", "test")
So(res, ShouldResemble, sql.NewTable("test"))
})
}

26
util/fncs/thing.go Normal file
View file

@ -0,0 +1,26 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"github.com/abcum/surreal/sql"
)
func thing(ctx context.Context, args ...interface{}) (*sql.Thing, error) {
tb, _ := ensureString(args[0])
return sql.NewThing(tb, args[1]), nil
}

36
util/fncs/thing_test.go Normal file
View file

@ -0,0 +1,36 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"github.com/abcum/surreal/sql"
. "github.com/smartystreets/goconvey/convey"
)
func TestThing(t *testing.T) {
var res interface{}
Convey("thing() works properly", t, func() {
res, _ = Run(context.Background(), "thing", 1, 1)
So(res, ShouldResemble, sql.NewThing("1", 1))
res, _ = Run(context.Background(), "thing", "test", 1)
So(res, ShouldResemble, sql.NewThing("test", 1))
})
}

156
util/fncs/time.go Normal file
View file

@ -0,0 +1,156 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"time"
)
func timeNow(ctx context.Context, args ...interface{}) (time.Time, error) {
return time.Now(), nil
}
func timeAdd(ctx context.Context, args ...interface{}) (time.Time, error) {
if t, ok := ensureTime(args[0]); ok {
if d, ok := ensureDuration(args[1]); ok {
return t.Add(d), nil
}
}
return time.Unix(0, 0), nil
}
func timeAge(ctx context.Context, args ...interface{}) (time.Time, error) {
if t, ok := ensureTime(args[0]); ok {
if d, ok := ensureDuration(args[1]); ok {
return t.Add(-d), nil
}
}
return time.Unix(0, 0), nil
}
func timeFloor(ctx context.Context, args ...interface{}) (interface{}, error) {
if t, ok := ensureTime(args[0]); ok {
if d, ok := ensureDuration(args[1]); ok {
return t.Truncate(d), nil
}
}
return nil, nil
}
func timeRound(ctx context.Context, args ...interface{}) (interface{}, error) {
if t, ok := ensureTime(args[0]); ok {
if d, ok := ensureDuration(args[1]); ok {
return t.Round(d), nil
}
}
return nil, nil
}
func timeDay(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Day()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Day()), nil
}
}
return 0, nil
}
func timeHour(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Hour()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Hour()), nil
}
}
return 0, nil
}
func timeMins(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Minute()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Minute()), nil
}
}
return 0, nil
}
func timeMonth(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Month()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Month()), nil
}
}
return 0, nil
}
func timeNano(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().UnixNano()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.UnixNano()), nil
}
}
return 0, nil
}
func timeSecs(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Second()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Second()), nil
}
}
return 0, nil
}
func timeUnix(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Unix()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Unix()), nil
}
}
return 0, nil
}
func timeYear(ctx context.Context, args ...interface{}) (float64, error) {
switch len(args) {
case 0:
return float64(time.Now().Year()), nil
case 1:
if v, ok := ensureTime(args[0]); ok {
return float64(v.Year()), nil
}
}
return 0, nil
}

234
util/fncs/time_test.go Normal file
View file

@ -0,0 +1,234 @@
// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fncs
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestTime(t *testing.T) {
now := time.Now()
org := time.Unix(0, 0)
dur := 24 * time.Hour
old, _ := time.Parse(time.RFC822Z, time.RFC822Z)
old = old.UTC()
rnd, _ := time.Parse("2006-01-02", "2006-01-03")
rnd = rnd.UTC()
trc, _ := time.Parse("2006-01-02", "2006-01-02")
trc = trc.UTC()
Convey("time.now() works properly", t, func() {
res, _ := Run(context.Background(), "time.now")
So(res, ShouldHaveSameTypeAs, now)
})
Convey("time.add(a, b) works properly", t, func() {
dur, _ := time.ParseDuration("1h")
res, _ := Run(context.Background(), "time.add", now, dur)
So(res, ShouldHaveSameTypeAs, now)
So(res, ShouldHappenAfter, now)
})
Convey("time.add(a, b) errors properly", t, func() {
res, _ := Run(context.Background(), "time.add", now, nil)
So(res, ShouldHaveSameTypeAs, org)
So(res, ShouldEqual, org)
})
Convey("time.age(a, b) errors properly", t, func() {
dur, _ := time.ParseDuration("1h")
res, _ := Run(context.Background(), "time.age", now, dur)
So(res, ShouldHaveSameTypeAs, now)
So(res, ShouldHappenBefore, now)
})
Convey("time.age(a, b) errors properly", t, func() {
res, _ := Run(context.Background(), "time.age", now, nil)
So(res, ShouldHaveSameTypeAs, org)
So(res, ShouldEqual, org)
})
Convey("time.floor(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "time.floor", old, dur)
So(res, ShouldHaveSameTypeAs, org)
So(res, ShouldEqual, trc)
})
Convey("time.floor(a,b) errors properly", t, func() {
res, _ := Run(context.Background(), "time.floor", "one", "two")
So(res, ShouldEqual, nil)
})
Convey("time.round(a,b) works properly", t, func() {
res, _ := Run(context.Background(), "time.round", old, dur)
So(res, ShouldHaveSameTypeAs, org)
So(res, ShouldEqual, rnd)
})
Convey("time.round(a,b) errors properly", t, func() {
res, _ := Run(context.Background(), "time.round", "one", "two")
So(res, ShouldEqual, nil)
})
Convey("time.day() works properly", t, func() {
res, _ := Run(context.Background(), "time.day")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, now.Day())
})
Convey("time.day(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.day", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 2)
})
Convey("time.day(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.day", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.hour() works properly", t, func() {
res, _ := Run(context.Background(), "time.hour")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, now.Hour())
})
Convey("time.hour(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.hour", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 22)
})
Convey("time.hour(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.hour", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.mins() works properly", t, func() {
res, _ := Run(context.Background(), "time.mins")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, now.Minute())
})
Convey("time.mins(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.mins", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 4)
})
Convey("time.mins(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.mins", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.month() works properly", t, func() {
res, _ := Run(context.Background(), "time.month")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, now.Month())
})
Convey("time.month(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.month", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 1)
})
Convey("time.month(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.month", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.nano() works properly", t, func() {
res, _ := Run(context.Background(), "time.nano")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldBeGreaterThanOrEqualTo, now.UnixNano())
})
Convey("time.nano(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.nano", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 1136239440000000000)
})
Convey("time.nano(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.nano", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.secs() works properly", t, func() {
res, _ := Run(context.Background(), "time.secs")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, now.Second())
})
Convey("time.secs(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.secs", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.secs(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.secs", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.unix() works properly", t, func() {
res, _ := Run(context.Background(), "time.unix")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldBeGreaterThanOrEqualTo, now.Unix())
})
Convey("time.unix(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.unix", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 1136239440)
})
Convey("time.unix(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.unix", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
Convey("time.year() works properly", t, func() {
res, _ := Run(context.Background(), "time.year")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, now.Year())
})
Convey("time.year(a) works properly", t, func() {
res, _ := Run(context.Background(), "time.year", old)
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 2006)
})
Convey("time.year(a,b,c) errors properly", t, func() {
res, _ := Run(context.Background(), "time.year", "one", "two")
So(res, ShouldHaveSameTypeAs, float64(0))
So(res, ShouldEqual, 0)
})
}