mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-08-29 20:42:35 +00:00
* Implement custom types: SqlGeometry, SqlGeography, SqlHalfVector, SqlSparseVector, SqlBitVector * Add spatial filter operators and vector similarity operators * Include metadata and OpenAPI reporting for geometry/vector column types * Create tests for EWKB and WKT conversions
146 lines
3.7 KiB
Go
146 lines
3.7 KiB
Go
package common
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestVectorOperator(t *testing.T) {
|
|
cases := map[string]string{
|
|
"": "<->", "l2": "<->", "euclidean": "<->",
|
|
"cosine": "<=>", "cos": "<=>",
|
|
"ip": "<#>", "inner": "<#>", "dot": "<#>",
|
|
}
|
|
for in, want := range cases {
|
|
if got := VectorOperator(in); got != want {
|
|
t.Errorf("VectorOperator(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestVectorLiteral(t *testing.T) {
|
|
cases := []struct {
|
|
in any
|
|
want string
|
|
}{
|
|
{[]float32{1, 2, 3}, "[1,2,3]"},
|
|
{[]float64{1.5, -2}, "[1.5,-2]"},
|
|
{[]int{1, 2}, "[1,2]"},
|
|
{[]any{1.0, 2.0}, "[1,2]"},
|
|
{"[4,5,6]", "[4,5,6]"},
|
|
}
|
|
for _, c := range cases {
|
|
got, err := VectorLiteral(c.in)
|
|
if err != nil || got != c.want {
|
|
t.Errorf("VectorLiteral(%v) = %q, %v; want %q", c.in, got, err, c.want)
|
|
}
|
|
}
|
|
if _, err := VectorLiteral("not-a-vector"); err == nil {
|
|
t.Error("expected error for malformed string")
|
|
}
|
|
if _, err := VectorLiteral(42); err == nil {
|
|
t.Error("expected error for unsupported type")
|
|
}
|
|
}
|
|
|
|
func TestBuildVectorCondition(t *testing.T) {
|
|
q, args, ok := BuildVectorCondition("embedding", "cosine_within", map[string]any{
|
|
"vector": []any{1.0, 2.0, 3.0}, "distance": 0.5,
|
|
})
|
|
if !ok {
|
|
t.Fatal("expected ok")
|
|
}
|
|
if q != "embedding <=> ? < ?" {
|
|
t.Errorf("query = %q", q)
|
|
}
|
|
if len(args) != 2 || args[0] != "[1,2,3]" || args[1] != 0.5 {
|
|
t.Errorf("args = %v", args)
|
|
}
|
|
|
|
// explicit comparator
|
|
q, _, ok = BuildVectorCondition("v", "l2_within", map[string]any{
|
|
"vector": []float32{1}, "lte": 2.0,
|
|
})
|
|
if !ok || q != "v <-> ? <= ?" {
|
|
t.Errorf("lte: q=%q ok=%v", q, ok)
|
|
}
|
|
|
|
// unknown operator
|
|
if _, _, ok := BuildVectorCondition("v", "bogus", map[string]any{}); ok {
|
|
t.Error("expected not ok for unknown operator")
|
|
}
|
|
// missing threshold
|
|
if _, _, ok := BuildVectorCondition("v", "l2_within", map[string]any{"vector": []float32{1}}); ok {
|
|
t.Error("expected not ok without threshold")
|
|
}
|
|
}
|
|
|
|
func TestBuildSpatialCondition_Predicates(t *testing.T) {
|
|
q, args, ok := BuildSpatialCondition("geom", "st_intersects", "SRID=4326;POINT(0 0)")
|
|
if !ok {
|
|
t.Fatal("expected ok")
|
|
}
|
|
if q != "ST_Intersects(geom, ST_GeomFromEWKT(?))" {
|
|
t.Errorf("query = %q", q)
|
|
}
|
|
if len(args) != 1 || args[0] != "SRID=4326;POINT(0 0)" {
|
|
t.Errorf("args = %v", args)
|
|
}
|
|
|
|
// GeoJSON value
|
|
q, args, ok = BuildSpatialCondition("geom", "st_contains", map[string]any{
|
|
"type": "Point", "coordinates": []any{1.0, 2.0},
|
|
})
|
|
if !ok || q != "ST_Contains(geom, ST_GeomFromGeoJSON(?))" {
|
|
t.Errorf("geojson: q=%q ok=%v", q, ok)
|
|
}
|
|
if len(args) != 1 {
|
|
t.Errorf("args = %v", args)
|
|
}
|
|
}
|
|
|
|
func TestBuildSpatialCondition_DWithin(t *testing.T) {
|
|
q, args, ok := BuildSpatialCondition("geom", "st_dwithin", map[string]any{
|
|
"geom": "SRID=4326;POINT(0 0)", "distance": 1000.0,
|
|
})
|
|
if !ok {
|
|
t.Fatal("expected ok")
|
|
}
|
|
if q != "ST_DWithin(geom, ST_GeomFromEWKT(?), ?)" {
|
|
t.Errorf("query = %q", q)
|
|
}
|
|
if len(args) != 2 || args[1] != 1000.0 {
|
|
t.Errorf("args = %v", args)
|
|
}
|
|
}
|
|
|
|
func TestBuildSpatialCondition_BBox(t *testing.T) {
|
|
q, args, ok := BuildSpatialCondition("geom", "bbox", map[string]any{
|
|
"bbox": []any{0.0, 0.0, 10.0, 10.0}, "srid": 4326.0,
|
|
})
|
|
if !ok {
|
|
t.Fatal("expected ok")
|
|
}
|
|
if q != "geom && ST_MakeEnvelope(?, ?, ?, ?, ?)" {
|
|
t.Errorf("query = %q", q)
|
|
}
|
|
if len(args) != 5 || args[4] != 4326 {
|
|
t.Errorf("args = %v", args)
|
|
}
|
|
}
|
|
|
|
func TestIsSpatialAndVectorOperator(t *testing.T) {
|
|
for _, op := range []string{"st_dwithin", "st_intersects", "bbox", "&&"} {
|
|
if !IsSpatialOperator(op) {
|
|
t.Errorf("%q should be spatial", op)
|
|
}
|
|
}
|
|
for _, op := range []string{"l2_within", "cosine_within", "ip_within"} {
|
|
if !IsVectorOperator(op) {
|
|
t.Errorf("%q should be vector", op)
|
|
}
|
|
}
|
|
if IsSpatialOperator("eq") || IsVectorOperator("eq") {
|
|
t.Error("eq is neither spatial nor vector")
|
|
}
|
|
}
|