tile38

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: MPL-2.0 Imports: 12 Imported by: 0

README

tile38.go

Go Reference Lint and Test Release License

A Tile38 client for Go with a fluent query builder and live geofence streaming. No dependencies outside the standard library.

st, _ := c.Nearby("fleet").Point(33.5, -115.5).Radius(5000).
    Detect(tile38.Enter, tile38.Exit).Fence(ctx)
defer st.Close()

for {
    ev, err := st.Next()
    if err != nil {
        return err
    }
    log.Printf("%s %s", ev.Detect, ev.ID) // enter truck1
}

Why

Most Go clients drive Tile38 through a Redis library, because Tile38 speaks RESP. That works for request/response commands and stops at the interesting part: a live geofence turns the connection into a one-way event stream, and a connection-pooling Redis client cannot hold one open.

This client speaks RESP over net.Conn directly, so live geofences and channel subscriptions are first-class — the same thing tile38-cli does when you add FENCE to a query. Talking to the wire directly also means the whole library is the standard library: no go-redis, no transitive tree.

Install

go get github.com/GO-VIRTUAL-bv/tile38.go

The import path ends in .go; the package is named tile38:

import "github.com/GO-VIRTUAL-bv/tile38.go"

Requires Go 1.25+ and any recent Tile38.

Getting started

c := tile38.New("localhost:9851")
defer c.Close()

if err := c.Ping(ctx); err != nil {
    return err
}

// Write a point with a field and a 60s TTL.
err := c.Set("fleet", "truck1").EX(60).Field("speed", 42).Point(33.5, -115.5).Do(ctx)

lat, lon, err := c.Get("fleet", "truck1").Point(ctx)

Commands are built by chaining and executed by the terminal call, which is the one that takes a context.Context. Chain the parts in whatever order reads best — they are assembled into protocol order when the command runs:

pts, err := c.Nearby("fleet").Limit(10).Point(33.5, -115.5).Radius(5000).Points(ctx)
ids, err := c.Nearby("fleet").Where("speed > 40").Point(33.5, -115.5).Radius(5000).IDs(ctx)
n, err := c.Within("fleet").Bounds(33, -116, 34, -115).Count(ctx)
objs, err := c.Intersects("fleet").Circle(33.5, -115.5, 5000).Objects(ctx)
near, err := c.Nearby("fleet").Point(33.5, -115.5).Radius(5000).PointsWithDistance(ctx)
trucks, err := c.Scan("fleet").Match("truck:*").IDs(ctx)

Every search verb offers the output formats IDs, Points, Count, Objects, Rects (BOUNDS), Hashes, and A5Cells, and every search area Tile38 supports: Bounds, Circle, Sector, Object (GeoJSON), Get (an object already stored), Hash, QuadKey, Tile, and A5. Nearby takes Point + Radius instead of an area, and Scan and Search take none.

Filters are Where, WhereIn, WhereEval, WhereEvalSha, and Match, which accumulate; Limit, Cursor, Sparse, NoFields, Clip, and Asc/Desc are single-use and overwrite.

Points and Objects results carry the object's Fields beside its geometry, so reading a collection's state is one round trip rather than an FGet per field per object. Geofence notifications carry them too:

for _, p := range pts {
    log.Printf("%s at %v,%v doing %s", p.ID, p.Lat, p.Lon, p.Fields["speed"])
}

A point may carry a third ordinate, written with PointZ and read back as NearbyResult.Z or through Get(...).PointZ(ctx). Tile38 omits it from a reply when it is zero, so a zero Z and a two-dimensional point are the same thing.

Values are Tile38's own text encoding — the decimal form of a number, the verbatim JSON text of a JSON field — and are absent for an object whose fields are all zero or when the query used NoFields. One object's fields come back with its geometry through Get(...).WithFields():

g := c.Get("fleet", "truck1").WithFields()
lat, lon, err := g.Point(ctx)
speed := g.Fields()["speed"]
Other commands

Search matches the string values Set(...).String(...) stores, rather than geometry. Test compares two areas without touching stored objects:

ok, err := c.Test(tile38.AreaGet("fleet", "truck1")).
    Within(tile38.AreaBounds(tile38.GlobalBounds())).Do(ctx)

Field, collection and server commands: FGet, FSet, FExists, JGet/JSet/ JDel, Keys, Bounds, Stats, DBSize, Drop, PDel, Rename, Expire, Persist, TTL, Exists, FlushDB, ConfigGet/ConfigSet/ConfigRewrite, GC, Healthz, AOFShrink, ReadOnly, Follow/FollowNone, and Timeout.

Result limits

Tile38 caps every search except Count at 100 results when the command carries no LIMIT. It reports that it stopped early by returning a non-zero cursor, which this client surfaces as ErrTruncated:

ids, err := c.Scan("fleet").IDs(ctx)
if errors.Is(err, ErrTruncated) {
    // ids holds the first 100; more objects match.
}

The results returned alongside the error are valid, just incomplete. Either page through the rest, or set an explicit Limit to say the cap is intended — an explicit Limit or Cursor silences the error, since then the bound is yours.

cmd := c.Scan("fleet")
for {
    ids, err := cmd.IDs(ctx)
    if err != nil && !errors.Is(err, tile38.ErrTruncated) {
        return err
    }
    use(ids)
    if !errors.Is(err, tile38.ErrTruncated) {
        break
    }
    cmd = c.Scan("fleet").Cursor(cmd.NextCursor())
}

Live geofences

Adding Fence to a search opens a stream instead of returning results. The Stream owns its own connection and has no read timeout, so a quiet fence can sit idle for hours.

st, err := c.Within("zones").Bounds(-90, -180, 90, 180).
    Detect(tile38.Enter, tile38.Exit).
    Commands(tile38.CommandSet).
    Fence(ctx)
if err != nil {
    return err
}
defer st.Close()

for {
    ev, err := st.Next() // io.EOF after Close, ctx.Err() on cancel
    if err != nil {
        return err
    }
    fmt.Println(ev.Detect, ev.ID, string(ev.Object))
}

Detect takes Inside, Outside, Enter, Exit, Cross; Commands filters by what caused the event (CommandSet, CommandDel, CommandDrop, CommandFSet, …). Both are named string types, so a typo is a compile error rather than a server error. Fence is available on Nearby, Within, and Intersects.

A Nearby fence can also roam — firing as objects come within range of another collection — which Tile38 allows only on a live fence:

st, err := c.Nearby("fleet").Roam("targets", 250).NoDwell().Fence(ctx)

Channels and hooks

A geofence can also be registered on the server and delivered to subscribers (SETCHAN) or pushed to an endpoint (SETHOOK).

// Server-side fence, delivered to subscribers.
err := c.SetChan("zone1").Within("fleet").
    Detect(tile38.Inside).
    Bounds(tile38.GlobalBounds()).
    Do(ctx)

sub, err := c.Subscribe(ctx, "zone1") // or c.PSubscribe(ctx, "zone*")
defer sub.Close()

ev, err := sub.Next() // same *FenceEvent as a live fence
// Server-side fence, pushed to an endpoint.
err := c.SetHook("alerts").Endpoint("http://example.com", "events").
    Within("fleet").
    Detect(tile38.Enter, tile38.Exit).
    Meta("team", "ops").
    Circle(33.5, -115.5, 5000).
    Do(ctx)

hooks, err := c.Hooks("*").Do(ctx)

Endpoint joins a base URL and a subject with /. For schemes that do not fit that shape, or to register several endpoints on one hook, use EndpointURL:

c.SetHook("alerts").EndpointURL("kafka://k:9092/events", "http://x/y?token=1")

Hooks and channels trigger on Nearby, Within, or Intersects, take the same fence areas as a search — Bounds, Circle, Object, Get, A5 — plus Roam, and accept Meta and EX. GlobalBounds() returns the whole-world box as four values, which Go binds straight onto Bounds' parameters.

A roaming fence reports objects that stay in range on every update. Chain NoDwell to suppress those — on hooks, channels, and live Nearby fences alike:

err := c.SetChan("proximity").Nearby("fleet").NoDwell().Roam("targets", 250).Do(ctx)

Hooks and Chans both return []HookInfo — name, watched collection, endpoints, and the fence command the hook was created with.

Pipelining

Batch writes into a single round trip:

p := c.Pipeline()
for _, t := range trucks {
    p.Set("fleet", t.ID).EX(300).Field("speed", t.Speed).Point(t.Lat, t.Lon).Queue()
}
err := p.Flush(ctx)

Configuration

The address is required; everything else is an option.

c := tile38.New("localhost:9851",
    tile38.WithPassword("secret"),            // AUTH on each new connection
    tile38.WithMaxIdle(16),                   // idle connections kept for reuse
    tile38.WithMaxActive(64),                 // commands in flight at once
    tile38.WithDialTimeout(5*time.Second),
    tile38.WithTimeout(2*time.Second),        // per-command deadline
)

Commands take a connection from an idle pool. A rejected command returns a ServerError and the connection stays in the pool; a transport failure drops it. Streams always get their own connection and are not counted against WithMaxActive, since they hold it for as long as they run.

WithMaxIdle bounds only the connections kept for reuse, so without WithMaxActive a burst of concurrent commands opens a socket per goroutine. WithTimeout defaults to DefaultTimeout (30s) so a command against a wedged server cannot hang forever on a context with no deadline; pass a negative duration to rely on the context alone.

For anything this library does not model:

v, err := c.Do(ctx, "SERVER") // string, int64, []any, or nil

Testing

make test              # unit tests against a scripted server, no Docker
make test-integration  # against a real Tile38 in Docker via testcontainers
make lint

Integration tests are behind the integration build tag, so go get of this library never pulls testcontainers into your build.

Contributing

make lint needs golangci-lint v2:

go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest

.claude/settings.json is checked in, so Claude Code picks up two repo hooks automatically: Go files are formatted on edit, and a new direct dependency in go.mod is refused — this client is deliberately dependency-free. The format hook shells out to golangci-lint so it agrees with make lint rather than approximating it, which means it fails on every edit if the binary is not on your PATH. Install it first, or drop .claude/settings.json from your working copy.

Notes

This client targets upstream Tile38 only. A command upstream does not accept is not exposed here — it goes upstream first, and lands here once accepted.

One nuance: Within(…).A5, Intersects(…).A5, and Get(…).A5 are merged into upstream Tile38 but have shipped in no release tag as of 1.38.0, so they need a server built from upstream master. That is why .version pins a tile38/tile38:edge digest rather than a release tag.

Claude Code skill

This repo ships a Claude Code skill that teaches the agent to use this client. Install it as a plugin:

/plugin marketplace add GO-VIRTUAL-bv/tile38.go
/plugin install tile38@go-virtual

Or with the skills CLI:

npx skills add GO-VIRTUAL-bv/tile38.go@tile38

The skill lives at .claude/skills/tile38 (SKILL.md plus a reference.md command catalog); you can also copy that folder into any ~/.claude/skills/ directly.

License

Mozilla Public License 2.0 — see LICENSE.

MPL-2.0 is file-level copyleft: you can import this client into proprietary software freely. If you modify one of its files and distribute the result, you have to make that file's source available to whoever you distributed it to. Files you add alongside it are yours.

Documentation

Overview

Package tile38 is a client for the Tile38 geospatial database.

It speaks RESP over TCP directly rather than through a Redis library, which is what makes live geofences possible: adding Fence to a search turns the connection into a stream of events instead of a single reply.

The package has no dependencies outside the standard library.

Index

Constants

View Source
const DefaultTimeout = conn.DefaultTimeout

DefaultTimeout bounds a single command when WithTimeout is not given.

Variables

View Source
var ErrClosed = conn.ErrClosed

ErrClosed is returned when a command is issued on a closed Client.

View Source
var ErrTruncated = errors.New("tile38: result truncated, more objects match")

ErrTruncated reports that a search returned only part of what matched: Tile38 stopped at the limit and more objects remain.

This is easy to hit unknowingly, because Tile38 caps every search output except COUNT at 100 results when the command carries no LIMIT (limitItems in internal/server/scanner.go). A query that is correct against a small collection therefore starts silently dropping results as that collection grows, which is what this error exists to prevent.

The results returned alongside it are valid, just incomplete. Either page through the rest with Cursor and NextCursor:

cmd := c.Scan("fleet")
for {
	ids, err := cmd.IDs(ctx)
	if err != nil && !errors.Is(err, ErrTruncated) {
		return err
	}
	use(ids)
	if !errors.Is(err, ErrTruncated) {
		break
	}
	cmd = c.Scan("fleet").Cursor(cmd.NextCursor())
}

or set an explicit Limit to say the cap is intended — an explicit Limit or Cursor silences this error, since then the bound is the caller's own.

Functions

func Field

func Field(name string, value any) field

Field creates a key/value field for use with the Field and Fields methods. The field type stays unexported; Field is the only public entry point.

func GlobalBounds

func GlobalBounds() (swLat, swLon, neLat, neLon float64)

GlobalBounds is the whole-world bounding box. Go binds a multi-valued call straight onto a matching parameter list, so it can be handed to any Bounds method as-is:

c.SetChan("zone").Within("fleet").Bounds(tile38.GlobalBounds())

Types

type A5Result added in v0.2.0

type A5Result struct {
	ID   string
	Cell string // A5 cell id at the level the query asked for
}

A5Result holds a single result from a search using the A5 output format. A5 is the one output format Tile38 does not attach fields to (scanner.go, hasFieldsOutput).

type Area added in v0.2.0

type Area struct {
	// contains filtered or unexported fields
}

Area is one side of a TEST comparison. TEST takes two areas positionally rather than as chained options, so they are built as values and handed to Client.Test and the verb method:

ok, err := c.Test(tile38.AreaGet("fleet", "truck1")).
	Within(tile38.AreaBounds(tile38.GlobalBounds())).Do(ctx)

The same geometries a search takes are available here, except A5: WITHIN and INTERSECTS accept an A5 cell but TEST rejects it on the supported server.

func AreaBounds added in v0.2.0

func AreaBounds(swLat, swLon, neLat, neLon float64) Area

AreaBounds is a lat/lon bounding box (BOUNDS keyword). Pass GlobalBounds() for the whole world.

func AreaCircle added in v0.2.0

func AreaCircle(lat, lon float64, metres int) Area

AreaCircle is a circle with centre and radius in metres (CIRCLE keyword).

func AreaGet added in v0.2.0

func AreaGet(collection, id string) Area

AreaGet is an object already stored in Tile38 (GET keyword).

func AreaHash added in v0.2.0

func AreaHash(geohash string) Area

AreaHash is the box a geohash covers (HASH keyword).

func AreaObject added in v0.2.0

func AreaObject(geojson string) Area

AreaObject is an inline GeoJSON geometry (OBJECT keyword).

func AreaPoint added in v0.2.0

func AreaPoint(lat, lon float64) Area

AreaPoint is a single coordinate (POINT keyword).

func AreaQuadKey added in v0.2.0

func AreaQuadKey(quadkey string) Area

AreaQuadKey is the tile a Bing Maps quadkey names (QUADKEY keyword).

func AreaSector added in v0.2.0

func AreaSector(lat, lon float64, metres int, bearing1, bearing2 float64) Area

AreaSector is a circle clipped to the arc between two compass bearings in degrees (SECTOR keyword).

func AreaTile added in v0.2.0

func AreaTile(x, y, z int) Area

AreaTile is a single XYZ map tile (TILE keyword).

type BoundsCmd

type BoundsCmd struct {
	// contains filtered or unexported fields
}

BoundsCmd builds a Tile38 BOUNDS command to get the bounding box of a collection.

func (*BoundsCmd) Do

func (cmd *BoundsCmd) Do(ctx context.Context) (BoundsResult, error)

Do executes: BOUNDS collection — returns the SW and NE corners of the collection's extent.

type BoundsResult

type BoundsResult struct {
	SW [2]float64 // {lat, lon}
	NE [2]float64 // {lat, lon}
}

BoundsResult holds the SW and NE corners of a bounding box.

type ChansCmd

type ChansCmd struct {
	// contains filtered or unexported fields
}

ChansCmd builds a Tile38 CHANS command to list registered pub/sub channels.

func (*ChansCmd) Do

func (cmd *ChansCmd) Do(ctx context.Context) ([]HookInfo, error)

Do executes: CHANS [pattern] — returns the channels matching the glob pattern.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a Tile38 client. It is safe for concurrent use.

Commands take a connection from a small idle pool. Streaming calls (Fence, Subscribe, PSubscribe) get a dedicated connection that never returns to the pool, because the server keeps writing to it.

The zero value is not usable; build one with New.

func New

func New(addr string, opts ...Option) *Client

New creates a Client for addr, the "host:port" of a Tile38 server. No connection is made until the first command.

func (*Client) AOFShrink added in v0.2.0

func (c *Client) AOFShrink() *StatusCmd

AOFShrink starts building a Tile38 AOFSHRINK command, which rewrites the append-only file in the background.

func (*Client) Bounds

func (c *Client) Bounds(collection string) *BoundsCmd

Bounds starts building a Tile38 BOUNDS command to get the bounding box of a collection.

func (*Client) Chans

func (c *Client) Chans(pattern string) *ChansCmd

Chans starts building a Tile38 CHANS command to list registered pub/sub channels. Pass "*" to list all channels.

func (*Client) Close

func (c *Client) Close() error

Close closes all pooled connections. Streams opened from this Client are not affected; close those with their own Close.

func (*Client) ConfigGet added in v0.2.0

func (c *Client) ConfigGet(parameter string) *ConfigGetCmd

ConfigGet starts building a Tile38 CONFIG GET command for one parameter.

func (*Client) ConfigRewrite added in v0.2.0

func (c *Client) ConfigRewrite() *StatusCmd

ConfigRewrite starts building a Tile38 CONFIG REWRITE command, which writes the running configuration back to the config file.

func (*Client) ConfigSet added in v0.2.0

func (c *Client) ConfigSet(parameter, value string) *StatusCmd

ConfigSet starts building a Tile38 CONFIG SET command. The change applies immediately but is lost on restart unless ConfigRewrite persists it.

func (*Client) DBSize

func (c *Client) DBSize() *DBSizeCmd

DBSize starts building a query for the total object count across all collections. Tile38 has no DBSIZE command, so this reads num_objects from SERVER.

func (*Client) Del

func (c *Client) Del(collection, id string) *DelCmd

Del starts building a Tile38 DEL command for the given collection and object ID.

func (*Client) DelChan

func (c *Client) DelChan(channelName string) *DelChanCmd

DelChan starts building a Tile38 DELCHAN command.

func (*Client) DelHook

func (c *Client) DelHook(hookName string) *DelHookCmd

DelHook starts building a Tile38 DELHOOK command for the given hook name.

func (*Client) Do

func (c *Client) Do(ctx context.Context, args ...any) (any, error)

Do runs a raw Tile38 command and returns the decoded reply — an escape hatch for commands this package does not model. Replies decode to string, int64, []any, or nil.

func (*Client) Drop

func (c *Client) Drop(collection string) *DropCmd

Drop starts building a Tile38 DROP command to delete an entire collection.

func (*Client) Exists

func (c *Client) Exists(collection, id string) *ExistsCmd

Exists starts building a Tile38 EXISTS command to check whether an object exists.

func (*Client) Expire

func (c *Client) Expire(collection, id string, seconds int) *ExpireCmd

Expire starts building a Tile38 EXPIRE command to set a TTL on an object.

func (*Client) FExists added in v0.2.0

func (c *Client) FExists(collection, id, field string) *FExistsCmd

FExists starts building a Tile38 FEXISTS command to test whether a field is set on an object.

func (*Client) FGet

func (c *Client) FGet(collection, id, field string) *FGetCmd

FGet starts building a Tile38 FGET command to read a single field value.

func (*Client) FSet

func (c *Client) FSet(collection, id string) *FSetCmd

FSet starts building a Tile38 FSET command for the given collection and object ID.

func (*Client) FlushDB

func (c *Client) FlushDB() *FlushDBCmd

FlushDB starts building a Tile38 FLUSHDB command to delete all objects and collections.

func (*Client) Follow added in v0.2.0

func (c *Client) Follow(host string, port int) *StatusCmd

Follow starts building a Tile38 FOLLOW command, making this server a replica of the one at host:port. Use FollowNone to stop.

func (*Client) FollowNone added in v0.2.0

func (c *Client) FollowNone() *StatusCmd

FollowNone starts building "FOLLOW no one", which promotes a replica back to a leader. Tile38 spells it as a host of "no" and a port of "one".

func (*Client) GC added in v0.2.0

func (c *Client) GC() *StatusCmd

GC starts building a Tile38 GC command, which forces a garbage collection.

func (*Client) Get

func (c *Client) Get(collection, id string) *GetCmd

Get starts building a Tile38 GET query for the given collection and object ID.

func (*Client) Healthz added in v0.2.0

func (c *Client) Healthz() *StatusCmd

Healthz starts building a Tile38 HEALTHZ command: a liveness check that takes no read lock, so it answers even while the server is busy. It is the one command besides AUTH and OUTPUT that needs no authentication.

func (*Client) Hooks

func (c *Client) Hooks(pattern string) *HooksCmd

Hooks starts building a Tile38 HOOKS command to list registered hooks. Pass "*" to list all hooks.

func (*Client) Intersects

func (c *Client) Intersects(collection string) *IntersectsCmd

Intersects starts building a Tile38 INTERSECTS query for the given collection.

func (*Client) JDel

func (c *Client) JDel(collection, id, path string) *JDelCmd

JDel starts building a Tile38 JDEL command to delete a JSON field by path.

func (*Client) JGet

func (c *Client) JGet(collection, id, path string) *JGetCmd

JGet starts building a Tile38 JGET command to read a JSON field by path.

func (*Client) JSet

func (c *Client) JSet(collection, id, path string, value any) *JSetCmd

JSet starts building a Tile38 JSET command to set a JSON field by path.

func (*Client) Keys

func (c *Client) Keys(pattern string) *KeysCmd

Keys starts building a Tile38 KEYS command to list collection names matching a glob pattern. Pass "*" to list all collections.

func (*Client) Nearby

func (c *Client) Nearby(collection string) *NearbyCmd

Nearby starts building a Tile38 NEARBY query for the given collection.

func (*Client) PDel

func (c *Client) PDel(collection, pattern string) *PDelCmd

PDel starts building a Tile38 PDEL command to delete objects matching a glob pattern.

func (*Client) PDelChan

func (c *Client) PDelChan(pattern string) *PDelChanCmd

PDelChan starts building a Tile38 PDELCHAN command (pattern-based channel deletion).

func (*Client) PDelHook

func (c *Client) PDelHook(pattern string) *PDelHookCmd

PDelHook starts building a Tile38 PDELHOOK command (pattern-based hook deletion).

func (*Client) PSubscribe

func (c *Client) PSubscribe(ctx context.Context, patterns ...string) (*Stream, error)

PSubscribe opens a stream of events from every SETCHAN channel matching the given glob patterns.

func (*Client) Persist

func (c *Client) Persist(collection, id string) *PersistCmd

Persist starts building a Tile38 PERSIST command to remove the TTL from an object.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping verifies connectivity. Call at startup.

func (*Client) Pipeline

func (c *Client) Pipeline() *Pipeline

Pipeline returns a Pipeline for batching multiple SET commands in one round trip.

func (*Client) ReadOnly added in v0.2.0

func (c *Client) ReadOnly(on bool) *StatusCmd

ReadOnly starts building a Tile38 READONLY command, turning read-only mode on or off. In read-only mode the server rejects every write.

func (*Client) Rename

func (c *Client) Rename(collection, newCollection string) *RenameCmd

Rename starts building a Tile38 RENAME command. Chain NX() to use RENAMENX.

func (*Client) Scan

func (c *Client) Scan(collection string) *ScanCmd

Scan starts building a Tile38 SCAN query for the given collection.

func (*Client) Search added in v0.2.0

func (c *Client) Search(collection string) *SearchCmd

Search starts building a Tile38 SEARCH query, which matches on the string values "SET … STRING" stores rather than on geometry.

func (*Client) Set

func (c *Client) Set(collection, id string) *SetCmd

Set starts building a Tile38 SET command for the given collection and object ID.

func (*Client) SetChan

func (c *Client) SetChan(channelName string) *SetChanCmd

SetChan starts building a Tile38 SETCHAN command for a pub/sub geofence channel.

func (*Client) SetHook

func (c *Client) SetHook(hookName string) *HookCmd

SetHook starts building a Tile38 SETHOOK command for the given hook name.

func (*Client) Stats added in v0.2.0

func (c *Client) Stats(collections ...string) *StatsCmd

Stats starts building a Tile38 STATS command for one or more collections.

func (*Client) Subscribe

func (c *Client) Subscribe(ctx context.Context, channels ...string) (*Stream, error)

Subscribe opens a stream of events from the given SETCHAN channels.

func (*Client) TTL

func (c *Client) TTL(collection, id string) *TTLCmd

TTL starts building a Tile38 TTL command to read the remaining TTL of an object.

func (*Client) Test added in v0.2.0

func (c *Client) Test(area Area) *TestCmd

Test starts building a Tile38 TEST command comparing area against another, given to Within or Intersects. It touches no stored object.

func (*Client) Timeout added in v0.2.0

func (c *Client) Timeout(ctx context.Context, seconds float64, args ...any) (any, error)

Timeout runs one raw command with a server-side time limit, matching Tile38's TIMEOUT keyword: the server abandons the command after seconds and answers with an error. That is a different guarantee from a context deadline, which only stops this client waiting.

It returns the decoded reply of the wrapped command, as Do does.

func (*Client) Within

func (c *Client) Within(collection string) *WithinCmd

Within starts building a Tile38 WITHIN query for the given collection.

type CollectionStats added in v0.2.0

type CollectionStats struct {
	Key          string
	Exists       bool
	InMemorySize int64
	NumObjects   int64
	NumPoints    int64
	NumStrings   int64
}

CollectionStats holds the STATS counters for one collection. Exists is false when the collection is not there: Tile38 answers with a null element for a missing key rather than an error.

type Command

type Command string

Command is a Tile38 command that can cause a fence event. Restrict a fence to a subset with Commands.

const (
	CommandSet    Command = "set"
	CommandFSet   Command = "fset"
	CommandDel    Command = "del"
	CommandPDel   Command = "pdel"
	CommandDrop   Command = "drop"
	CommandExpire Command = "expire"
)

Commands that produce fence events.

type ConfigGetCmd added in v0.2.0

type ConfigGetCmd struct {
	// contains filtered or unexported fields
}

ConfigGetCmd builds a Tile38 CONFIG GET command.

func (*ConfigGetCmd) Do added in v0.2.0

func (cmd *ConfigGetCmd) Do(ctx context.Context) (string, error)

Do executes: CONFIG GET parameter — returns the value as text. An unset parameter reads as the empty string rather than an error, which is how Tile38 reports it.

type DBSizeCmd

type DBSizeCmd struct {
	// contains filtered or unexported fields
}

DBSizeCmd reads the total object count from SERVER.

func (*DBSizeCmd) Do

func (cmd *DBSizeCmd) Do(ctx context.Context) (int64, error)

Do executes: SERVER — returns num_objects, the total across all collections.

type DelChanCmd

type DelChanCmd struct {
	// contains filtered or unexported fields
}

DelChanCmd builds a Tile38 DELCHAN command.

func (*DelChanCmd) Do

func (cmd *DelChanCmd) Do(ctx context.Context) error

Do executes: DELCHAN channelName

type DelCmd

type DelCmd struct {
	// contains filtered or unexported fields
}

DelCmd builds a Tile38 DEL command.

func (*DelCmd) Do

func (cmd *DelCmd) Do(ctx context.Context) error

Do executes: DEL collection id

type DelHookCmd

type DelHookCmd struct {
	// contains filtered or unexported fields
}

DelHookCmd builds a Tile38 DELHOOK command.

func (*DelHookCmd) Do

func (cmd *DelHookCmd) Do(ctx context.Context) error

Do executes: DELHOOK hookName

type DetectState

type DetectState string

DetectState is a geofence transition a fence can report. Restrict a fence to a subset with Detect; omitting it means Tile38's default set.

const (
	Inside  DetectState = "inside"  // object is within the fence
	Outside DetectState = "outside" // object is outside the fence
	Enter   DetectState = "enter"   // object crossed in
	Exit    DetectState = "exit"    // object crossed out
	Cross   DetectState = "cross"   // object passed through
)

Geofence transitions.

type DropCmd

type DropCmd struct {
	// contains filtered or unexported fields
}

DropCmd builds a Tile38 DROP command.

func (*DropCmd) Do

func (cmd *DropCmd) Do(ctx context.Context) error

Do executes: DROP collection

type ExistsCmd

type ExistsCmd struct {
	// contains filtered or unexported fields
}

ExistsCmd builds a Tile38 EXISTS command.

func (*ExistsCmd) Do

func (cmd *ExistsCmd) Do(ctx context.Context) (bool, error)

Do executes: EXISTS collection id

type ExpireCmd

type ExpireCmd struct {
	// contains filtered or unexported fields
}

ExpireCmd builds a Tile38 EXPIRE command.

func (*ExpireCmd) Do

func (cmd *ExpireCmd) Do(ctx context.Context) error

Do executes: EXPIRE collection id seconds

type FExistsCmd added in v0.2.0

type FExistsCmd struct {
	// contains filtered or unexported fields
}

FExistsCmd builds a Tile38 FEXISTS command.

func (*FExistsCmd) Do added in v0.2.0

func (cmd *FExistsCmd) Do(ctx context.Context) (bool, error)

Do executes: FEXISTS collection id field — reports whether the field is set on the object. Unlike FGet, this distinguishes a missing field from one holding the zero value.

type FGetCmd

type FGetCmd struct {
	// contains filtered or unexported fields
}

FGetCmd builds a Tile38 FGET command.

func (*FGetCmd) Do

func (cmd *FGetCmd) Do(ctx context.Context) (string, error)

Do executes: FGET collection id field

It returns the raw string value of the field. A missing field and an empty one are indistinguishable: Tile38 replies with the zero value of the field either way — "" for a string field, "0" for a numeric one — rather than a null. A missing collection or object does produce an error, so only the field name is ambiguous.

type FSetCmd

type FSetCmd struct {
	// contains filtered or unexported fields
}

FSetCmd builds a Tile38 FSET command.

func (*FSetCmd) Do

func (cmd *FSetCmd) Do(ctx context.Context) error

Do executes: FSET collection id [name val ...]

func (*FSetCmd) Field

func (cmd *FSetCmd) Field(name string, value any) *FSetCmd

Field appends a single named field to update.

func (*FSetCmd) Fields

func (cmd *FSetCmd) Fields(fields ...field) *FSetCmd

Fields appends multiple named fields to update in one call.

type FenceEvent

type FenceEvent struct {
	Command  string            `json:"command"`            // set | del | drop | fset
	Group    string            `json:"group,omitempty"`    // correlation group id
	Detect   string            `json:"detect,omitempty"`   // enter|exit|inside|outside|cross|roam
	Hook     string            `json:"hook,omitempty"`     // hook/channel name
	Meta     map[string]string `json:"meta,omitempty"`     // hook META key/values
	Key      string            `json:"key,omitempty"`      // collection key
	Time     string            `json:"time,omitempty"`     // RFC3339 timestamp
	ID       string            `json:"id,omitempty"`       // object id
	Object   json.RawMessage   `json:"object,omitempty"`   // GeoJSON of the object
	Fields   Fields            `json:"fields,omitempty"`   // the object's FIELDS at the time of the event
	Distance float64           `json:"distance,omitempty"` // metres from the fence centre; only on a fence that asked for DISTANCE
	Nearby   json.RawMessage   `json:"nearby,omitempty"`   // roam companion object
	Faraway  json.RawMessage   `json:"faraway,omitempty"`  // roam companion object
}

FenceEvent is a decoded Tile38 geofence notification — the JSON payload Tile38 pushes to a webhook endpoint (SETHOOK), broadcasts to a pub/sub channel (SETCHAN), or streams down a live fence connection (Fence) when an object enters, dwells in, or exits a fenced area.

func DecodeFenceEvent

func DecodeFenceEvent(data []byte) (*FenceEvent, error)

DecodeFenceEvent unmarshals a Tile38 geofence notification payload.

type Fields added in v0.2.0

type Fields map[string]string

Fields are an object's Tile38 FIELDS, name → Tile38's own text encoding of the value: the decimal form of a number, the verbatim JSON text of a JSON field. Nil when the object has no non-zero fields, or when the query used NoFields.

Reading them off a result is what makes a whole-collection query one round trip rather than an FGet per field per object.

func (*Fields) UnmarshalJSON added in v0.2.0

func (f *Fields) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the "fields" object of a geofence notification. Tile38 writes those values as JSON — a string field arrives quoted — where the RESP search replies carry the same values as flat text. Unquoting here means a field reads the same whichever path it arrived on.

type FlushDBCmd

type FlushDBCmd struct {
	// contains filtered or unexported fields
}

FlushDBCmd builds a Tile38 FLUSHDB command.

func (*FlushDBCmd) Do

func (cmd *FlushDBCmd) Do(ctx context.Context) error

Do executes: FLUSHDB — deletes all objects and collections.

type GetCmd

type GetCmd struct {
	// contains filtered or unexported fields
}

GetCmd builds a Tile38 GET command.

func (*GetCmd) A5

func (cmd *GetCmd) A5(ctx context.Context, level int) (string, error)

A5 executes: GET collection id A5 level — returns the id of the A5 cell the object's centre falls in, which is what WithinCmd.A5 and IntersectsCmd.A5 take as their area. Requires a server built from upstream master: A5 is merged upstream but has shipped in no release tag as of 1.38.0.

func (*GetCmd) Bounds

func (cmd *GetCmd) Bounds(ctx context.Context) (BoundsResult, error)

Bounds executes: GET collection id BOUNDS — returns the bounding box of the object.

func (*GetCmd) Fields added in v0.2.0

func (cmd *GetCmd) Fields() Fields

Fields returns the fields read by the most recent terminal. It is nil until a terminal has run, when WithFields was not chained, or when the object has no non-zero fields — Tile38 omits the fields element entirely in that case.

func (*GetCmd) Hash

func (cmd *GetCmd) Hash(ctx context.Context, precision int) (string, error)

Hash executes: GET collection id HASH precision — returns the geohash at the given precision.

func (*GetCmd) Object

func (cmd *GetCmd) Object(ctx context.Context) (string, error)

Object executes: GET collection id — returns the raw GeoJSON string.

func (*GetCmd) Point

func (cmd *GetCmd) Point(ctx context.Context) (lat, lon float64, err error)

Point executes: GET collection id POINT — returns the lat/lon of the object. Use PointZ for an object stored with a third ordinate.

func (*GetCmd) PointZ added in v0.2.0

func (cmd *GetCmd) PointZ(ctx context.Context) (lat, lon, z float64, err error)

PointZ executes: GET collection id POINT — returns the lat/lon of the object along with its third ordinate, which Tile38 appends only when it is non-zero.

func (*GetCmd) WithFields added in v0.2.0

func (cmd *GetCmd) WithFields() *GetCmd

WithFields asks for the object's fields alongside its geometry, matching Tile38's WITHFIELDS keyword. It applies to every output format; read the fields with Fields once the terminal has returned:

g := c.Get("fleet", "truck1").WithFields()
lat, lon, err := g.Point(ctx)
speed := g.Fields()["speed"]

One GET then answers what would otherwise take an FGet per field.

type HashResult added in v0.2.0

type HashResult struct {
	ID     string
	Hash   string // geohash at the precision the query asked for
	Fields Fields
}

HashResult holds a single result from a search using the HASHES output format.

type HookCmd

type HookCmd struct {
	// contains filtered or unexported fields
}

HookCmd builds a Tile38 SETHOOK command: an endpoint, a spatial trigger (Nearby/Within), optional Detect/Commands filters, and one fence area (Bounds/Circle/Object/Get, or Roam).

Methods may be chained in any order; the parts are assembled into protocol order when the command runs.

func (*HookCmd) Bounds

func (cmd *HookCmd) Bounds(swLat, swLon, neLat, neLon float64) *HookCmd

Bounds sets the fence area to a lat/lon bounding box. Pass GlobalBounds() to fence the whole world.

func (*HookCmd) Circle

func (cmd *HookCmd) Circle(lat, lon float64, radius int) *HookCmd

Circle sets the fence area to a circle with centre + radius in metres.

func (*HookCmd) Commands

func (cmd *HookCmd) Commands(commands ...Command) *HookCmd

Commands restricts the hook to events caused by the given commands.

func (*HookCmd) Detect

func (cmd *HookCmd) Detect(states ...DetectState) *HookCmd

Detect restricts the hook to the given transitions. When omitted, Tile38's default detect set applies.

func (*HookCmd) Distance added in v0.2.0

func (cmd *HookCmd) Distance() *HookCmd

Distance adds each object's distance from the fence centre to every event the fence produces, matching Tile38's DISTANCE keyword. It arrives on FenceEvent as Distance, and applies to the live fence only — a plain query reads the same value through PointsWithDistance.

func (*HookCmd) Do

func (cmd *HookCmd) Do(ctx context.Context) error

Do executes the SETHOOK command.

func (*HookCmd) EX

func (cmd *HookCmd) EX(secs int) *HookCmd

EX sets how long the hook lives before Tile38 removes it, in seconds.

func (*HookCmd) Endpoint

func (cmd *HookCmd) Endpoint(baseURL, subject string) *HookCmd

Endpoint adds a target endpoint built by joining a base URL and a subject or path with "/" — the shape NATS and HTTP endpoints take (e.g. "nats://host:4222" + "subject"). For any other scheme, or for a URL carrying query parameters, use EndpointURL.

Calling Endpoint or EndpointURL more than once registers every endpoint on the hook; Tile38 delivers each event to all of them.

func (*HookCmd) EndpointURL

func (cmd *HookCmd) EndpointURL(urls ...string) *HookCmd

EndpointURL adds target endpoints verbatim, for schemes whose URL is not a base plus a path — kafka://host:9092/topic, sqs://region/queue, grpc://host:port, or an http:// URL with a query string.

func (*HookCmd) Get

func (cmd *HookCmd) Get(collection, id string) *HookCmd

Get sets the fence area to an object already stored in Tile38.

func (*HookCmd) Hash added in v0.2.0

func (cmd *HookCmd) Hash(geohash string) *HookCmd

Hash sets the search area to the box a geohash covers, matching Tile38's HASH keyword. The shorter the hash, the larger the box.

func (*HookCmd) Intersects

func (cmd *HookCmd) Intersects(collection string) *HookCmd

Intersects selects the INTERSECTS spatial trigger, which fires on any overlap with the fence area rather than requiring full containment.

func (*HookCmd) Match

func (cmd *HookCmd) Match(pattern string) *HookCmd

Match filters the trigger collection by object ID pattern (glob-style, e.g. "org:*"), matching Tile38's MATCH keyword. It accumulates: each call adds another pattern.

func (*HookCmd) Meta

func (cmd *HookCmd) Meta(key, value string) *HookCmd

Meta attaches a key/value pair to the hook, echoed back on every event it produces. It accumulates: each call adds another pair.

func (*HookCmd) Nearby

func (cmd *HookCmd) Nearby(collection string) *HookCmd

Nearby selects the NEARBY spatial trigger. Use with Point and Radius, or with Roam.

func (*HookCmd) NoDwell

func (cmd *HookCmd) NoDwell() *HookCmd

NoDwell stops a roaming fence from re-reporting objects that stay within range between updates, matching Tile38's NODWELL keyword. It only affects Roam fences, and it is opt-in: dwelling is Tile38's own default.

func (*HookCmd) Object

func (cmd *HookCmd) Object(geojson string) *HookCmd

Object sets the fence area to an inline GeoJSON string.

func (*HookCmd) Point added in v0.2.0

func (cmd *HookCmd) Point(lat, lon float64) *HookCmd

Point sets the fence area to a point, and is the area a Nearby trigger takes: NEARBY reads "POINT lat lon meters" and rejects CIRCLE, so a hook or channel fencing on NEARBY needs this rather than Circle. Pair it with Radius.

func (*HookCmd) QuadKey added in v0.2.0

func (cmd *HookCmd) QuadKey(quadkey string) *HookCmd

QuadKey sets the search area to the tile a Bing Maps quadkey names, matching Tile38's QUADKEY keyword. Tile is the same area expressed as x/y/z.

func (*HookCmd) Radius added in v0.2.0

func (cmd *HookCmd) Radius(metres int) *HookCmd

Radius sets the trailing metres of a Point area. Named for the value it carries: Tile38 has no keyword for it, it is the last argument of "POINT lat lon meters".

func (*HookCmd) Roam

func (cmd *HookCmd) Roam(collection string, radiusM int) *HookCmd

Roam fires when objects in the trigger collection come within radiusM metres of an object in collection. Use with Nearby.

Objects that stay in range keep reporting on each update; chain NoDwell to suppress those.

func (*HookCmd) Sector added in v0.2.0

func (cmd *HookCmd) Sector(lat, lon float64, metres int, bearing1, bearing2 float64) *HookCmd

Sector sets the search area to a circular sector: a circle of radius metres centred on lat/lon, clipped to the arc between two compass bearings in degrees. Matches Tile38's SECTOR keyword, which NEARBY does not accept.

func (*HookCmd) Where

func (cmd *HookCmd) Where(expr string) *HookCmd

Where sets an optional Tile38 field expression filter.

func (*HookCmd) Within

func (cmd *HookCmd) Within(collection string) *HookCmd

Within selects the WITHIN spatial trigger. Use with any fence area.

type HookInfo

type HookInfo struct {
	Name      string            // hook or channel name
	Key       string            // collection the fence watches
	Endpoints []string          // delivery targets; "local://<name>" for channels
	Command   []string          // the fence command tokens the hook was created with
	Meta      map[string]string // the META pairs the hook was created with
}

HookInfo describes a registered hook (HOOKS) or pub/sub channel (CHANS).

type HooksCmd

type HooksCmd struct {
	// contains filtered or unexported fields
}

HooksCmd builds a Tile38 HOOKS command to list registered hooks.

func (*HooksCmd) Do

func (cmd *HooksCmd) Do(ctx context.Context) ([]HookInfo, error)

Do executes: HOOKS [pattern]

type IntersectsCmd

type IntersectsCmd struct {
	// contains filtered or unexported fields
}

IntersectsCmd builds a Tile38 INTERSECTS query. INTERSECTS finds objects whose geometry intersects the search area, whereas WITHIN requires full containment. Methods may be chained in any order; the parts are assembled into protocol order when the command runs.

func (*IntersectsCmd) A5

func (cmd *IntersectsCmd) A5(cellID string) *IntersectsCmd

A5 sets the search area to a single A5 cell's pentagon, identified by its hex cell id (A5 keyword). Requires a server built from upstream master: A5 is merged upstream but has shipped in no release tag as of 1.38.0. Tile38 accepts A5 as a search area only, not as a hook or channel fence area.

func (*IntersectsCmd) A5Cells added in v0.2.0

func (cmd *IntersectsCmd) A5Cells(ctx context.Context, level int) ([]A5Result, error)

A5Cells executes: INTERSECTS collection [opts] A5 level <area> Each result is the A5 cell a matching object's centre falls in. Named for the output rather than the keyword because A5 is already the search-area method on the builders that take one. Requires a server built from upstream master.

func (*IntersectsCmd) Bounds

func (cmd *IntersectsCmd) Bounds(swLat, swLon, neLat, neLon float64) *IntersectsCmd

Bounds sets the search area to a lat/lon bounding box (BOUNDS keyword).

func (*IntersectsCmd) Buffer added in v0.2.0

func (cmd *IntersectsCmd) Buffer(metres int) *IntersectsCmd

Buffer grows the search area by the given number of metres before matching, matching Tile38's BUFFER keyword. Tile38 can only buffer point-like areas — it answers "cannot buffer Polygon type" for a Bounds or polygon Object area, and it panics rather than answering on NEARBY, which is why NearbyCmd has no Buffer.

It is appended rather than stored: Tile38 has no duplicate guard for BUFFER, so a repeat is legal and the last one wins.

func (*IntersectsCmd) Circle

func (cmd *IntersectsCmd) Circle(lat, lon float64, radius int) *IntersectsCmd

Circle sets the search area to a circle with centre + radius in metres (CIRCLE keyword).

func (*IntersectsCmd) Clip

func (cmd *IntersectsCmd) Clip() *IntersectsCmd

Clip trims returned objects to the search area rather than returning them whole, matching Tile38's CLIP keyword.

func (*IntersectsCmd) Commands

func (cmd *IntersectsCmd) Commands(commands ...Command) *IntersectsCmd

Commands restricts a live fence to events caused by the given commands. Only meaningful with Fence.

func (*IntersectsCmd) Count

func (cmd *IntersectsCmd) Count(ctx context.Context) (int, error)

Count executes: INTERSECTS collection [opts] COUNT area

func (*IntersectsCmd) Cursor

func (cmd *IntersectsCmd) Cursor(n uint64) *IntersectsCmd

Cursor resumes a search from where a previous one stopped, matching Tile38's CURSOR keyword. Pass the value NextCursor reported. Setting it also means the caller is paging deliberately, so a truncated result no longer reports ErrTruncated. Tile38 rejects CURSOR on a fence, so Fence ignores it.

func (*IntersectsCmd) Detect

func (cmd *IntersectsCmd) Detect(states ...DetectState) *IntersectsCmd

Detect restricts a live fence to the given transitions. Only meaningful with Fence.

func (*IntersectsCmd) Distance added in v0.2.0

func (cmd *IntersectsCmd) Distance() *IntersectsCmd

Distance adds each object's distance from the fence centre to every event the fence produces, matching Tile38's DISTANCE keyword. It arrives on FenceEvent as Distance, and applies to the live fence only — a plain query reads the same value through PointsWithDistance.

func (*IntersectsCmd) Fence

func (cmd *IntersectsCmd) Fence(ctx context.Context) (*Stream, error)

Fence opens a live geofence: INTERSECTS collection [opts] FENCE [DETECT …] area. The returned Stream holds a dedicated connection and delivers events until it is closed or ctx is cancelled.

func (*IntersectsCmd) Get

func (cmd *IntersectsCmd) Get(collection, id string) *IntersectsCmd

Get sets the search area to an object already stored in Tile38 (GET keyword).

func (*IntersectsCmd) Hash added in v0.2.0

func (cmd *IntersectsCmd) Hash(geohash string) *IntersectsCmd

Hash sets the search area to the box a geohash covers, matching Tile38's HASH keyword. The shorter the hash, the larger the box.

func (*IntersectsCmd) Hashes added in v0.2.0

func (cmd *IntersectsCmd) Hashes(ctx context.Context, precision int) ([]HashResult, error)

Hashes executes: INTERSECTS collection [opts] HASHES precision <area> Each result is the geohash of a matching object's centre.

func (*IntersectsCmd) IDs

func (cmd *IntersectsCmd) IDs(ctx context.Context) ([]string, error)

IDs executes: INTERSECTS collection [opts] IDS area

func (*IntersectsCmd) Limit

func (cmd *IntersectsCmd) Limit(n int) *IntersectsCmd

Limit caps the number of results. Zero means no limit.

func (*IntersectsCmd) Match

func (cmd *IntersectsCmd) Match(pattern string) *IntersectsCmd

Match filters results by ID pattern (glob-style, e.g. "truck:*").

func (*IntersectsCmd) NextCursor

func (cmd *IntersectsCmd) NextCursor() uint64

NextCursor reports where to resume after the last executed terminal. It is non-zero only when Tile38 stopped at the limit with more objects matching.

func (*IntersectsCmd) NoFields

func (cmd *IntersectsCmd) NoFields() *IntersectsCmd

NoFields drops field values from the reply, matching Tile38's NOFIELDS keyword.

func (*IntersectsCmd) Object

func (cmd *IntersectsCmd) Object(geojson string) *IntersectsCmd

Object sets the search area to an inline GeoJSON string (OBJECT keyword).

func (*IntersectsCmd) Objects

func (cmd *IntersectsCmd) Objects(ctx context.Context) ([]SearchObject, error)

Objects executes: INTERSECTS collection [opts] OBJECTS area

func (*IntersectsCmd) Points

func (cmd *IntersectsCmd) Points(ctx context.Context) ([]NearbyResult, error)

Points executes: INTERSECTS collection [opts] POINTS area

func (*IntersectsCmd) QuadKey added in v0.2.0

func (cmd *IntersectsCmd) QuadKey(quadkey string) *IntersectsCmd

QuadKey sets the search area to the tile a Bing Maps quadkey names, matching Tile38's QUADKEY keyword. Tile is the same area expressed as x/y/z.

func (*IntersectsCmd) Rects added in v0.2.0

func (cmd *IntersectsCmd) Rects(ctx context.Context) ([]RectResult, error)

Rects executes: INTERSECTS collection [opts] BOUNDS <area> Each result is the bounding box of a matching object, lat first.

func (*IntersectsCmd) Sector added in v0.2.0

func (cmd *IntersectsCmd) Sector(lat, lon float64, metres int, bearing1, bearing2 float64) *IntersectsCmd

Sector sets the search area to a circular sector: a circle of radius metres centred on lat/lon, clipped to the arc between two compass bearings in degrees. Matches Tile38's SECTOR keyword, which NEARBY does not accept.

func (*IntersectsCmd) Sparse

func (cmd *IntersectsCmd) Sparse(depth int) *IntersectsCmd

Sparse spreads results evenly over the search area at the given depth (1-8), matching Tile38's SPARSE keyword. Tile38 rejects SPARSE combined with Limit.

func (*IntersectsCmd) Tile

func (cmd *IntersectsCmd) Tile(x, y, z int) *IntersectsCmd

Tile sets the search area to a single XYZ map tile (TILE keyword).

func (*IntersectsCmd) Where

func (cmd *IntersectsCmd) Where(expr string) *IntersectsCmd

Where sets an optional Tile38 field expression filter.

func (*IntersectsCmd) WhereEval added in v0.2.0

func (cmd *IntersectsCmd) WhereEval(script string, args ...any) *IntersectsCmd

WhereEval keeps results for which the given Lua script returns true, matching Tile38's WHEREEVAL keyword. The script sees the object's fields as FIELDS and the extra arguments as ARGV. It accumulates: each call adds another filter.

func (*IntersectsCmd) WhereEvalSha added in v0.2.0

func (cmd *IntersectsCmd) WhereEvalSha(sha string, args ...any) *IntersectsCmd

WhereEvalSha is WhereEval against a script already loaded on the server, matching Tile38's WHEREEVALSHA keyword.

func (*IntersectsCmd) WhereIn

func (cmd *IntersectsCmd) WhereIn(field string, values ...any) *IntersectsCmd

WhereIn keeps results whose field holds one of the given values, matching Tile38's WHEREIN keyword. It accumulates: each call adds another filter.

type JDelCmd

type JDelCmd struct {
	// contains filtered or unexported fields
}

JDelCmd builds a Tile38 JDEL command to delete a value at a JSON path.

func (*JDelCmd) Do

func (cmd *JDelCmd) Do(ctx context.Context) error

Do executes: JDEL collection id path

type JGetCmd

type JGetCmd struct {
	// contains filtered or unexported fields
}

JGetCmd builds a Tile38 JGET command to read a value at a JSON path.

func (*JGetCmd) Do

func (cmd *JGetCmd) Do(ctx context.Context) (string, error)

Do executes: JGET collection id path — returns the JSON value at the path.

type JSetCmd

type JSetCmd struct {
	// contains filtered or unexported fields
}

JSetCmd builds a Tile38 JSET command to set a value at a JSON path.

func (*JSetCmd) Do

func (cmd *JSetCmd) Do(ctx context.Context) error

Do executes: JSET collection id path value

type KeysCmd

type KeysCmd struct {
	// contains filtered or unexported fields
}

KeysCmd builds a Tile38 KEYS command to list collection names.

func (*KeysCmd) Do

func (cmd *KeysCmd) Do(ctx context.Context) ([]string, error)

Do executes: KEYS pattern — returns collection names matching the glob pattern.

type NearbyCmd

type NearbyCmd struct {
	// contains filtered or unexported fields
}

NearbyCmd builds a Tile38 NEARBY command. Methods may be chained in any order; the parts are assembled into protocol order when the command runs.

func (*NearbyCmd) A5Cells added in v0.2.0

func (cmd *NearbyCmd) A5Cells(ctx context.Context, level int) ([]A5Result, error)

A5Cells executes: NEARBY collection [opts] A5 level POINT lat lon radius Each result is the A5 cell a matching object's centre falls in. Named for the output rather than the keyword because A5 is already the search-area method on the builders that take one. Requires a server built from upstream master.

func (*NearbyCmd) Commands

func (cmd *NearbyCmd) Commands(commands ...Command) *NearbyCmd

Commands restricts a live fence to events caused by the given commands. Only meaningful with Fence.

func (*NearbyCmd) Count

func (cmd *NearbyCmd) Count(ctx context.Context) (int, error)

Count executes: NEARBY collection [opts] COUNT POINT lat lon radius

func (*NearbyCmd) Cursor

func (cmd *NearbyCmd) Cursor(n uint64) *NearbyCmd

Cursor resumes a search from where a previous one stopped, matching Tile38's CURSOR keyword. Pass the value NextCursor reported. Setting it also means the caller is paging deliberately, so a truncated result no longer reports ErrTruncated. Tile38 rejects CURSOR on a fence, so Fence ignores it.

func (*NearbyCmd) Detect

func (cmd *NearbyCmd) Detect(states ...DetectState) *NearbyCmd

Detect restricts a live fence to the given transitions. Only meaningful with Fence.

func (*NearbyCmd) Distance added in v0.2.0

func (cmd *NearbyCmd) Distance() *NearbyCmd

Distance adds each object's distance from the fence centre to every event the fence produces, matching Tile38's DISTANCE keyword. It arrives on FenceEvent as Distance, and applies to the live fence only — a plain query reads the same value through PointsWithDistance.

func (*NearbyCmd) Fence

func (cmd *NearbyCmd) Fence(ctx context.Context) (*Stream, error)

Fence opens a live geofence: NEARBY collection [opts] FENCE [DETECT …] POINT lat lon radius. The returned Stream holds a dedicated connection and delivers events until it is closed or ctx is cancelled.

func (*NearbyCmd) Hashes added in v0.2.0

func (cmd *NearbyCmd) Hashes(ctx context.Context, precision int) ([]HashResult, error)

Hashes executes: NEARBY collection [opts] HASHES precision POINT lat lon radius Each result is the geohash of a matching object's centre.

func (*NearbyCmd) IDs

func (cmd *NearbyCmd) IDs(ctx context.Context) ([]string, error)

IDs executes: NEARBY collection [opts] IDS POINT lat lon radius

func (*NearbyCmd) Limit

func (cmd *NearbyCmd) Limit(n int) *NearbyCmd

Limit caps the number of results. Zero means no limit.

func (*NearbyCmd) Match

func (cmd *NearbyCmd) Match(pattern string) *NearbyCmd

Match filters results by ID pattern (glob-style, e.g. "truck:*").

func (*NearbyCmd) NextCursor

func (cmd *NearbyCmd) NextCursor() uint64

NextCursor reports where to resume after the last executed terminal. It is non-zero only when Tile38 stopped at the limit with more objects matching.

func (*NearbyCmd) NoDwell

func (cmd *NearbyCmd) NoDwell() *NearbyCmd

NoDwell stops a roaming fence from re-reporting objects that stay within range between updates, matching Tile38's NODWELL keyword. It only affects Roam fences.

func (*NearbyCmd) NoFields

func (cmd *NearbyCmd) NoFields() *NearbyCmd

NoFields drops field values from the reply, matching Tile38's NOFIELDS keyword.

func (*NearbyCmd) Objects

func (cmd *NearbyCmd) Objects(ctx context.Context) ([]SearchObject, error)

Objects executes: NEARBY collection [opts] OBJECTS POINT lat lon radius

func (*NearbyCmd) Point

func (cmd *NearbyCmd) Point(lat, lon float64) *NearbyCmd

Point sets the centre coordinates.

func (*NearbyCmd) Points

func (cmd *NearbyCmd) Points(ctx context.Context) ([]NearbyResult, error)

Points executes: NEARBY collection [opts] POINTS POINT lat lon radius

func (*NearbyCmd) PointsWithDistance

func (cmd *NearbyCmd) PointsWithDistance(ctx context.Context) ([]NearbyResultWithDistance, error)

PointsWithDistance executes: NEARBY collection [opts] DISTANCE POINTS POINT lat lon radius DISTANCE is an option token, so it has to precede the output format.

func (*NearbyCmd) Radius

func (cmd *NearbyCmd) Radius(metres int) *NearbyCmd

Radius sets the search radius in metres. It applies to a Point area; a Roam area carries its own radius.

func (*NearbyCmd) Rects added in v0.2.0

func (cmd *NearbyCmd) Rects(ctx context.Context) ([]RectResult, error)

Rects executes: NEARBY collection [opts] BOUNDS POINT lat lon radius Each result is the bounding box of a matching object, lat first.

func (*NearbyCmd) Roam

func (cmd *NearbyCmd) Roam(collection string, radiusM int) *NearbyCmd

Roam turns the fence into a roaming one: it fires as objects in this collection move within radiusM metres of an object in collection. Tile38 accepts ROAM only on a live NEARBY fence, so this needs Fence — the plain query terminators will be rejected by the server.

func (*NearbyCmd) Sparse

func (cmd *NearbyCmd) Sparse(depth int) *NearbyCmd

Sparse spreads results evenly over the search area at the given depth (1-8), matching Tile38's SPARSE keyword. Tile38 rejects SPARSE combined with Limit.

func (*NearbyCmd) Where

func (cmd *NearbyCmd) Where(expr string) *NearbyCmd

Where sets an optional Tile38 field expression filter.

func (*NearbyCmd) WhereEval added in v0.2.0

func (cmd *NearbyCmd) WhereEval(script string, args ...any) *NearbyCmd

WhereEval keeps results for which the given Lua script returns true, matching Tile38's WHEREEVAL keyword. The script sees the object's fields as FIELDS and the extra arguments as ARGV. It accumulates: each call adds another filter.

func (*NearbyCmd) WhereEvalSha added in v0.2.0

func (cmd *NearbyCmd) WhereEvalSha(sha string, args ...any) *NearbyCmd

WhereEvalSha is WhereEval against a script already loaded on the server, matching Tile38's WHEREEVALSHA keyword.

func (*NearbyCmd) WhereIn

func (cmd *NearbyCmd) WhereIn(field string, values ...any) *NearbyCmd

WhereIn keeps results whose field holds one of the given values, matching Tile38's WHEREIN keyword. It accumulates: each call adds another filter.

type NearbyResult

type NearbyResult struct {
	ID  string
	Lat float64
	Lon float64
	// Z is the point's third ordinate — Tile38 stores whatever a caller put
	// there, most often an altitude. It is zero both for a two-dimensional point
	// and for a z of zero: Tile38 omits the ordinate entirely when it is zero,
	// so the two are indistinguishable on the wire.
	Z      float64
	Fields Fields
}

NearbyResult holds a single result from a Nearby or Scan query.

type NearbyResultWithDistance

type NearbyResultWithDistance struct {
	NearbyResult
	Distance float64 // metres
}

NearbyResultWithDistance extends NearbyResult with the distance from the query centre.

type Option

type Option func(*options)

Option configures a Client. Pass any number of them to New.

func WithDialTimeout

func WithDialTimeout(d time.Duration) Option

WithDialTimeout caps how long opening a connection may take. Defaults to 5s.

func WithMaxActive

func WithMaxActive(n int) Option

WithMaxActive caps how many commands may be in flight at once. Beyond that, callers wait for a slot rather than opening another connection, which is what keeps a burst of concurrent commands from opening a socket per goroutine. Zero, the default, leaves it uncapped. Streams are not counted: they hold a dedicated connection for as long as they run.

func WithMaxIdle

func WithMaxIdle(n int) Option

WithMaxIdle caps the connections kept for reuse. It bounds idle connections, not in-flight ones — use WithMaxActive to bound those. Defaults to 8.

func WithPassword

func WithPassword(password string) Option

WithPassword sends AUTH on each new connection.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets a deadline for every command. Whichever of this and the call's context expires first wins. Unset, it defaults to DefaultTimeout, so a command against a wedged server fails instead of hanging forever when the context carries no deadline of its own. Pass a negative duration to opt out and rely on the context alone.

It does not apply to streams, which have no read deadline: a quiet fence may legitimately send nothing for hours.

type PDelChanCmd

type PDelChanCmd struct {
	// contains filtered or unexported fields
}

PDelChanCmd builds a Tile38 PDELCHAN command (pattern-based channel deletion).

func (*PDelChanCmd) Do

func (cmd *PDelChanCmd) Do(ctx context.Context) error

Do executes: PDELCHAN pattern

type PDelCmd

type PDelCmd struct {
	// contains filtered or unexported fields
}

PDelCmd builds a Tile38 PDEL command to delete objects matching a glob pattern.

func (*PDelCmd) Do

func (cmd *PDelCmd) Do(ctx context.Context) error

Do executes: PDEL collection pattern

type PDelHookCmd

type PDelHookCmd struct {
	// contains filtered or unexported fields
}

PDelHookCmd builds a Tile38 PDELHOOK command (pattern-based hook deletion).

func (*PDelHookCmd) Do

func (cmd *PDelHookCmd) Do(ctx context.Context) error

Do executes: PDELHOOK pattern

type PersistCmd

type PersistCmd struct {
	// contains filtered or unexported fields
}

PersistCmd builds a Tile38 PERSIST command to remove the TTL from an object.

func (*PersistCmd) Do

func (cmd *PersistCmd) Do(ctx context.Context) error

Do executes: PERSIST collection id

type Pipeline

type Pipeline struct {
	// contains filtered or unexported fields
}

Pipeline batches SET commands and executes them in a single round trip. It is not safe for concurrent use.

func (*Pipeline) Flush

func (p *Pipeline) Flush(ctx context.Context) error

Flush writes all queued commands in one batch, reads every reply, and resets the pipeline. It returns the first command error encountered.

func (*Pipeline) Len

func (p *Pipeline) Len() int

Len reports how many commands are queued.

func (*Pipeline) Set

func (p *Pipeline) Set(collection, id string) *PipelineSetCmd

Set returns a PipelineSetCmd. Chain modifiers then call Queue to enqueue.

type PipelineSetCmd

type PipelineSetCmd struct {
	// contains filtered or unexported fields
}

PipelineSetCmd is a deferred SET command queued onto a Pipeline. Chain modifiers then call Queue to enqueue.

func (*PipelineSetCmd) EX

func (cmd *PipelineSetCmd) EX(secs int) *PipelineSetCmd

EX sets the expiry in seconds, matching Tile38's EX keyword. Zero means no expiry.

func (*PipelineSetCmd) Field

func (cmd *PipelineSetCmd) Field(name string, value any) *PipelineSetCmd

Field appends a single named field to the SET command.

func (*PipelineSetCmd) Fields

func (cmd *PipelineSetCmd) Fields(fields ...field) *PipelineSetCmd

Fields appends multiple named fields to the SET command in one call.

func (*PipelineSetCmd) Point

func (cmd *PipelineSetCmd) Point(lat, lon float64) *PipelineSetCmd

Point sets the POINT coordinates.

func (*PipelineSetCmd) PointZ added in v0.2.0

func (cmd *PipelineSetCmd) PointZ(lat, lon, z float64) *PipelineSetCmd

PointZ sets the POINT coordinates with a third ordinate. See SetCmd.PointZ.

func (*PipelineSetCmd) Queue

func (cmd *PipelineSetCmd) Queue()

Queue enqueues the command onto the pipeline. Context is supplied at Flush.

type RectResult added in v0.2.0

type RectResult struct {
	ID     string
	Bounds BoundsResult
	Fields Fields
}

RectResult holds a single result from a search using the BOUNDS output format.

type RenameCmd

type RenameCmd struct {
	// contains filtered or unexported fields
}

RenameCmd builds a Tile38 RENAME command.

func (*RenameCmd) Do

func (cmd *RenameCmd) Do(ctx context.Context) error

Do executes: RENAME collection newCollection (or RENAMENX after calling NX)

func (*RenameCmd) NX

func (cmd *RenameCmd) NX() *RenameCmd

NX switches the command to RENAMENX, which only renames if the destination does not exist.

type ScanCmd

type ScanCmd struct {
	// contains filtered or unexported fields
}

ScanCmd builds a Tile38 SCAN command.

func (*ScanCmd) A5Cells added in v0.2.0

func (cmd *ScanCmd) A5Cells(ctx context.Context, level int) ([]A5Result, error)

A5Cells executes: SCAN collection [opts] A5 level Each result is the A5 cell a matching object's centre falls in. Named for the output rather than the keyword because A5 is already the search-area method on the builders that take one. Requires a server built from upstream master.

func (*ScanCmd) Asc added in v0.2.0

func (cmd *ScanCmd) Asc() *ScanCmd

Asc returns results in ascending ID order, matching Tile38's ASC keyword. Only SCAN and SEARCH take an order — the spatial verbs answer "ASC is not allowed for NEARBY". Asc and Desc overwrite each other: Tile38 rejects a command carrying both.

func (*ScanCmd) Count

func (cmd *ScanCmd) Count(ctx context.Context) (int, error)

Count executes: SCAN collection [opts] COUNT

func (*ScanCmd) Cursor

func (cmd *ScanCmd) Cursor(n uint64) *ScanCmd

Cursor resumes a search from where a previous one stopped, matching Tile38's CURSOR keyword. Pass the value NextCursor reported. Setting it also means the caller is paging deliberately, so a truncated result no longer reports ErrTruncated. Tile38 rejects CURSOR on a fence, so Fence ignores it.

func (*ScanCmd) Desc added in v0.2.0

func (cmd *ScanCmd) Desc() *ScanCmd

Desc returns results in descending ID order, matching Tile38's DESC keyword. See Asc for why it is single-use.

func (*ScanCmd) Hashes added in v0.2.0

func (cmd *ScanCmd) Hashes(ctx context.Context, precision int) ([]HashResult, error)

Hashes executes: SCAN collection [opts] HASHES precision Each result is the geohash of a matching object's centre.

func (*ScanCmd) IDs

func (cmd *ScanCmd) IDs(ctx context.Context) ([]string, error)

IDs executes: SCAN collection [opts] IDS

func (*ScanCmd) Limit

func (cmd *ScanCmd) Limit(n int) *ScanCmd

Limit caps the number of results. Zero means no limit.

func (*ScanCmd) Match

func (cmd *ScanCmd) Match(pattern string) *ScanCmd

Match filters results by ID pattern (glob-style, e.g. "truck:*").

func (*ScanCmd) NextCursor

func (cmd *ScanCmd) NextCursor() uint64

NextCursor reports where to resume after the last executed terminal. It is non-zero only when Tile38 stopped at the limit with more objects matching.

func (*ScanCmd) NoFields

func (cmd *ScanCmd) NoFields() *ScanCmd

NoFields drops field values from the reply, matching Tile38's NOFIELDS keyword. SCAN takes no SPARSE — Tile38 rejects it for this command.

func (*ScanCmd) Objects

func (cmd *ScanCmd) Objects(ctx context.Context) ([]SearchObject, error)

Objects executes: SCAN collection [opts] OBJECTS

func (*ScanCmd) Points

func (cmd *ScanCmd) Points(ctx context.Context) ([]NearbyResult, error)

Points executes: SCAN collection [opts] POINTS

func (*ScanCmd) Rects added in v0.2.0

func (cmd *ScanCmd) Rects(ctx context.Context) ([]RectResult, error)

Rects executes: SCAN collection [opts] BOUNDS Each result is the bounding box of a matching object, lat first.

func (*ScanCmd) Where

func (cmd *ScanCmd) Where(expr string) *ScanCmd

Where sets an optional Tile38 field expression filter.

func (*ScanCmd) WhereEval added in v0.2.0

func (cmd *ScanCmd) WhereEval(script string, args ...any) *ScanCmd

WhereEval keeps results for which the given Lua script returns true, matching Tile38's WHEREEVAL keyword. The script sees the object's fields as FIELDS and the extra arguments as ARGV. It accumulates: each call adds another filter.

func (*ScanCmd) WhereEvalSha added in v0.2.0

func (cmd *ScanCmd) WhereEvalSha(sha string, args ...any) *ScanCmd

WhereEvalSha is WhereEval against a script already loaded on the server, matching Tile38's WHEREEVALSHA keyword.

func (*ScanCmd) WhereIn

func (cmd *ScanCmd) WhereIn(field string, values ...any) *ScanCmd

WhereIn keeps results whose field holds one of the given values, matching Tile38's WHEREIN keyword. It accumulates: each call adds another filter.

type SearchCmd added in v0.2.0

type SearchCmd struct {
	// contains filtered or unexported fields
}

SearchCmd builds a Tile38 SEARCH command, which matches on the string values "SET … STRING" stores rather than on geometry. It takes no area and no fence.

func (*SearchCmd) Asc added in v0.2.0

func (cmd *SearchCmd) Asc() *SearchCmd

Asc returns results in ascending order, matching Tile38's ASC keyword. Asc and Desc overwrite each other: Tile38 rejects a command carrying both.

func (*SearchCmd) Count added in v0.2.0

func (cmd *SearchCmd) Count(ctx context.Context) (int, error)

Count executes: SEARCH collection [opts] COUNT

func (*SearchCmd) Cursor added in v0.2.0

func (cmd *SearchCmd) Cursor(n uint64) *SearchCmd

Cursor resumes a search from where a previous one stopped, matching Tile38's CURSOR keyword. Pass the value NextCursor reported.

func (*SearchCmd) Desc added in v0.2.0

func (cmd *SearchCmd) Desc() *SearchCmd

Desc returns results in descending order, matching Tile38's DESC keyword.

func (*SearchCmd) IDs added in v0.2.0

func (cmd *SearchCmd) IDs(ctx context.Context) ([]string, error)

IDs executes: SEARCH collection [opts] IDS

func (*SearchCmd) Limit added in v0.2.0

func (cmd *SearchCmd) Limit(n int) *SearchCmd

Limit caps the number of results. Zero means no limit.

func (*SearchCmd) Match added in v0.2.0

func (cmd *SearchCmd) Match(pattern string) *SearchCmd

Match filters results by string value (glob-style, e.g. "*hello*"), matching Tile38's MATCH keyword. It accumulates: each call adds another pattern.

func (*SearchCmd) NextCursor added in v0.2.0

func (cmd *SearchCmd) NextCursor() uint64

NextCursor reports where to resume after the last executed terminal. It is non-zero only when Tile38 stopped at the limit with more objects matching.

func (*SearchCmd) NoFields added in v0.2.0

func (cmd *SearchCmd) NoFields() *SearchCmd

NoFields drops field values from the reply, matching Tile38's NOFIELDS keyword.

func (*SearchCmd) Strings added in v0.2.0

func (cmd *SearchCmd) Strings(ctx context.Context) ([]StringObject, error)

Strings executes: SEARCH collection [opts] — the default output, which pairs each id with the string value that matched. Tile38 has no keyword for it, so the method is named for what it returns.

func (*SearchCmd) Where added in v0.2.0

func (cmd *SearchCmd) Where(expr string) *SearchCmd

Where sets an optional Tile38 field expression filter.

func (*SearchCmd) WhereEval added in v0.2.0

func (cmd *SearchCmd) WhereEval(script string, args ...any) *SearchCmd

WhereEval keeps results for which the given Lua script returns true, matching Tile38's WHEREEVAL keyword. It accumulates: each call adds another filter.

func (*SearchCmd) WhereEvalSha added in v0.2.0

func (cmd *SearchCmd) WhereEvalSha(sha string, args ...any) *SearchCmd

WhereEvalSha is WhereEval against a script already loaded on the server, matching Tile38's WHEREEVALSHA keyword.

func (*SearchCmd) WhereIn added in v0.2.0

func (cmd *SearchCmd) WhereIn(field string, values ...any) *SearchCmd

WhereIn keeps results whose field holds one of the given values, matching Tile38's WHEREIN keyword. It accumulates: each call adds another filter.

type SearchObject

type SearchObject struct {
	ID      string
	GeoJSON string
	Fields  Fields
}

SearchObject holds a single result from a search query using the OBJECTS output format.

type ServerError

type ServerError = resp.Error

ServerError is an error reply from Tile38 ("-ERR ..."). It means the command was rejected, not that the connection broke.

type SetChanCmd

type SetChanCmd struct {
	// contains filtered or unexported fields
}

SetChanCmd builds a Tile38 SETCHAN command for a pub/sub geofence channel. SETCHAN is identical to SETHOOK but broadcasts events to Subscribe clients instead of pushing to an endpoint URL: a spatial trigger (Nearby/Within), optional Detect/Commands filters, and one fence area.

Methods may be chained in any order; the parts are assembled into protocol order when the command runs.

func (*SetChanCmd) Bounds

func (cmd *SetChanCmd) Bounds(swLat, swLon, neLat, neLon float64) *SetChanCmd

Bounds sets the fence area to a lat/lon bounding box. Pass GlobalBounds() to fence the whole world.

func (*SetChanCmd) Circle

func (cmd *SetChanCmd) Circle(lat, lon float64, radius int) *SetChanCmd

Circle sets the fence area to a circle with centre + radius in metres.

func (*SetChanCmd) Commands

func (cmd *SetChanCmd) Commands(commands ...Command) *SetChanCmd

Commands restricts the channel to events caused by the given commands.

func (*SetChanCmd) Detect

func (cmd *SetChanCmd) Detect(states ...DetectState) *SetChanCmd

Detect restricts the channel to the given transitions. When omitted, Tile38's default detect set applies.

func (*SetChanCmd) Distance added in v0.2.0

func (cmd *SetChanCmd) Distance() *SetChanCmd

Distance adds each object's distance from the fence centre to every event the fence produces, matching Tile38's DISTANCE keyword. It arrives on FenceEvent as Distance, and applies to the live fence only — a plain query reads the same value through PointsWithDistance.

func (*SetChanCmd) Do

func (cmd *SetChanCmd) Do(ctx context.Context) error

Do executes the SETCHAN command.

func (*SetChanCmd) EX

func (cmd *SetChanCmd) EX(secs int) *SetChanCmd

EX sets how long the channel lives before Tile38 removes it, in seconds.

func (*SetChanCmd) Get

func (cmd *SetChanCmd) Get(collection, id string) *SetChanCmd

Get sets the fence area to an object already stored in Tile38.

func (*SetChanCmd) Hash added in v0.2.0

func (cmd *SetChanCmd) Hash(geohash string) *SetChanCmd

Hash sets the search area to the box a geohash covers, matching Tile38's HASH keyword. The shorter the hash, the larger the box.

func (*SetChanCmd) Intersects

func (cmd *SetChanCmd) Intersects(collection string) *SetChanCmd

Intersects selects the INTERSECTS spatial trigger, which fires on any overlap with the fence area rather than requiring full containment.

func (*SetChanCmd) Meta

func (cmd *SetChanCmd) Meta(key, value string) *SetChanCmd

Meta attaches a key/value pair to the channel, echoed back on every event it produces. It accumulates: each call adds another pair.

func (*SetChanCmd) Nearby

func (cmd *SetChanCmd) Nearby(collection string) *SetChanCmd

Nearby selects the NEARBY spatial trigger. Use with Point and Radius, or with Roam.

func (*SetChanCmd) NoDwell

func (cmd *SetChanCmd) NoDwell() *SetChanCmd

NoDwell stops a roaming fence from re-reporting objects that stay within range between updates, matching Tile38's NODWELL keyword. It only affects Roam fences, and it is opt-in: dwelling is Tile38's own default.

func (*SetChanCmd) Object

func (cmd *SetChanCmd) Object(geojson string) *SetChanCmd

Object sets the fence area to an inline GeoJSON string.

func (*SetChanCmd) Point added in v0.2.0

func (cmd *SetChanCmd) Point(lat, lon float64) *SetChanCmd

Point sets the fence area to a point, and is the area a Nearby trigger takes: NEARBY reads "POINT lat lon meters" and rejects CIRCLE, so a channel fencing on NEARBY needs this rather than Circle. Pair it with Radius.

func (*SetChanCmd) QuadKey added in v0.2.0

func (cmd *SetChanCmd) QuadKey(quadkey string) *SetChanCmd

QuadKey sets the search area to the tile a Bing Maps quadkey names, matching Tile38's QUADKEY keyword. Tile is the same area expressed as x/y/z.

func (*SetChanCmd) Radius added in v0.2.0

func (cmd *SetChanCmd) Radius(metres int) *SetChanCmd

Radius sets the trailing metres of a Point area. Named for the value it carries: Tile38 has no keyword for it, it is the last argument of "POINT lat lon meters".

func (*SetChanCmd) Roam

func (cmd *SetChanCmd) Roam(collection string, radiusM int) *SetChanCmd

Roam fires when objects in the trigger collection come within radiusM metres of an object in collection. Use with Nearby.

Objects that stay in range keep reporting on each update; chain NoDwell to suppress those.

func (*SetChanCmd) Sector added in v0.2.0

func (cmd *SetChanCmd) Sector(lat, lon float64, metres int, bearing1, bearing2 float64) *SetChanCmd

Sector sets the search area to a circular sector: a circle of radius metres centred on lat/lon, clipped to the arc between two compass bearings in degrees. Matches Tile38's SECTOR keyword, which NEARBY does not accept.

func (*SetChanCmd) Where

func (cmd *SetChanCmd) Where(expr string) *SetChanCmd

Where sets an optional Tile38 field expression filter.

func (*SetChanCmd) Within

func (cmd *SetChanCmd) Within(collection string) *SetChanCmd

Within selects the WITHIN spatial trigger. Use with any fence area.

type SetCmd

type SetCmd struct {
	// contains filtered or unexported fields
}

SetCmd builds a Tile38 SET command. Ordering contract: chain TTL/NX/XX then Field/Fields then one geometry method (At/Object/Bounds/Hash/String).

func (*SetCmd) Bounds

func (cmd *SetCmd) Bounds(swLat, swLon, neLat, neLon float64) *SetCmd

Bounds stores the object as a bounding box.

func (*SetCmd) Do

func (cmd *SetCmd) Do(ctx context.Context) error

Do executes the SET command.

func (*SetCmd) EX

func (cmd *SetCmd) EX(secs int) *SetCmd

EX sets the expiry in seconds, matching Tile38's EX keyword. Zero means no expiry.

func (*SetCmd) Field

func (cmd *SetCmd) Field(name string, value any) *SetCmd

Field appends a single named field to the SET command.

func (*SetCmd) Fields

func (cmd *SetCmd) Fields(fields ...field) *SetCmd

Fields appends multiple named fields to the SET command in one call.

func (*SetCmd) Hash

func (cmd *SetCmd) Hash(geohash string) *SetCmd

Hash stores the object from a geohash string.

func (*SetCmd) NX

func (cmd *SetCmd) NX() *SetCmd

NX causes SET to be a no-op if the object already exists.

func (*SetCmd) Object

func (cmd *SetCmd) Object(geojson string) *SetCmd

Object stores a GeoJSON string as the object's geometry.

func (*SetCmd) Point

func (cmd *SetCmd) Point(lat, lon float64) *SetCmd

Point stores the object as a POINT at the given coordinates.

func (*SetCmd) PointZ added in v0.2.0

func (cmd *SetCmd) PointZ(lat, lon, z float64) *SetCmd

PointZ stores the object as a POINT carrying a third ordinate, which Tile38 keeps and hands back through PointZ and NearbyResult.Z. A z of zero is stored as a plain two-dimensional point.

func (*SetCmd) String

func (cmd *SetCmd) String(value string) *SetCmd

String stores a plain string value (non-spatial).

func (*SetCmd) XX

func (cmd *SetCmd) XX() *SetCmd

XX causes SET to be a no-op if the object does not exist.

type StatsCmd added in v0.2.0

type StatsCmd struct {
	// contains filtered or unexported fields
}

StatsCmd builds a Tile38 STATS command.

func (*StatsCmd) Do added in v0.2.0

func (cmd *StatsCmd) Do(ctx context.Context) ([]CollectionStats, error)

Do executes: STATS collection… — one CollectionStats per collection asked for, in the same order. A collection that does not exist comes back as a null element, which reads as Exists false rather than as an error.

type StatusCmd added in v0.2.0

type StatusCmd struct {
	// contains filtered or unexported fields
}

StatusCmd is a command that takes no chained options and answers with a status: its entry point fixes every argument. Commands that do take options get a type of their own, so that a builder's methods always describe what that one command accepts.

func (*StatusCmd) Do added in v0.2.0

func (cmd *StatusCmd) Do(ctx context.Context) error

Do executes the command.

type Stream

type Stream struct {
	// contains filtered or unexported fields
}

Stream is a long-lived connection that receives geofence notifications as they happen: either a live geofence opened with Fence on a search command, or a pub/sub subscription to channels registered with SETCHAN.

A Stream owns a dedicated connection and no read deadline, because a quiet fence may send nothing for hours. Stop it with Close or by cancelling the context it was created with.

A Stream is not safe for concurrent use; call Next from one goroutine.

func (*Stream) Close

func (s *Stream) Close() error

Close stops the stream and releases its connection. It is safe to call more than once, and unblocks a concurrent Next.

func (*Stream) Next

func (s *Stream) Next() (*FenceEvent, error)

Next blocks until the next event arrives. It returns io.EOF after Close, and the context error if the stream's context is cancelled. Any other error means the connection failed; the Stream is spent either way.

type StringObject added in v0.2.0

type StringObject struct {
	ID     string
	Value  string
	Fields Fields
}

StringObject holds a single result from a Search query, which matches on the string values "SET … STRING" stores rather than on geometry.

type TTLCmd

type TTLCmd struct {
	// contains filtered or unexported fields
}

TTLCmd builds a Tile38 TTL command.

func (*TTLCmd) Do

func (cmd *TTLCmd) Do(ctx context.Context) (time.Duration, error)

Do executes: TTL collection id Returns the remaining TTL as a Duration, or -1 if the object has no expiry. Returns an error if the object does not exist.

type TestCmd added in v0.2.0

type TestCmd struct {
	// contains filtered or unexported fields
}

TestCmd builds a Tile38 TEST command: a spatial comparison of two areas that touches no stored object and needs no collection.

func (*TestCmd) Clip added in v0.2.0

func (cmd *TestCmd) Clip(ctx context.Context) (bool, string, error)

Clip executes the comparison with Tile38's CLIP keyword, which also returns the first area clipped to the second as GeoJSON. It is a separate terminal because CLIP changes the reply from a bare integer to [result, geojson].

func (*TestCmd) Do added in v0.2.0

func (cmd *TestCmd) Do(ctx context.Context) (bool, error)

Do executes the comparison and reports whether it holds.

func (*TestCmd) Intersects added in v0.2.0

func (cmd *TestCmd) Intersects(area Area) *TestCmd

Intersects compares with the INTERSECTS relation: true when the two areas overlap at all.

func (*TestCmd) Within added in v0.2.0

func (cmd *TestCmd) Within(area Area) *TestCmd

Within compares with the WITHIN relation: true when the first area lies entirely inside the second.

type WithinCmd

type WithinCmd struct {
	// contains filtered or unexported fields
}

WithinCmd builds a Tile38 WITHIN query. Methods may be chained in any order; the parts are assembled into protocol order when the command runs.

func (*WithinCmd) A5

func (cmd *WithinCmd) A5(cellID string) *WithinCmd

A5 sets the search area to a single A5 cell's pentagon, identified by its hex cell id (A5 keyword). Requires a server built from upstream master: A5 is merged upstream but has shipped in no release tag as of 1.38.0. Tile38 accepts A5 as a search area only, not as a hook or channel fence area.

func (*WithinCmd) A5Cells added in v0.2.0

func (cmd *WithinCmd) A5Cells(ctx context.Context, level int) ([]A5Result, error)

A5Cells executes: WITHIN collection [opts] A5 level <area> Each result is the A5 cell a matching object's centre falls in. Named for the output rather than the keyword because A5 is already the search-area method on the builders that take one. Requires a server built from upstream master.

func (*WithinCmd) Bounds

func (cmd *WithinCmd) Bounds(swLat, swLon, neLat, neLon float64) *WithinCmd

Bounds sets the search area to a lat/lon bounding box (BOUNDS keyword).

func (*WithinCmd) Buffer added in v0.2.0

func (cmd *WithinCmd) Buffer(metres int) *WithinCmd

Buffer grows the search area by the given number of metres before matching, matching Tile38's BUFFER keyword. Tile38 can only buffer point-like areas — it answers "cannot buffer Polygon type" for a Bounds or polygon Object area, and it panics rather than answering on NEARBY, which is why NearbyCmd has no Buffer.

It is appended rather than stored: Tile38 has no duplicate guard for BUFFER, so a repeat is legal and the last one wins.

func (*WithinCmd) Circle

func (cmd *WithinCmd) Circle(lat, lon float64, radius int) *WithinCmd

Circle sets the search area to a circle with centre + radius in metres (CIRCLE keyword).

func (*WithinCmd) Clip

func (cmd *WithinCmd) Clip() *WithinCmd

Clip trims returned objects to the search area rather than returning them whole, matching Tile38's CLIP keyword.

func (*WithinCmd) Commands

func (cmd *WithinCmd) Commands(commands ...Command) *WithinCmd

Commands restricts a live fence to events caused by the given commands. Only meaningful with Fence.

func (*WithinCmd) Count

func (cmd *WithinCmd) Count(ctx context.Context) (int, error)

Count executes: WITHIN collection [opts] COUNT area

func (*WithinCmd) Cursor

func (cmd *WithinCmd) Cursor(n uint64) *WithinCmd

Cursor resumes a search from where a previous one stopped, matching Tile38's CURSOR keyword. Pass the value NextCursor reported. Setting it also means the caller is paging deliberately, so a truncated result no longer reports ErrTruncated. Tile38 rejects CURSOR on a fence, so Fence ignores it.

func (*WithinCmd) Detect

func (cmd *WithinCmd) Detect(states ...DetectState) *WithinCmd

Detect restricts a live fence to the given transitions. Only meaningful with Fence.

func (*WithinCmd) Distance added in v0.2.0

func (cmd *WithinCmd) Distance() *WithinCmd

Distance adds each object's distance from the fence centre to every event the fence produces, matching Tile38's DISTANCE keyword. It arrives on FenceEvent as Distance, and applies to the live fence only — a plain query reads the same value through PointsWithDistance.

func (*WithinCmd) Fence

func (cmd *WithinCmd) Fence(ctx context.Context) (*Stream, error)

Fence opens a live geofence: WITHIN collection [opts] FENCE [DETECT …] area. The returned Stream holds a dedicated connection and delivers events until it is closed or ctx is cancelled.

func (*WithinCmd) Get

func (cmd *WithinCmd) Get(collection, id string) *WithinCmd

Get sets the search area to an object already stored in Tile38 (GET keyword).

func (*WithinCmd) Hash added in v0.2.0

func (cmd *WithinCmd) Hash(geohash string) *WithinCmd

Hash sets the search area to the box a geohash covers, matching Tile38's HASH keyword. The shorter the hash, the larger the box.

func (*WithinCmd) Hashes added in v0.2.0

func (cmd *WithinCmd) Hashes(ctx context.Context, precision int) ([]HashResult, error)

Hashes executes: WITHIN collection [opts] HASHES precision <area> Each result is the geohash of a matching object's centre.

func (*WithinCmd) IDs

func (cmd *WithinCmd) IDs(ctx context.Context) ([]string, error)

IDs executes: WITHIN collection [opts] IDS area

func (*WithinCmd) Limit

func (cmd *WithinCmd) Limit(n int) *WithinCmd

Limit caps the number of results. Zero means no limit.

func (*WithinCmd) Match

func (cmd *WithinCmd) Match(pattern string) *WithinCmd

Match filters results by ID pattern (glob-style, e.g. "truck:*").

func (*WithinCmd) NextCursor

func (cmd *WithinCmd) NextCursor() uint64

NextCursor reports where to resume after the last executed terminal. It is non-zero only when Tile38 stopped at the limit with more objects matching.

func (*WithinCmd) NoFields

func (cmd *WithinCmd) NoFields() *WithinCmd

NoFields drops field values from the reply, matching Tile38's NOFIELDS keyword.

func (*WithinCmd) Object

func (cmd *WithinCmd) Object(geojson string) *WithinCmd

Object sets the search area to an inline GeoJSON string (OBJECT keyword).

func (*WithinCmd) Objects

func (cmd *WithinCmd) Objects(ctx context.Context) ([]SearchObject, error)

Objects executes: WITHIN collection [opts] OBJECTS area

func (*WithinCmd) Points

func (cmd *WithinCmd) Points(ctx context.Context) ([]NearbyResult, error)

Points executes: WITHIN collection [opts] POINTS area

func (*WithinCmd) QuadKey added in v0.2.0

func (cmd *WithinCmd) QuadKey(quadkey string) *WithinCmd

QuadKey sets the search area to the tile a Bing Maps quadkey names, matching Tile38's QUADKEY keyword. Tile is the same area expressed as x/y/z.

func (*WithinCmd) Rects added in v0.2.0

func (cmd *WithinCmd) Rects(ctx context.Context) ([]RectResult, error)

Rects executes: WITHIN collection [opts] BOUNDS <area> Each result is the bounding box of a matching object, lat first.

func (*WithinCmd) Sector added in v0.2.0

func (cmd *WithinCmd) Sector(lat, lon float64, metres int, bearing1, bearing2 float64) *WithinCmd

Sector sets the search area to a circular sector: a circle of radius metres centred on lat/lon, clipped to the arc between two compass bearings in degrees. Matches Tile38's SECTOR keyword, which NEARBY does not accept.

func (*WithinCmd) Sparse

func (cmd *WithinCmd) Sparse(depth int) *WithinCmd

Sparse spreads results evenly over the search area at the given depth (1-8), matching Tile38's SPARSE keyword. Tile38 rejects SPARSE combined with Limit.

func (*WithinCmd) Tile

func (cmd *WithinCmd) Tile(x, y, z int) *WithinCmd

Tile sets the search area to a single XYZ map tile (TILE keyword).

func (*WithinCmd) Where

func (cmd *WithinCmd) Where(expr string) *WithinCmd

Where sets an optional Tile38 field expression filter.

func (*WithinCmd) WhereEval added in v0.2.0

func (cmd *WithinCmd) WhereEval(script string, args ...any) *WithinCmd

WhereEval keeps results for which the given Lua script returns true, matching Tile38's WHEREEVAL keyword. The script sees the object's fields as FIELDS and the extra arguments as ARGV. It accumulates: each call adds another filter.

func (*WithinCmd) WhereEvalSha added in v0.2.0

func (cmd *WithinCmd) WhereEvalSha(sha string, args ...any) *WithinCmd

WhereEvalSha is WhereEval against a script already loaded on the server, matching Tile38's WHEREEVALSHA keyword.

func (*WithinCmd) WhereIn

func (cmd *WithinCmd) WhereIn(field string, values ...any) *WithinCmd

WhereIn keeps results whose field holds one of the given values, matching Tile38's WHEREIN keyword. It accumulates: each call adds another filter.

Directories

Path Synopsis
internal
conn
Package conn holds the Tile38 transport: a single connection, and a pool of idle ones for request/response commands.
Package conn holds the Tile38 transport: a single connection, and a pool of idle ones for request/response commands.
resp
Package resp implements the subset of the Redis serialization protocol that Tile38 speaks: commands out as arrays of bulk strings, replies in as strings, integers, arrays, and nulls.
Package resp implements the subset of the Redis serialization protocol that Tile38 speaks: commands out as arrays of bulk strings, replies in as strings, integers, arrays, and nulls.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL