Files
chaisql/internal/expr/functions/math.go
2023-12-01 20:39:23 +04:00

178 lines
4.1 KiB
Go

package functions
import (
"fmt"
"math"
"math/rand"
"github.com/genjidb/genji/object"
"github.com/genjidb/genji/types"
)
// MathFunctions returns all math package functions.
func MathFunctions() Definitions {
return mathFunctions
}
var mathFunctions = Definitions{
"floor": floor,
"abs": abs,
"acos": acos,
"acosh": acosh,
"asin": asin,
"asinh": asinh,
"atan": atan,
"atan2": atan2,
"random": random,
}
var floor = &ScalarDefinition{
name: "floor",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
switch args[0].Type() {
case types.DoubleValue:
return types.NewDoubleValue(math.Floor(types.As[float64](args[0]))), nil
case types.IntegerValue:
return args[0], nil
default:
return nil, fmt.Errorf("floor(arg1) expects arg1 to be a number")
}
},
}
var abs = &ScalarDefinition{
name: "abs",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
if args[0].Type() == types.NullValue {
return types.NewNullValue(), nil
}
v, err := object.CastAs(args[0], types.DoubleValue)
if err != nil {
return nil, err
}
res := math.Abs(types.As[float64](v))
if args[0].Type() == types.IntegerValue {
return object.CastAs(types.NewDoubleValue(res), types.IntegerValue)
}
return types.NewDoubleValue(res), nil
},
}
var acos = &ScalarDefinition{
name: "acos",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
if args[0].Type() == types.NullValue {
return types.NewNullValue(), nil
}
v, err := object.CastAs(args[0], types.DoubleValue)
if err != nil {
return nil, err
}
vv := types.As[float64](v)
if vv > 1.0 || vv < -1.0 {
return nil, fmt.Errorf("out of range, acos(arg1) expects arg1 to be within [-1, 1]")
}
res := math.Acos(vv)
return types.NewDoubleValue(res), nil
},
}
var acosh = &ScalarDefinition{
name: "acosh",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
if args[0].Type() == types.NullValue {
return types.NewNullValue(), nil
}
v, err := object.CastAs(args[0], types.DoubleValue)
if err != nil {
return nil, err
}
vv := types.As[float64](v)
if vv < 1.0 {
return nil, fmt.Errorf("out of range, acosh(arg1) expects arg1 >= 1")
}
res := math.Acosh(vv)
return types.NewDoubleValue(res), nil
},
}
var asin = &ScalarDefinition{
name: "asin",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
if args[0].Type() == types.NullValue {
return types.NewNullValue(), nil
}
v, err := object.CastAs(args[0], types.DoubleValue)
if err != nil {
return nil, err
}
vv := types.As[float64](v)
if vv > 1.0 || vv < -1.0 {
return nil, fmt.Errorf("out of range, asin(arg1) expects arg1 to be within [-1, 1]")
}
res := math.Asin(vv)
return types.NewDoubleValue(res), nil
},
}
var asinh = &ScalarDefinition{
name: "asinh",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
v, err := object.CastAs(args[0], types.DoubleValue)
if err != nil || v.Type() == types.NullValue {
return v, err
}
vv := types.As[float64](v)
res := math.Asinh(vv)
return types.NewDoubleValue(res), nil
},
}
var atan = &ScalarDefinition{
name: "atan",
arity: 1,
callFn: func(args ...types.Value) (types.Value, error) {
v, err := object.CastAs(args[0], types.DoubleValue)
if err != nil || v.Type() == types.NullValue {
return v, err
}
vv := types.As[float64](v)
res := math.Atan(vv)
return types.NewDoubleValue(res), nil
},
}
var atan2 = &ScalarDefinition{
name: "atan2",
arity: 2,
callFn: func(args ...types.Value) (types.Value, error) {
vA, err := object.CastAs(args[0], types.DoubleValue)
if err != nil || vA.Type() == types.NullValue {
return vA, err
}
vvA := types.As[float64](vA)
vB, err := object.CastAs(args[1], types.DoubleValue)
if err != nil || vB.Type() == types.NullValue {
return vB, err
}
vvB := types.As[float64](vB)
res := math.Atan2(vvA, vvB)
return types.NewDoubleValue(res), nil
},
}
var random = &ScalarDefinition{
name: "random",
arity: 0,
callFn: func(args ...types.Value) (types.Value, error) {
randomNum := rand.Int63()
return types.NewIntegerValue(randomNum), nil
},
}