convex
Version:
Client for the Convex Cloud
195 lines (194 loc) • 5.13 kB
JavaScript
"use strict";
import { jsonToConvex } from "../../values/index.js";
import { performAsyncSyscall, performSyscall } from "./syscall.js";
import {
filterBuilderImpl,
serializeExpression
} from "./filter_builder_impl.js";
import {
IndexRangeBuilderImpl
} from "./index_range_builder_impl.js";
export class QueryInitializerImpl {
constructor(tableName) {
this.tableName = tableName;
}
withIndex(indexName, indexRange) {
const rangeBuilder = indexRange(IndexRangeBuilderImpl.new());
return new QueryImpl({
source: {
type: "IndexRange",
indexName: this.tableName + "." + indexName,
range: rangeBuilder.export(),
order: "asc"
},
operators: []
});
}
fullTableScan() {
return new QueryImpl({
source: {
type: "FullTableScan",
tableName: this.tableName,
order: "asc"
},
operators: []
});
}
order(order) {
return this.fullTableScan().order(order);
}
async count() {
const syscallJSON = await performAsyncSyscall("count", {
table: this.tableName
});
const syscallResult = jsonToConvex(syscallJSON);
return syscallResult;
}
filter(predicate) {
return this.fullTableScan().filter(predicate);
}
limit(n) {
return this.fullTableScan().limit(n);
}
collect() {
return this.fullTableScan().collect();
}
take(n) {
return this.fullTableScan().take(n);
}
paginate(options) {
return this.fullTableScan().paginate(options);
}
first() {
return this.fullTableScan().first();
}
unique() {
return this.fullTableScan().unique();
}
[Symbol.asyncIterator]() {
return this.fullTableScan()[Symbol.asyncIterator]();
}
}
function throwClosedError(type) {
throw new Error(
type === "consumed" ? "This query is closed and can't emit any more values." : "This query has been chained with another operator and can't be reused."
);
}
class QueryImpl {
constructor(query) {
this.state = { type: "preparing", query };
}
takeQuery() {
if (this.state.type !== "preparing") {
throw new Error(
"A query can only be chained once and can't be chained after iteration begins."
);
}
const query = this.state.query;
this.state = { type: "closed" };
return query;
}
startQuery() {
if (this.state.type === "executing") {
throw new Error("Iteration can only begin on a query once.");
}
if (this.state.type === "closed" || this.state.type === "consumed") {
throwClosedError(this.state.type);
}
const query = this.state.query;
const { queryId } = performSyscall("queryStream", { query });
this.state = { type: "executing", queryId };
return queryId;
}
closeQuery() {
if (this.state.type === "executing") {
const queryId = this.state.queryId;
performSyscall("queryCleanup", { queryId });
}
this.state = { type: "consumed" };
}
order(order) {
const query = this.takeQuery();
query.source.order = order;
return new QueryImpl(query);
}
filter(predicate) {
const query = this.takeQuery();
query.operators.push({
filter: serializeExpression(predicate(filterBuilderImpl))
});
return new QueryImpl(query);
}
limit(n) {
const query = this.takeQuery();
query.operators.push({ limit: n });
return new QueryImpl(query);
}
[Symbol.asyncIterator]() {
this.startQuery();
return this;
}
async next() {
if (this.state.type === "closed" || this.state.type === "consumed") {
throwClosedError(this.state.type);
}
const queryId = this.state.type === "preparing" ? this.startQuery() : this.state.queryId;
const { value, done } = await performAsyncSyscall("queryStreamNext", {
queryId
});
if (done) {
this.closeQuery();
}
const convexValue = jsonToConvex(value);
return { value: convexValue, done };
}
return() {
this.closeQuery();
return Promise.resolve({ done: true, value: void 0 });
}
async paginate(options) {
const query = this.takeQuery();
const pageSize = options.numItems;
const cursor = options.cursor;
const maximumRowsRead = options.maximumRowsRead ?? null;
const { page, isDone, continueCursor } = await performAsyncSyscall(
"queryPage",
{
query,
cursor,
pageSize,
maximumRowsRead
}
);
return {
page: page.map(jsonToConvex),
isDone,
continueCursor
};
}
async collect() {
const out = [];
for await (const item of this) {
out.push(item);
}
return out;
}
async take(n) {
return this.limit(n).collect();
}
async first() {
const first_array = await this.take(1);
return first_array.length === 0 ? null : first_array[0];
}
async unique() {
const first_two_array = await this.take(2);
if (first_two_array.length === 0) {
return null;
}
if (first_two_array.length === 2) {
throw new Error("unique() query returned more than one result");
}
return first_two_array[0];
}
}
//# sourceMappingURL=query_impl.js.map