@convex-dev/geospatial
Version:
A geospatial index for Convex
55 lines • 2.02 kB
JavaScript
// Encode (sortKey: number, pointId: Id<"points">) as an order preserving string.
import * as d64 from "./d64.js";
export function encodeTupleKey(sortKey, pointId) {
const buf = new ArrayBuffer(9);
const view = new DataView(buf);
// Write `0x0D` as the header.
view.setUint8(0, 0x0d);
const littleEndian = true;
view.setFloat64(1, sortKey, littleEndian);
let sortKeyUint64 = view.getBigUint64(1, littleEndian);
// Flip all of the bits if the sign bit is set.
if ((sortKeyUint64 & (1n << 63n)) !== 0n) {
sortKeyUint64 = ~sortKeyUint64;
}
// Otherwise, just flip the sign bit.
else {
sortKeyUint64 |= 1n << 63n;
}
view.setBigUint64(1, sortKeyUint64, littleEndian);
let out = d64.encode(buf);
out += `:${pointId}`;
return out;
}
export function decodeTupleKey(key) {
const pieces = key.split(":");
if (pieces.length !== 2) {
throw new Error(`Invalid tuple key ${key}: Expected two parts separated by a colon`);
}
const [encodedSortKey, pointId] = pieces;
const buf = d64.decode(encodedSortKey);
if (buf.byteLength !== 9) {
throw new Error(`Invalid tuple key ${key}: Expected 9 bytes, got ${buf.byteLength}`);
}
const view = new DataView(buf);
if (view.getUint8(0) !== 0x0d) {
throw new Error(`Invalid tuple key ${key}: Expected header 0x0D, got ${view.getUint8(0)}`);
}
const littleEndian = true;
let encodedUint64 = view.getBigUint64(1, littleEndian);
// If the sign bit was set, just turn it off.
if ((encodedUint64 & (1n << 63n)) !== 0n) {
encodedUint64 &= ~(1n << 63n);
}
// Otherwise, flip all of the bits.
else {
encodedUint64 = ~encodedUint64;
}
view.setBigUint64(1, encodedUint64, littleEndian);
const sortKey = view.getFloat64(1, littleEndian);
return { sortKey, pointId: pointId };
}
export function encodeBound(sortKey) {
return encodeTupleKey(sortKey, "");
}
//# sourceMappingURL=tupleKey.js.map