@convex-dev/geospatial
Version:
A geospatial index for Convex
102 lines • 3.26 kB
JavaScript
import { PREFETCH_SIZE } from "../query.js";
export class Intersection {
streams;
initialized = false;
constructor(streams) {
this.streams = streams;
}
async initialize() {
if (this.initialized) {
return;
}
const sizeHintPromises = this.streams.map(async (stream) => {
return { stream, sizeHint: await stream.sizeHint() };
});
const sizeHintByStream = new Map();
for (const { stream, sizeHint } of await Promise.all(sizeHintPromises)) {
sizeHintByStream.set(stream, sizeHint);
}
this.streams.sort((a, b) => sizeHintByStream.get(a) - sizeHintByStream.get(b));
for (const stream of this.streams.slice(1)) {
stream.setPrefetch(PREFETCH_SIZE / 4);
}
await this.goToFirstDoc();
this.initialized = true;
}
async goToFirstDoc() {
if (this.streams.length === 0) {
return null;
}
const currentPromises = this.streams.map((stream) => stream.current());
const currentResults = await Promise.all(currentPromises);
let candidate = null;
for (const result of currentResults) {
if (result === null) {
this.streams = [];
return null;
}
if (candidate === null || candidate < result) {
candidate = result;
}
}
if (candidate === null) {
this.streams = [];
return null;
}
while (true) {
let restart = false;
for (const stream of this.streams) {
await stream.seek(candidate);
const seekResult = await stream.current();
if (seekResult === null) {
this.streams = [];
return null;
}
if (candidate < seekResult) {
candidate = seekResult;
restart = true;
break;
}
}
if (restart) {
continue;
}
for (const stream of this.streams) {
if ((await stream.current()) !== candidate) {
throw new Error("Internal error: stream diverged");
}
}
return candidate;
}
}
async current() {
await this.initialize();
return this.streams.length > 0 ? this.streams[0].current() : null;
}
async advance() {
await this.initialize();
if (this.streams.length === 0) {
return null;
}
await this.streams[0].advance();
return this.goToFirstDoc();
}
async seek(tuple) {
await this.initialize();
if (this.streams.length === 0) {
return;
}
this.streams[0].seek(tuple);
await this.goToFirstDoc();
}
async sizeHint() {
await this.initialize();
return this.streams.length > 0 ? this.streams[0].sizeHint() : 0;
}
setPrefetch(prefetch) {
for (const stream of this.streams) {
stream.setPrefetch(prefetch);
}
}
}
//# sourceMappingURL=intersection.js.map