UNPKG

@convex-dev/geospatial

Version:
159 lines 6.36 kB
import { point, rectangle } from "../component/types.js"; import { FilterBuilderImpl } from "./query.js"; export { point, rectangle }; if (typeof Convex === "undefined") { throw new Error("this is Convex backend code, but it's running somewhere else!"); } export const DEFAULT_MIN_LEVEL = 4; export const DEFAULT_MAX_LEVEL = 16; export const DEFAULT_MAX_CELLS = 8; export const DEFAULT_LEVEL_MOD = 2; export class GeospatialIndex { component; logLevel; minLevel; maxLevel; levelMod; maxCells; /** * Create a new geospatial index, powered by S2 and Convex. This index maps unique string keys to geographic coordinates * on the Earth's surface, with the ability to efficiently query for all keys within a given geographic area. * * @param component - The registered geospatial index from `components`. * @param options - The options to configure the index. */ constructor(component, options) { this.component = component; let DEFAULT_LOG_LEVEL = "INFO"; if (process.env.GEOSPATIAL_LOG_LEVEL) { if (!["DEBUG", "INFO", "WARN", "ERROR"].includes(process.env.GEOSPATIAL_LOG_LEVEL)) { console.warn(`Invalid log level (${process.env.GEOSPATIAL_LOG_LEVEL}), defaulting to "INFO"`); } DEFAULT_LOG_LEVEL = process.env.GEOSPATIAL_LOG_LEVEL; } this.logLevel = options?.logLevel ?? DEFAULT_LOG_LEVEL; this.minLevel = options?.minLevel ?? DEFAULT_MIN_LEVEL; this.maxLevel = options?.maxLevel ?? DEFAULT_MAX_LEVEL; this.levelMod = options?.levelMod ?? DEFAULT_LEVEL_MOD; this.maxCells = options?.maxCells ?? DEFAULT_MAX_CELLS; } /** * Insert a new key-coordinate pair into the index. * * @param ctx - The Convex mutation context. * @param key - The unique string key to associate with the coordinate. * @param coordinates - The geographic coordinate `{ latitude, longitude }` to associate with the key. * @param filterKeys - The filter keys to associate with the key. * @param sortKey - The sort key to associate with the key, defaults to a randomly generated number. */ async insert(ctx, key, coordinates, filterKeys, sortKey) { await ctx.runMutation(this.component.document.insert, { document: { key, coordinates, filterKeys, sortKey: sortKey ?? Math.random(), }, minLevel: this.minLevel, maxLevel: this.maxLevel, levelMod: this.levelMod, maxCells: this.maxCells, }); } /** * Retrieve the coordinate associated with a specific key. * * @param ctx - The Convex query context. * @param key - The unique string key to retrieve the coordinate for. * @returns - The geographic coordinate `{ latitude, longitude }` associated with the key, or `null` if the key is not found. */ async get(ctx, key) { const result = await ctx.runQuery(this.component.document.get, { key }); return result; } /** * Remove a key-coordinate pair from the index. * * @param ctx - The Convex mutation context. * @param key - The unique string key to remove from the index. * @returns - `true` if the key was found and removed, `false` otherwise. */ async remove(ctx, key) { return await ctx.runMutation(this.component.document.remove, { key, minLevel: this.minLevel, maxLevel: this.maxLevel, levelMod: this.levelMod, maxCells: this.maxCells, }); } /** * Query for keys within a given shape. * * @param ctx - The Convex query context. * @param query - The query to execute. * @param cursor - The continuation cursor to use for paginating through results. * @returns - An array of objects with the key-coordinate pairs and optionally a continuation cursor. */ async query(ctx, query, cursor = undefined) { const filterBuilder = new FilterBuilderImpl(); if (query.filter) { query.filter(filterBuilder); } const resp = await ctx.runQuery(this.component.query.execute, { query: { rectangle: query.shape.rectangle, filtering: filterBuilder.filterConditions, sorting: { interval: filterBuilder.interval ?? {} }, maxResults: query.limit ?? 64, }, cursor, minLevel: this.minLevel, maxLevel: this.maxLevel, levelMod: this.levelMod, maxCells: this.maxCells, logLevel: this.logLevel, }); return resp; } /** * Query for the nearest points to a given point. * * @param ctx - The Convex query context. * @param point - The point to query for. * @param maxResults - The maximum number of results to return. * @param maxDistance - The maximum distance to return results within in meters. * @returns - An array of objects with the key-coordinate pairs and their distance from the query point in meters. */ async queryNearest(ctx, point, maxResults, maxDistance) { const resp = await ctx.runQuery(this.component.query.nearestPoints, { point, maxDistance, maxResults, minLevel: this.minLevel, maxLevel: this.maxLevel, levelMod: this.levelMod, logLevel: this.logLevel, }); return resp; } /** * Debug the S2 cells that would be queried for a given rectangle. * * @param ctx - The Convex query context. * @param rectangle - The geographic area to query. * @param maxResolution - The maximum resolution to use when querying. * @returns - An array of S2 cell identifiers and their vertices. */ async debugCells(ctx, rectangle, maxResolution) { const resp = await ctx.runQuery(this.component.query.debugCells, { rectangle, minLevel: this.minLevel, maxLevel: maxResolution ?? this.maxLevel, levelMod: this.levelMod, maxCells: this.maxCells, }); return resp; } } //# sourceMappingURL=index.js.map