Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Test and lint
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

on:
push:
branches: [main]
pull_request:
branches: ["**"]

jobs:
check:
name: Test and lint
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Node setup
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
with:
cache-dependency-path: package.json
node-version: "20.x"
cache: "npm"

- name: Install and build
run: |
npm i
npm run build
- name: Publish package for testing branch
run: npx pkg-pr-new publish || echo "Have you set up pkg-pr-new for this repo?"
- name: Test
run: |
npm run test
npm run typecheck
npm run lint
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ dist-ssr
explorations
node_modules
.eslintcache
# components are libraries!
.package-lock.json

# this is a package-json-redirect stub dir, see https://github.com/andrewbranch/example-subpath-exports-ts-compat?tab=readme-ov-file
frontend/package.json
# npm pack output
*.tgz
*.tsbuildinfo
7 changes: 0 additions & 7 deletions .prettierrc

This file was deleted.

5 changes: 4 additions & 1 deletion .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
{}
{
"trailingComma": "all",
"proseWrap": "always"
}
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changelog

## 0.2.0

- Adds /test and /\_generated/component.js entrypoints
- Drops commonjs support
- Improves source mapping for generated files
- Changes to a statically generated component API
40 changes: 40 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Developing guide

## Running locally

```sh
npm i
npm run dev
```

## Testing

```sh
npm run clean
npm run build
npm run typecheck
npm run lint
npm run test
```

## Deploying

### Building a one-off package

```sh
npm run clean
npm ci
npm pack
```

### Deploying a new version

```sh
npm run release
```

or for alpha release:

```sh
npm run alpha
```
91 changes: 56 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,31 @@

<!-- START: Include on https://convex.dev/components -->

This component adds a geospatial index to Convex, allowing you to efficiently store and query points on the Earth's surface.
This component adds a geospatial index to Convex, allowing you to efficiently
store and query points on the Earth's surface.

- Insert points into the geospatial key value store along with their geographic coordinates.
- Insert points into the geospatial key value store along with their geographic
coordinates.
- Efficiently query for all points within a given rectangle on the sphere.
- Control the sort order for the results with a custom sorting key.
- Filter query results with equality and `IN` clauses.
- And since it's built on Convex, everything is automatically consistent, reactive, and cached!
- And since it's built on Convex, everything is automatically consistent,
reactive, and cached!

This component is currently in beta. It's missing some functionality, but what's there should work. We've tested the example
app up to about 1,000,000 points, so reach out if you're using a much larger dataset.
If you find a bug or have a feature request, you can [file it here](https://github.com/get-convex/geospatial/issues).
This component is currently in beta. It's missing some functionality, but what's
there should work. We've tested the example app up to about 1,000,000 points, so
reach out if you're using a much larger dataset. If you find a bug or have a
feature request, you can
[file it here](https://github.com/get-convex/geospatial/issues).

## Pre-requisite: Convex

You'll need an existing Convex project to use the component.
Convex is a hosted backend platform, including a database, serverless functions,
and a ton more you can learn about [here](https://docs.convex.dev/get-started).
You'll need an existing Convex project to use the component. Convex is a hosted
backend platform, including a database, serverless functions, and a ton more you
can learn about [here](https://docs.convex.dev/get-started).

Run `npm create convex` or follow any of the [quickstarts](https://docs.convex.dev/home) to set one up.
Run `npm create convex` or follow any of the
[quickstarts](https://docs.convex.dev/home) to set one up.

## Installation

Expand All @@ -34,11 +40,12 @@ First, add `@convex-dev/geospatial` to your Convex project:
npm install @convex-dev/geospatial
```

Then, install the component into your Convex project within the `convex/convex.config.ts` file:
Then, install the component into your Convex project within the
`convex/convex.config.ts` file:

```ts
// convex/convex.config.ts
import geospatial from "@convex-dev/geospatial/convex.config";
import geospatial from "@convex-dev/geospatial/convex.config.js";
import { defineApp } from "convex/server";

const app = defineApp();
Expand All @@ -47,7 +54,8 @@ app.use(geospatial);
export default app;
```

Finally, create a new `GeospatialIndex` within your `convex/` folder, and point it to the installed component:
Finally, create a new `GeospatialIndex` within your `convex/` folder, and point
it to the installed component:

```ts
// convex/index.ts
Expand All @@ -59,9 +67,10 @@ const geospatial = new GeospatialIndex(components.geospatial);

## Inserting points

After installing the component, you can `insert`, `get`, and `remove` points from the index. You can specify
a `filterKeys` record for filtering at query time and optionally a `sortKey` for the query result order. We
currently only support ascending order on the `sortKey`.
After installing the component, you can `insert`, `get`, and `remove` points
from the index. You can specify a `filterKeys` record for filtering at query
time and optionally a `sortKey` for the query result order. We currently only
support ascending order on the `sortKey`.

```ts
// convex/index.ts
Expand All @@ -85,9 +94,11 @@ const example = mutation({
});
```

If you would like some more typesafety, you can specify a type argument for the `GeospatialIndex` class. This
will also provide you with auto-complete for the `filterKeys` and `sortKey` parameters.
Above the key was "American Museum of Natural History" but most commonly the `key` will be an ID in another table of yours.
If you would like some more typesafety, you can specify a type argument for the
`GeospatialIndex` class. This will also provide you with auto-complete for the
`filterKeys` and `sortKey` parameters. Above the key was "American Museum of
Natural History" but most commonly the `key` will be an ID in another table of
yours.

```ts
// convex/index.ts
Expand Down Expand Up @@ -125,13 +136,13 @@ const example = query({
});
```

This query will find all points that lie within the query rectangle, sort them in ascending
`sortKey` order, and return at most 16 results.
This query will find all points that lie within the query rectangle, sort them
in ascending `sortKey` order, and return at most 16 results.

You can optionally add filter conditions to queries.

The first type of filter condition is an `in()` filter, which requires that a matching
document have a filter field with a value in a specified set.
The first type of filter condition is an `in()` filter, which requires that a
matching document have a filter field with a value in a specified set.

```ts
// convex/index.ts
Expand All @@ -153,8 +164,8 @@ const example = query({
});
```

The second type of filter condition is an `eq()` filter, which requires that a matching
document have a filter field with a value equal to a specified value.
The second type of filter condition is an `eq()` filter, which requires that a
matching document have a filter field with a value equal to a specified value.

```ts
// convex/index.ts
Expand All @@ -170,7 +181,9 @@ const example = query({
});
```

The final type of filter condition allows you to specify ranges over the `sortKey`. We currently only support (optional) inclusive lower bounds and exclusive upper bounds.
The final type of filter condition allows you to specify ranges over the
`sortKey`. We currently only support (optional) inclusive lower bounds and
exclusive upper bounds.

```ts
// convex/index.ts
Expand All @@ -192,10 +205,13 @@ const example = query({
});
```

Queries take in a `limit`, which bounds the maximum number of rows returned. If this limit is hit,
the query will return a `nextCursor` for continuation. The query may also return a `nextCursor` with fewer than `limit` results if it runs out of its IO budget while executing.
Queries take in a `limit`, which bounds the maximum number of rows returned. If
this limit is hit, the query will return a `nextCursor` for continuation. The
query may also return a `nextCursor` with fewer than `limit` results if it runs
out of its IO budget while executing.

In either case, you can continue the stream by passing `nextCursor` to the next call's `cursor` parameter.
In either case, you can continue the stream by passing `nextCursor` to the next
call's `cursor` parameter.

```ts
// convex/index.ts
Expand Down Expand Up @@ -234,11 +250,13 @@ const example = query({
});
```

**Note: you typically pass the `nextCursor` in from a client that is paginating through results, to avoid loading too much data in a single query.**
**Note: you typically pass the `nextCursor` in from a client that is paginating
through results, to avoid loading too much data in a single query.**

## Querying the points nearest a query point

You can also query for the points closest to a given point, optionally limiting to a maximum distance (in meters).
You can also query for the points closest to a given point, optionally limiting
to a maximum distance (in meters).

```ts
// convex/index.ts
Expand All @@ -258,11 +276,13 @@ const example = query({
});
```

The `maxDistance` parameter is optional, but providing it can greatly speed up searching the index.
The `maxDistance` parameter is optional, but providing it can greatly speed up
searching the index.

## Example

See [`example/`](./example/) for a full example with a [Leaflet](https://leafletjs.com/)-based frontend.
See [`example/`](./example/) for a full example with a
[Leaflet](https://leafletjs.com/)-based frontend.

## Development

Expand All @@ -275,7 +295,8 @@ npm install
npm run dev
```

The component definition is in `src/` and reflects what users of the component will install. The example app,
which is entirely independent, lives in `example/`.
The component definition is in `src/` and reflects what users of the component
will install. The example app, which is entirely independent, lives in
`example/`.

<!-- END: Include on https://convex.dev/components -->
8 changes: 0 additions & 8 deletions commonjs.json

This file was deleted.

7 changes: 7 additions & 0 deletions convex.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/convex/schemas/convex.schema.json",
"functions": "example/convex",
"codegen": {
"legacyComponentApi": false
}
}
Loading
Loading