1
0
Fork 0
golang-github-pocketbase-po.../tools/search/token_functions.go
Daniel Baumann e28c88ef14
Adding upstream version 0.28.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-22 10:57:38 +02:00

56 lines
2.3 KiB
Go

package search
import (
"fmt"
"github.com/ganigeorgiev/fexpr"
)
var TokenFunctions = map[string]func(
argTokenResolverFunc func(fexpr.Token) (*ResolverResult, error),
args ...fexpr.Token,
) (*ResolverResult, error){
// geoDistance(lonA, latA, lonB, latB) calculates the Haversine
// distance between 2 points in kilometres (https://www.movable-type.co.uk/scripts/latlong.html).
//
// The accepted arguments at the moment could be either a plain number or a column identifier (including NULL).
// If the column identifier cannot be resolved and converted to a numeric value, it resolves to NULL.
//
// Similar to the built-in SQLite functions, geoDistance doesn't apply
// a "match-all" constraints in case there are multiple relation fields arguments.
// Or in other words, if a collection has "orgs" multiple relation field pointing to "orgs" collection that has "office" as "geoPoint" field,
// then the filter: `geoDistance(orgs.office.lon, orgs.office.lat, 1, 2) < 200`
// will evaluate to true if for at-least-one of the "orgs.office" records the function result in a value satisfying the condition (aka. "result < 200").
"geoDistance": func(argTokenResolverFunc func(fexpr.Token) (*ResolverResult, error), args ...fexpr.Token) (*ResolverResult, error) {
if len(args) != 4 {
return nil, fmt.Errorf("[geoDistance] expected 4 arguments, got %d", len(args))
}
resolvedArgs := make([]*ResolverResult, 4)
for i, arg := range args {
if arg.Type != fexpr.TokenIdentifier && arg.Type != fexpr.TokenNumber {
return nil, fmt.Errorf("[geoDistance] argument %d must be an identifier or number", i)
}
resolved, err := argTokenResolverFunc(arg)
if err != nil {
return nil, fmt.Errorf("[geoDistance] failed to resolve argument %d: %w", i, err)
}
resolvedArgs[i] = resolved
}
lonA := resolvedArgs[0].Identifier
latA := resolvedArgs[1].Identifier
lonB := resolvedArgs[2].Identifier
latB := resolvedArgs[3].Identifier
return &ResolverResult{
NoCoalesce: true,
Identifier: `(6371 * acos(` +
`cos(radians(` + latA + `)) * cos(radians(` + latB + `)) * ` +
`cos(radians(` + lonB + `) - radians(` + lonA + `)) + ` +
`sin(radians(` + latA + `)) * sin(radians(` + latB + `))` +
`))`,
Params: mergeParams(resolvedArgs[0].Params, resolvedArgs[1].Params, resolvedArgs[2].Params, resolvedArgs[3].Params),
}, nil
},
}