Files
graph/types/s2index_test.go
zeekay f5aaeb712e Hanzo Graph — the engine, on zapdb, ZAP-native
Derived from Dgraph (github.com/dgraph-io/dgraph) at commit 64804bd2, Apache-2.0.
See NOTICE.

WHAT THIS IS. The graph engine as a Go library: posting lists, the DQL parser,
the type and tokenizer system, the index and schema layers, and the wire types.
39,170 lines of the upstream's 166,337.

THE STORE is github.com/luxfi/zapdb, a Badger fork that kept the package name,
the subpackages (options, pb, y) and the API — Open, OpenManaged, DB, Options —
so the 74 import sites are aliased rather than rewritten.

THE CODEC is ZAP. zapdb serializes with ZAP, not protobuf: its pb package builds
the ZAP types by default and the protobuf ones only under `-tags grpc`, a path
that does not compile (table/builder.go calls pb.Marshal, which that tag
removes). One call site in posting needed converting; every other type here is
Hanzo's own protobuf and is untouched.

NO TRANSPORT. An embedded engine dials nothing, so nothing here imports
google.golang.org/grpc. Removed: 20 transport functions in x, the generated
service stubs for Raft, Zero and Worker (1,657 lines), and the JWT helper —
identity belongs to IAM. The core called none of them.

NOT KEPT: worker, conn, raftwal, the cluster commands, the GraphQL layer and the
test harnesses. `query`, the DQL execution engine, went with them because it
depends on worker; parsing DQL is available here, executing it is not.

The history of the upstream project lives at github.com/dgraph-io/dgraph. This
repository begins at the derivation because three quarters of that history
describes code this fork does not carry.
2026-08-20 21:26:27 -07:00

255 lines
5.9 KiB
Go

/*
* SPDX-FileCopyrightText: © 2017-2026 Istari Digital, Inc.
* SPDX-License-Identifier: Apache-2.0
*/
package types
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"os"
"testing"
"github.com/golang/geo/s2"
"github.com/stretchr/testify/require"
"github.com/twpayne/go-geom"
"github.com/twpayne/go-geom/encoding/geojson"
"github.com/twpayne/go-geom/encoding/wkb"
)
func loadPolygon(name string) (geom.T, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
defer f.Close()
var b bytes.Buffer
_, err = io.Copy(&b, f)
if err != nil {
return nil, err
}
var gf geojson.Feature
if err := gf.UnmarshalJSON(b.Bytes()); err != nil {
return nil, err
}
return gf.Geometry, nil
}
func TestIndexCellsPoint(t *testing.T) {
p := geom.NewPoint(geom.XY).MustSetCoords(geom.Coord{-122.082506, 37.4249518})
parents, cover, err := indexCells(p)
require.NoError(t, err)
require.Len(t, parents, MaxCellLevel-MinCellLevel+1)
c := parents[0]
if c.Level() != MinCellLevel {
t.Errorf("Expected cell level %d. Got %d instead.", MinCellLevel, c.Level())
}
if c.ToToken() != "808c" {
t.Errorf("Unexpected cell token %s.", c.ToToken())
}
c = parents[len(parents)-1]
if c.Level() != MaxCellLevel {
t.Errorf("Expected cell level %d. Got %d instead.", MaxCellLevel, c.Level())
}
if c.ToToken() != "808fb9f81" {
t.Errorf("Unexpected cell token %s.", c.ToToken())
}
// check that all cell levels are different
pc := parents[0]
for _, c := range parents[1:] {
if c.Level() <= pc.Level() {
t.Errorf("Expected cell to have level greater than %d. Got %d", pc.Level(), c.Level())
}
pc = c
}
// Check that cover only has one item
require.Len(t, cover, 1)
c = cover[0]
require.Equal(t, c.Level(), MaxCellLevel)
require.Equal(t, c.ToToken(), "808fb9f81")
}
func TestIndexCellsPolygon(t *testing.T) {
p, err := loadPolygon("testdata/zip.json")
require.NoError(t, err)
parents, cover, err := indexCells(p)
require.NoError(t, err)
if len(cover) > MaxCells {
t.Errorf("Expected less than %d cells. Got %d instead.", MaxCells, len(cover))
}
for _, c := range cover {
if c.Level() > MaxCellLevel || c.Level() < MinCellLevel {
t.Errorf("Invalid cell level %d.", c.Level())
}
require.Contains(t, parents, c)
}
require.True(t, len(parents) > len(cover))
}
func TestIndexCellsPolygonError(t *testing.T) {
poly := geom.NewPolygon(geom.XY).MustSetCoords([][]geom.Coord{
{{-122, 37}, {-123, 37}, {-123, 38}, {-122, 38}, {-122, 38}}})
_, _, err := indexCells(poly)
require.Error(t, err)
require.Contains(t, err.Error(), "Last coordinate not same as first")
}
func TestKeyGeneratorPoint(t *testing.T) {
p := geom.NewPoint(geom.XY).MustSetCoords(geom.Coord{-122.082506, 37.4249518})
data, err := wkb.Marshal(p, binary.LittleEndian)
require.NoError(t, err)
src := ValueForType(BinaryID)
src.Value = data
gc, err := Convert(src, GeoID)
require.NoError(t, err)
g := gc.Value.(geom.T)
keys, err := IndexGeoTokens(g)
require.NoError(t, err)
require.Len(t, keys, MaxCellLevel-MinCellLevel+1+1) // +1 for the cover
}
func TestKeyGeneratorPolygon(t *testing.T) {
p, err := loadPolygon("testdata/zip.json")
require.NoError(t, err)
data, err := wkb.Marshal(p, binary.LittleEndian)
require.NoError(t, err)
src := ValueForType(BinaryID)
src.Value = data
gc, err := Convert(src, GeoID)
require.NoError(t, err)
g := gc.Value.(geom.T)
keys, err := IndexGeoTokens(g)
require.NoError(t, err)
require.Len(t, keys, 67)
}
func printCoverAccuracy(l *s2.Loop, cu s2.CellUnion) {
a1 := cellUnionArea(cu)
a2 := l.Area()
fmt.Printf("Loop area: %v. Cell area %v. Ratio %.3f\n", EarthArea(a2), EarthArea(a1), a1/a2)
}
func cellUnionArea(cu s2.CellUnion) float64 {
var area float64
for _, c := range cu {
cell := s2.CellFromCellID(c)
area += cell.ExactArea()
}
return area
}
func BenchmarkToLoopZip(b *testing.B) {
benchToLoop(b, "testdata/zip.json")
}
func BenchmarkToLoopAruba(b *testing.B) {
benchToLoop(b, "testdata/aruba.json")
}
func BenchmarkCoverZip_10(b *testing.B) {
benchCover(b, "testdata/zip.json", 10)
}
func BenchmarkCoverZip_15(b *testing.B) {
benchCover(b, "testdata/zip.json", 15)
}
func BenchmarkCoverZip_18(b *testing.B) {
benchCover(b, "testdata/zip.json", 18)
}
func BenchmarkCoverZip_30(b *testing.B) {
benchCover(b, "testdata/zip.json", 30)
}
func BenchmarkCoverAruba_10(b *testing.B) {
benchCover(b, "testdata/aruba.json", 10)
}
func BenchmarkCoverAruba_15(b *testing.B) {
benchCover(b, "testdata/aruba.json", 15)
}
func BenchmarkCoverAruba_18(b *testing.B) {
benchCover(b, "testdata/aruba.json", 18)
}
func BenchmarkCoverAruba_30(b *testing.B) {
benchCover(b, "testdata/aruba.json", 30)
}
func BenchmarkKeyGeneratorPoint(b *testing.B) {
p := geom.NewPoint(geom.XY).MustSetCoords(geom.Coord{-122.082506, 37.4249518})
data, err := wkb.Marshal(p, binary.LittleEndian)
if err != nil {
b.Error(err)
}
src := ValueForType(BinaryID)
src.Value = data
gc, err := Convert(src, GeoID)
require.NoError(b, err)
g := gc.Value.(geom.T)
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _ = IndexGeoTokens(g)
}
}
func BenchmarkKeyGeneratorPolygon(b *testing.B) {
p, err := loadPolygon("testdata/zip.json")
if err != nil {
b.Error(err)
}
data, err := wkb.Marshal(p, binary.LittleEndian)
if err != nil {
b.Error(err)
}
src := ValueForType(GeoID)
src.Value = data
gc, err := Convert(src, GeoID)
require.NoError(b, err)
g := gc.Value.(geom.T)
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _ = IndexGeoTokens(g)
}
}
func benchCover(b *testing.B, file string, max int) {
p, err := loadPolygon(file)
if err != nil {
b.Error(err)
}
l, _ := loopFromPolygon(p.(*geom.Polygon))
var cu s2.CellUnion
b.ResetTimer()
for n := 0; n < b.N; n++ {
cu = coverLoop(l, MinCellLevel, MaxCellLevel, max)
}
printCoverAccuracy(l, cu)
}
func benchToLoop(b *testing.B, file string) {
p, err := loadPolygon(file)
if err != nil {
b.Error(err)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _ = loopFromPolygon(p.(*geom.Polygon))
}
}