kitcn 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial, dn as ConvexTableWithColumns, tr as ConvexTextBuilderInitial } from "../where-clause-compiler-B1weGkP4.js";
1
+ import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial, dn as ConvexTableWithColumns, tr as ConvexTextBuilderInitial } from "../where-clause-compiler-CmBz9CWA.js";
2
2
  import * as convex_values0 from "convex/values";
3
3
  import { GenericId, Infer, Value } from "convex/values";
4
4
  import { DocumentByName, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, TableNamesInDataModel } from "convex/server";
@@ -3,7 +3,7 @@ import { r as partial } from "../validators-C7LelqTN.js";
3
3
  import { i as defineAuth, n as createDisabledAuthRuntime, r as getGeneratedAuthDisabledReason, t as DEFAULT_AUTH_DEFINITION_PATH } from "../generated-contract-disabled-BXaz7JCE.js";
4
4
  import { n as createGeneratedFunctionReference, o as isQueryCtx, s as isRunMutationCtx } from "../api-entry-N3nBOlI2.js";
5
5
  import { n as customCtx, r as customMutation } from "../customFunctions-DxEEO4Dq.js";
6
- import { o as mergedStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken, y as eq } from "../query-context-CJE_hYA3.js";
6
+ import { o as mergedStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken, y as eq } from "../query-context-BzihIpnM.js";
7
7
  import { n as convex } from "../convex-plugin-BHVCqWTH.js";
8
8
  import { v } from "convex/values";
9
9
  import { internalActionGeneric, internalMutationGeneric, internalQueryGeneric, paginationOptsValidator } from "convex/server";
@@ -1,4 +1,4 @@
1
- import { $ as GenericOrmCtx$1, $n as unique, $r as endsWith, $t as ManyConfig, A as ConvexDateMode, An as ConvexRankIndexBuilder, Ar as ReturningResult, At as MigrationManifestEntry, B as ConvexBytesBuilderInitial, Bn as rankIndex, Br as OrmSchemaRelations, Bt as defineMigration, C as ConvexNumberBuilderInitial, Ci as ColumnBuilderWithTableName, Cn as RlsRole, Cr as MutationReturning, Ct as MigrationStatusArgs, D as id, Di as IsPrimaryKey, Dn as ConvexAggregateIndexBuilderOn, Dr as PaginatedResult, Dt as MigrationDoc, E as ConvexIdBuilderInitial, Ei as HasDefault, En as ConvexAggregateIndexBuilder, Er as OrderDirection, Et as MigrationDirection, F as custom, Fn as ConvexVectorIndexBuilder, Fr as unsetToken, Ft as MigrationStateMap, G as ConvexBigIntBuilder, Gn as ConvexCheckConfig, Gr as ExpressionVisitor, Gt as OrmReader$1, H as ConvexBooleanBuilder, Hn as uniqueIndex, Hr as TableName, Ht as detectMigrationDrift, I as json, In as ConvexVectorIndexBuilderOn, Ir as Brand, It as MigrationStep, J as CountBackfillChunkArgs, Jn as ConvexUniqueConstraintBuilder, Jr as LogicalExpression, Jt as RlsMode, K as ConvexBigIntBuilderInitial, Kn as ConvexForeignKeyBuilder, Kr as FieldReference, Kt as OrmWriter$1, L as objectOf, Ln as ConvexVectorIndexConfig, Lr as Columns, Lt as MigrationTableName, M as ConvexCustomBuilder, Mn as ConvexSearchIndexBuilder, Mr as UpdateSet, Mt as MigrationPlan, N as ConvexCustomBuilderInitial, Nn as ConvexSearchIndexBuilderOn, Nr as VectorQueryConfig, Nt as MigrationRunStatus, O as ConvexDateBuilder, Oi as IsUnique, On as ConvexIndexBuilder, Or as PredicateWhereIndexConfig, Ot as MigrationDocContext, P as arrayOf, Pn as ConvexSearchIndexConfig, Pr as VectorSearchProvider, Pt as MigrationSet, Q as GenericOrm$1, Qn as foreignKey, Qr as contains, Qt as ExtractTablesWithRelations, R as unionOf, Rn as aggregateIndex, Rr as OrmSchemaExtensionTables, Rt as MigrationWriteMode, S as ConvexNumberBuilder, Si as ColumnBuilderTypeConfig, Sn as rlsPolicy, Sr as MutationResult, St as MigrationRunChunkArgs, T as ConvexIdBuilder, Ti as DrizzleEntity, Tn as rlsRole, Tr as OrderByClause, Tt as MigrationDefinition, U as ConvexBooleanBuilderInitial, Un as vectorIndex, Ur as SystemFields, Ut as DatabaseWithMutations, V as bytes, Vn as searchIndex, Vr as OrmSchemaTriggers, Vt as defineMigrationSet, W as boolean, Wn as ConvexCheckBuilder, Wr as BinaryExpression, Wt as DatabaseWithQuery, X as CountBackfillStatusArgs, Xn as ConvexUniqueConstraintConfig, Xr as and, Xt as extractRelationsConfig, Y as CountBackfillKickoffArgs, Yn as ConvexUniqueConstraintBuilderOn, Yr as UnaryExpression, Yt as EdgeMetadata, Z as CreateOrmOptions, Zn as check, Zr as between, Zt as ExtractTablesFromSchema, _ as ConvexTimestampMode, _i as startsWith, _n as deletion, _r as MutationExecuteConfig, _t as OrmTriggerContext, a as requireSchemaRelations, ai as inArray, an as TablesRelationalConfig, ar as AggregateResult, at as OrmWriterCtx, b as ConvexTextEnumBuilderInitial, bi as ColumnBuilderBaseConfig, bn as RlsPolicyConfig, br as MutationPaginateConfig, bt as MigrationCancelArgs, c as TableConfigResult, ci as isNull, cn as ConvexDeletionBuilder, cr as CountConfig, ct as ScheduledMutationBatchArgs, d as OrmNotFoundError, di as lte, dn as ConvexTableWithColumns, dr as FilterOperators, dt as scheduledDeleteFactory, ei as eq, en as OneConfig, er as ConvexTextBuilder, et as OrmApiResult, f as ConvexVectorBuilder, fi as ne, fn as DiscriminatorBuilderConfig, fr as GetColumnData, ft as SchemaExtension, g as ConvexTimestampBuilderInitial, gi as or, gn as convexTable, gr as InsertValue, gt as OrmTriggerChange, h as ConvexTimestampBuilder, hi as notInArray, hn as TableConfig, hr as InferSelectModel, ht as OrmTableTriggers, i as getSchemaTriggers, ii as ilike, in as TableRelationalConfig, ir as AggregateFieldValue, it as OrmReaderCtx, j as date, jn as ConvexRankIndexBuilderOn, jr as ReturningSelection, jt as MigrationMigrateOne, k as ConvexDateBuilderInitial, ki as NotNull, kn as ConvexIndexBuilderOn, kr as ReturningAll, kt as MigrationDriftIssue, l as getTableColumns, li as like, ln as ConvexDeletionConfig, lr as CountResult, lt as scheduledMutationBatchFactory, m as vector, mi as notBetween, mn as OrmLifecycleOperation, mr as InferModelFromColumns, mt as OrmBeforeResult, n as defineSchema, ni as gt, nn as RelationsBuilderColumnBase, nr as text, nt as OrmClientWithApi$1, o as asc, oi as isFieldReference, on as defineRelations, or as BuildQueryResult, ot as ResolveOrmSchema, p as ConvexVectorBuilderInitial, pi as not, pn as OrmLifecycleChange, pr as InferInsertModel, pt as defineSchemaExtension, q as bigint, qn as ConvexForeignKeyConfig, qr as FilterExpression, qt as RlsContext, r as getSchemaRelations, ri as gte, rn as RelationsBuilderColumnConfig, rr as AggregateConfig, rt as OrmFunctions, s as desc, si as isNotNull, sn as defineRelationsPart, sr as BuildRelationResult, st as createOrm, t as WhereClauseResult, ti as fieldRef, tn as RelationsBuilder, tr as ConvexTextBuilderInitial, tt as OrmClientBase$1, u as getTableConfig, ui as lt, un as ConvexTable, ur as DBQueryConfig, ut as ScheduledDeleteArgs, v as timestamp, vi as AnyColumn, vn as discriminator, vr as MutationExecuteResult, vt as OrmTriggers, w as integer, wi as ColumnDataType, wn as RlsRoleConfig, wr as MutationRunMode, wt as MigrationAppliedState, x as textEnum, xi as ColumnBuilderRuntimeConfig, xn as RlsPolicyToOption, xr as MutationPaginatedResult, xt as MigrationRunArgs, y as ConvexTextEnumBuilder, yi as ColumnBuilder, yn as RlsPolicy, yr as MutationExecutionMode, yt as defineTriggers, z as ConvexBytesBuilder, zn as index, zr as OrmSchemaExtensions, zt as buildMigrationPlan } from "../where-clause-compiler-B1weGkP4.js";
1
+ import { $ as GenericOrmCtx$1, $n as unique, $r as endsWith, $t as ManyConfig, A as ConvexDateMode, An as ConvexRankIndexBuilder, Ar as ReturningResult, At as MigrationManifestEntry, B as ConvexBytesBuilderInitial, Bn as rankIndex, Br as OrmSchemaRelations, Bt as defineMigration, C as ConvexNumberBuilderInitial, Ci as ColumnBuilderWithTableName, Cn as RlsRole, Cr as MutationReturning, Ct as MigrationStatusArgs, D as id, Di as IsPrimaryKey, Dn as ConvexAggregateIndexBuilderOn, Dr as PaginatedResult, Dt as MigrationDoc, E as ConvexIdBuilderInitial, Ei as HasDefault, En as ConvexAggregateIndexBuilder, Er as OrderDirection, Et as MigrationDirection, F as custom, Fn as ConvexVectorIndexBuilder, Fr as unsetToken, Ft as MigrationStateMap, G as ConvexBigIntBuilder, Gn as ConvexCheckConfig, Gr as ExpressionVisitor, Gt as OrmReader$1, H as ConvexBooleanBuilder, Hn as uniqueIndex, Hr as TableName, Ht as detectMigrationDrift, I as json, In as ConvexVectorIndexBuilderOn, Ir as Brand, It as MigrationStep, J as CountBackfillChunkArgs, Jn as ConvexUniqueConstraintBuilder, Jr as LogicalExpression, Jt as RlsMode, K as ConvexBigIntBuilderInitial, Kn as ConvexForeignKeyBuilder, Kr as FieldReference, Kt as OrmWriter$1, L as objectOf, Ln as ConvexVectorIndexConfig, Lr as Columns, Lt as MigrationTableName, M as ConvexCustomBuilder, Mn as ConvexSearchIndexBuilder, Mr as UpdateSet, Mt as MigrationPlan, N as ConvexCustomBuilderInitial, Nn as ConvexSearchIndexBuilderOn, Nr as VectorQueryConfig, Nt as MigrationRunStatus, O as ConvexDateBuilder, Oi as IsUnique, On as ConvexIndexBuilder, Or as PredicateWhereIndexConfig, Ot as MigrationDocContext, P as arrayOf, Pn as ConvexSearchIndexConfig, Pr as VectorSearchProvider, Pt as MigrationSet, Q as GenericOrm$1, Qn as foreignKey, Qr as contains, Qt as ExtractTablesWithRelations, R as unionOf, Rn as aggregateIndex, Rr as OrmSchemaExtensionTables, Rt as MigrationWriteMode, S as ConvexNumberBuilder, Si as ColumnBuilderTypeConfig, Sn as rlsPolicy, Sr as MutationResult, St as MigrationRunChunkArgs, T as ConvexIdBuilder, Ti as DrizzleEntity, Tn as rlsRole, Tr as OrderByClause, Tt as MigrationDefinition, U as ConvexBooleanBuilderInitial, Un as vectorIndex, Ur as SystemFields, Ut as DatabaseWithMutations, V as bytes, Vn as searchIndex, Vr as OrmSchemaTriggers, Vt as defineMigrationSet, W as boolean, Wn as ConvexCheckBuilder, Wr as BinaryExpression, Wt as DatabaseWithQuery, X as CountBackfillStatusArgs, Xn as ConvexUniqueConstraintConfig, Xr as and, Xt as extractRelationsConfig, Y as CountBackfillKickoffArgs, Yn as ConvexUniqueConstraintBuilderOn, Yr as UnaryExpression, Yt as EdgeMetadata, Z as CreateOrmOptions, Zn as check, Zr as between, Zt as ExtractTablesFromSchema, _ as ConvexTimestampMode, _i as startsWith, _n as deletion, _r as MutationExecuteConfig, _t as OrmTriggerContext, a as requireSchemaRelations, ai as inArray, an as TablesRelationalConfig, ar as AggregateResult, at as OrmWriterCtx, b as ConvexTextEnumBuilderInitial, bi as ColumnBuilderBaseConfig, bn as RlsPolicyConfig, br as MutationPaginateConfig, bt as MigrationCancelArgs, c as TableConfigResult, ci as isNull, cn as ConvexDeletionBuilder, cr as CountConfig, ct as ScheduledMutationBatchArgs, d as OrmNotFoundError, di as lte, dn as ConvexTableWithColumns, dr as FilterOperators, dt as scheduledDeleteFactory, ei as eq, en as OneConfig, er as ConvexTextBuilder, et as OrmApiResult, f as ConvexVectorBuilder, fi as ne, fn as DiscriminatorBuilderConfig, fr as GetColumnData, ft as SchemaExtension, g as ConvexTimestampBuilderInitial, gi as or, gn as convexTable, gr as InsertValue, gt as OrmTriggerChange, h as ConvexTimestampBuilder, hi as notInArray, hn as TableConfig, hr as InferSelectModel, ht as OrmTableTriggers, i as getSchemaTriggers, ii as ilike, in as TableRelationalConfig, ir as AggregateFieldValue, it as OrmReaderCtx, j as date, jn as ConvexRankIndexBuilderOn, jr as ReturningSelection, jt as MigrationMigrateOne, k as ConvexDateBuilderInitial, ki as NotNull, kn as ConvexIndexBuilderOn, kr as ReturningAll, kt as MigrationDriftIssue, l as getTableColumns, li as like, ln as ConvexDeletionConfig, lr as CountResult, lt as scheduledMutationBatchFactory, m as vector, mi as notBetween, mn as OrmLifecycleOperation, mr as InferModelFromColumns, mt as OrmBeforeResult, n as defineSchema, ni as gt, nn as RelationsBuilderColumnBase, nr as text, nt as OrmClientWithApi$1, o as asc, oi as isFieldReference, on as defineRelations, or as BuildQueryResult, ot as ResolveOrmSchema, p as ConvexVectorBuilderInitial, pi as not, pn as OrmLifecycleChange, pr as InferInsertModel, pt as defineSchemaExtension, q as bigint, qn as ConvexForeignKeyConfig, qr as FilterExpression, qt as RlsContext, r as getSchemaRelations, ri as gte, rn as RelationsBuilderColumnConfig, rr as AggregateConfig, rt as OrmFunctions, s as desc, si as isNotNull, sn as defineRelationsPart, sr as BuildRelationResult, st as createOrm, t as WhereClauseResult, ti as fieldRef, tn as RelationsBuilder, tr as ConvexTextBuilderInitial, tt as OrmClientBase$1, u as getTableConfig, ui as lt, un as ConvexTable, ur as DBQueryConfig, ut as ScheduledDeleteArgs, v as timestamp, vi as AnyColumn, vn as discriminator, vr as MutationExecuteResult, vt as OrmTriggers, w as integer, wi as ColumnDataType, wn as RlsRoleConfig, wr as MutationRunMode, wt as MigrationAppliedState, x as textEnum, xi as ColumnBuilderRuntimeConfig, xn as RlsPolicyToOption, xr as MutationPaginatedResult, xt as MigrationRunArgs, y as ConvexTextEnumBuilder, yi as ColumnBuilder, yn as RlsPolicy, yr as MutationExecutionMode, yt as defineTriggers, z as ConvexBytesBuilder, zn as index, zr as OrmSchemaExtensions, zt as buildMigrationPlan } from "../where-clause-compiler-CmBz9CWA.js";
2
2
  import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-BhsByJeg.js";
3
3
  import { a as QueryCtxWithPreferredOrmQueryTable, i as QueryCtxWithOrmQueryTable, n as LookupByIdResultByCtx, o as getByIdWithOrmQueryFallback, r as QueryCtxWithOptionalOrmQueryTable, t as DocByCtx } from "../query-context-CNo9ffvI.js";
4
4
  import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
package/dist/orm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { A as vectorIndex, B as ConvexColumnBuilder, C as RlsPolicy, D as rankIndex, E as index, F as arrayOf, I as custom, L as json, M as createSystemFields, N as integer, O as searchIndex, P as id, R as objectOf, S as TablePolymorphic, T as aggregateIndex, V as entityKind, _ as OrmSchemaRelations, a as deletion, b as TableDeleteConfig, c as Columns, d as OrmSchemaDefinition, f as OrmSchemaExtensionRelations, g as OrmSchemaOptions, h as OrmSchemaExtensions, i as convexTable, j as text, k as uniqueIndex, l as EnableRLS, m as OrmSchemaExtensionTriggers, o as discriminator, p as OrmSchemaExtensionTables, s as Brand, t as DirectAggregate, u as OrmContext, v as OrmSchemaTriggers, w as rlsPolicy, x as TableName, y as RlsPolicies, z as unionOf } from "../runtime-DmVSOe24.js";
2
2
  import { a as pretendRequired, i as pretend, n as deprecated } from "../validators-C7LelqTN.js";
3
- import { A as like, B as or, C as gt, D as isFieldReference, E as inArray, F as not, I as notBetween, L as notIlike, M as lte, N as matchLikePattern, O as isNotNull, P as ne, R as notInArray, S as filterValuesEqual, T as ilike, V as startsWith, _ as contains, a as indexKeyWithinBounds, b as fieldRef, c as streamIndexRange, d as and, f as arrayContained, g as column, h as between, i as getIndexFields, j as lt, k as isNull, l as isUnsetToken, m as arrayOverlaps, n as EmptyStream, o as mergedStream, p as arrayContains, r as QueryStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken, v as endsWith, w as gte, x as filterValueInList, y as eq, z as notLike } from "../query-context-CJE_hYA3.js";
3
+ import { A as like, B as or, C as gt, D as isFieldReference, E as inArray, F as not, I as notBetween, L as notIlike, M as lte, N as matchLikePattern, O as isNotNull, P as ne, R as notInArray, S as filterValuesEqual, T as ilike, V as startsWith, _ as contains, a as indexKeyWithinBounds, b as fieldRef, c as streamIndexRange, d as and, f as arrayContained, g as column, h as between, i as getIndexFields, j as lt, k as isNull, l as isUnsetToken, m as arrayOverlaps, n as EmptyStream, o as mergedStream, p as arrayContains, r as QueryStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken, v as endsWith, w as gte, x as filterValueInList, y as eq, z as notLike } from "../query-context-BzihIpnM.js";
4
4
  import { compareValues, v } from "convex/values";
5
5
  import { defineSchema as defineSchema$1, internalActionGeneric, internalMutationGeneric } from "convex/server";
6
6
 
@@ -4585,6 +4585,42 @@ var BufferedQueryStream = class BufferedQueryStream extends QueryStream {
4585
4585
  return this.equalityIndexFilter;
4586
4586
  }
4587
4587
  };
4588
+ const ID_LIST_POSITION_FIELD = "__kitcn_id_list_position";
4589
+ /**
4590
+ * Reads an `id` / `id in [...]` where one document at a time, in the order the
4591
+ * ids were given.
4592
+ *
4593
+ * The index key is the position in the de-duplicated id list, so a cursor names
4594
+ * a position and `narrow` drops entries without reading them. A page reads only
4595
+ * the listed positions it visits, not every id in the list on every page.
4596
+ */
4597
+ var LazyIdListQueryStream = class LazyIdListQueryStream extends QueryStream {
4598
+ constructor(readId, entries, order) {
4599
+ super();
4600
+ this.readId = readId;
4601
+ this.entries = entries;
4602
+ this.order = order;
4603
+ }
4604
+ iterWithKeys() {
4605
+ const entries = this.entries;
4606
+ const readId = this.readId;
4607
+ return { async *[Symbol.asyncIterator]() {
4608
+ for (const [position, id] of entries) yield [await readId(id), [position]];
4609
+ } };
4610
+ }
4611
+ narrow(indexBounds) {
4612
+ return new LazyIdListQueryStream(this.readId, this.entries.filter(([position]) => indexKeyWithinBounds([position], indexBounds)), this.order);
4613
+ }
4614
+ getOrder() {
4615
+ return this.order;
4616
+ }
4617
+ getIndexFields() {
4618
+ return [ID_LIST_POSITION_FIELD];
4619
+ }
4620
+ getEqualityIndexFilter() {
4621
+ return [];
4622
+ }
4623
+ };
4588
4624
  const PIPELINE_LIMIT_ORDINAL_FIELD = "__kitcn_limit_ordinal";
4589
4625
  /** Cap a stream at its first `limit` matching documents without eager reads. */
4590
4626
  var LimitedMatchesQueryStream = class LimitedMatchesQueryStream extends QueryStream {
@@ -5787,9 +5823,12 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
5787
5823
  * The where-clause compiler is built from declared indexes only, and `_id` is
5788
5824
  * never one of them, so an `id` filter can never be index-selected: it lands
5789
5825
  * in the post-filters and the stream walks the creation-time index until it
5790
- * happens on the row. `db.get()` reads exactly the rows asked for, so the ids
5791
- * are fetched directly and replayed as a creation-time-ordered stream — the
5792
- * order the scan would have produced, so stage order and cursors are the same.
5826
+ * happens on the row. `db.get()` reads exactly the rows asked for.
5827
+ *
5828
+ * Rows come back in the order the ids were given, one read at a time. Missing
5829
+ * or policy-filtered ids still cost a read, but a page does not reread the
5830
+ * complete list. An `orderBy` on creation time is the exception: an id carries
5831
+ * no creation time, so every id must be read before the first row is placed.
5793
5832
  *
5794
5833
  * Returns null when something else already owns the read: a pinned index, an
5795
5834
  * index the compiler did select, a `where(predicate)`, or an `orderBy` that
@@ -5801,13 +5840,26 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
5801
5840
  const primaryOrder = queryConfig.order?.[0];
5802
5841
  if (primaryOrder && primaryOrder.field !== INTERNAL_CREATION_TIME_FIELD) return null;
5803
5842
  const ids = idLookup.kind === "in" ? Array.from(new Map(idLookup.ids.map((id) => [String(id), id])).values()) : [idLookup.id];
5804
- const rows = (await this._mapWithConcurrency(ids, async (id) => {
5805
- return this._getById(this.tableConfig.name, id);
5806
- })).filter((row) => !!row);
5843
+ const readId = (id) => this._getById(this.tableConfig.name, id);
5844
+ if (!primaryOrder) {
5845
+ const entries = ids.map((id, position) => [position, id]);
5846
+ if (order === "desc") entries.reverse();
5847
+ return new LazyIdListQueryStream(readId, entries, order);
5848
+ }
5849
+ const rows = (await this._mapWithConcurrency(ids, readId)).filter((row) => !!row);
5807
5850
  rows.sort((a, b) => compareValues(a[INTERNAL_CREATION_TIME_FIELD], b[INTERNAL_CREATION_TIME_FIELD]) || compareValues(a[INTERNAL_ID_FIELD], b[INTERNAL_ID_FIELD]));
5808
5851
  if (order === "desc") rows.reverse();
5809
5852
  return new BufferedQueryStream(rows.map((row) => [row, [row[INTERNAL_CREATION_TIME_FIELD], row[INTERNAL_ID_FIELD]]]), order, [INTERNAL_CREATION_TIME_FIELD, INTERNAL_ID_FIELD], []);
5810
5853
  }
5854
+ /**
5855
+ * The declared index a stream read can walk to emit `field` in order.
5856
+ *
5857
+ * A stream orders by the index it scans, so only an index that leads with
5858
+ * the field produces that order.
5859
+ */
5860
+ _findStreamOrderIndex(field) {
5861
+ return getIndexes(this.tableConfig.table).find((index) => index.fields[0] === field);
5862
+ }
5811
5863
  _buildBasePipelineStream(queryConfig, wherePredicate, configuredIndex) {
5812
5864
  const schemaDefinition = this._getSchemaDefinitionOrThrow();
5813
5865
  let streamQuery = stream(this.db, schemaDefinition).query(this.tableConfig.name);
@@ -5819,8 +5871,8 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
5819
5871
  return indexQuery;
5820
5872
  });
5821
5873
  else if (configuredIndex?.name) streamQuery = streamQuery.withIndex(configuredIndex.name, configuredIndex.range ? configuredIndex.range : (q) => q);
5822
- else if (primaryOrder && primaryOrder.field !== "_creationTime") {
5823
- const orderIndex = getIndexes(this.tableConfig.table).find((idx) => idx.fields[0] === primaryOrder.field);
5874
+ else if (primaryOrder && primaryOrder.field !== INTERNAL_CREATION_TIME_FIELD) {
5875
+ const orderIndex = this._findStreamOrderIndex(primaryOrder.field);
5824
5876
  if (orderIndex) streamQuery = streamQuery.withIndex(orderIndex.name, (q) => q);
5825
5877
  }
5826
5878
  streamQuery = streamQuery.order(primaryOrderDirection);
@@ -6978,7 +7030,11 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
6978
7030
  streamQuery = mergedStream(streams, pipeline.interleaveBy.map((field) => this._normalizePublicFieldName(field)));
6979
7031
  }
6980
7032
  } else {
6981
- if (isCursorPaginated && maxScan !== void 0 && idLookup?.kind === "in") throw new Error("An id IN pipeline cannot use maxScan because creation-order replay requires reading the complete ID list.");
7033
+ const orderedIdList = isCursorPaginated && maxScan !== void 0 && idLookup?.kind === "in" ? queryConfig.order?.[0] : void 0;
7034
+ if (orderedIdList) {
7035
+ if (orderedIdList.field === INTERNAL_CREATION_TIME_FIELD) throw new Error("An id IN pipeline cannot combine orderBy on createdAt with maxScan, because ordering an id list by creation time requires reading every id in the list. Drop maxScan, or drop orderBy to page in id-list order at one read per row.");
7036
+ if (queryConfig.order?.length !== 1 || configuredIndex?.name || queryConfig.index || !this._findStreamOrderIndex(orderedIdList.field)) throw new Error(`An id IN pipeline cannot combine orderBy on ${this._toPublicFilterFieldName(orderedIdList.field)} with maxScan, because the scan cannot produce that order. It needs a single orderBy field that an index leads with, and no index pinned by withIndex().`);
7037
+ }
6982
7038
  streamQuery = await this._buildIdLookupStream({
6983
7039
  configuredIndex,
6984
7040
  idLookup,
@@ -528,11 +528,19 @@ function getIndexFields(table, index, schema) {
528
528
  fields.push("_id");
529
529
  return fields;
530
530
  }
531
- function getIndexKey(doc, indexFields) {
531
+ /**
532
+ * Read the index key out of a document.
533
+ *
534
+ * Takes field paths already split on `.` rather than the field names: the field
535
+ * list is fixed for the life of a query, so splitting it once at `withIndex`
536
+ * time saves an array allocation per field per document pulled through the
537
+ * stream.
538
+ */
539
+ function getIndexKey(doc, indexFieldPaths) {
532
540
  const key = [];
533
- for (const field of indexFields) {
541
+ for (const path of indexFieldPaths) {
534
542
  let obj = doc;
535
- for (const subfield of field.split(".")) obj = obj[subfield];
543
+ for (const subfield of path) obj = obj[subfield];
536
544
  key.push(obj);
537
545
  }
538
546
  return key;
@@ -729,17 +737,26 @@ var QueryStream = class {
729
737
  }
730
738
  [Symbol.asyncIterator]() {
731
739
  const iterator = this.iterWithKeys()[Symbol.asyncIterator]();
732
- return { async next() {
733
- const result = await iterator.next();
734
- if (result.done) return {
735
- done: true,
736
- value: void 0
737
- };
738
- return {
739
- done: false,
740
- value: result.value[0]
741
- };
742
- } };
740
+ return {
741
+ async next() {
742
+ const result = await iterator.next();
743
+ if (result.done) return {
744
+ done: true,
745
+ value: void 0
746
+ };
747
+ return {
748
+ done: false,
749
+ value: result.value[0]
750
+ };
751
+ },
752
+ async return() {
753
+ await iterator.return?.();
754
+ return {
755
+ done: true,
756
+ value: void 0
757
+ };
758
+ }
759
+ };
743
760
  }
744
761
  };
745
762
  var StreamDatabaseReader = class {
@@ -858,6 +875,7 @@ var OrderedStreamQuery = class extends StreamableQuery {
858
875
  table: this.parent.parent.table,
859
876
  index: this.parent.index,
860
877
  indexFields: this.parent.q.indexFields,
878
+ indexFieldPaths: this.parent.q.indexFieldPaths,
861
879
  order: this.order,
862
880
  bounds: {
863
881
  lowerBound: this.parent.q.lowerBoundIndexKey ?? [],
@@ -876,7 +894,7 @@ var OrderedStreamQuery = class extends StreamableQuery {
876
894
  return db.query(table).withIndex(index, indexRange).order(order);
877
895
  }
878
896
  iterWithKeys() {
879
- const { indexFields } = this.reflect();
897
+ const { indexFieldPaths } = this.reflect();
880
898
  const iterable = this.inner();
881
899
  return { [Symbol.asyncIterator]() {
882
900
  const iterator = iterable[Symbol.asyncIterator]();
@@ -888,7 +906,7 @@ var OrderedStreamQuery = class extends StreamableQuery {
888
906
  };
889
907
  return {
890
908
  done: false,
891
- value: [result.value, getIndexKey(result.value, indexFields)]
909
+ value: [result.value, getIndexKey(result.value, indexFieldPaths)]
892
910
  };
893
911
  } };
894
912
  } };
@@ -950,8 +968,11 @@ var ReflectIndexRange = class {
950
968
  upperBoundInclusive = true;
951
969
  equalityIndexFilter = [];
952
970
  indexFields;
971
+ /** `indexFields`, each split on `.` once, for `getIndexKey`. */
972
+ indexFieldPaths;
953
973
  constructor(indexFields) {
954
974
  this.indexFields = indexFields;
975
+ this.indexFieldPaths = indexFields.map((field) => field.split("."));
955
976
  }
956
977
  eq(field, value) {
957
978
  if (!this.#canLowerBound(field) || !this.#canUpperBound(field)) throw new Error(`Cannot use eq on field '${field}'`);
@@ -1043,16 +1064,24 @@ var ReflectIndexRange = class {
1043
1064
  function mergedStream(streams, orderByIndexFields) {
1044
1065
  return new MergedStream(streams, orderByIndexFields);
1045
1066
  }
1067
+ /**
1068
+ * Marks sources that are already `OrderByStream`s, so `narrow` reuses them
1069
+ * instead of adding a redundant delegation layer per call.
1070
+ *
1071
+ * Module-private on purpose: wrapping is also where the ordering invariant is
1072
+ * checked, so no caller outside this file can skip it.
1073
+ */
1074
+ const PRE_ORDERED_STREAMS = Symbol("preOrderedStreams");
1046
1075
  var MergedStream = class MergedStream extends QueryStream {
1047
1076
  #order;
1048
1077
  #streams;
1049
1078
  #equalityIndexFilter;
1050
1079
  #indexFields;
1051
- constructor(streams, orderByIndexFields) {
1080
+ constructor(streams, orderByIndexFields, preOrdered) {
1052
1081
  super();
1053
1082
  if (streams.length === 0) throw new Error("Cannot union empty array of streams");
1054
1083
  this.#order = allSame(streams.map((stream) => stream.getOrder()), "Cannot merge streams with different orders");
1055
- this.#streams = streams.map((stream) => new OrderByStream(stream, orderByIndexFields));
1084
+ this.#streams = preOrdered === PRE_ORDERED_STREAMS ? streams : streams.map((stream) => new OrderByStream(stream, orderByIndexFields.slice()));
1056
1085
  this.#indexFields = allSame(this.#streams.map((stream) => stream.getIndexFields()), "Cannot merge streams with different index fields. Consider using .orderBy()");
1057
1086
  this.#equalityIndexFilter = commonPrefix(this.#streams.map((stream) => stream.getEqualityIndexFilter()));
1058
1087
  }
@@ -1065,40 +1094,60 @@ var MergedStream = class MergedStream extends QueryStream {
1065
1094
  done: false,
1066
1095
  value: void 0
1067
1096
  }));
1068
- return { async next() {
1069
- await Promise.all(iterators.map(async (iterator, i) => {
1070
- if (!results[i].done && !results[i].value) results[i] = await iterator.next();
1071
- }));
1072
- let minIndexKeyAndIndex;
1073
- for (let i = 0; i < results.length; i++) {
1074
- const result = results[i];
1075
- if (result.done || !result.value) continue;
1076
- const [_, resultIndexKey] = result.value;
1077
- if (minIndexKeyAndIndex === void 0) {
1078
- minIndexKeyAndIndex = [resultIndexKey, i];
1079
- continue;
1097
+ let started = false;
1098
+ let refillIndex;
1099
+ return {
1100
+ async next() {
1101
+ if (started) {
1102
+ if (refillIndex !== void 0) {
1103
+ results[refillIndex] = await iterators[refillIndex].next();
1104
+ refillIndex = void 0;
1105
+ }
1106
+ } else {
1107
+ started = true;
1108
+ await Promise.all(iterators.map(async (iterator, i) => {
1109
+ results[i] = await iterator.next();
1110
+ }));
1080
1111
  }
1081
- const [prevMin, _prevMinIndex] = minIndexKeyAndIndex;
1082
- if (compareKeys({
1083
- value: resultIndexKey,
1084
- kind: "exact"
1085
- }, {
1086
- value: prevMin,
1087
- kind: "exact"
1088
- }) * comparisonInversion < 0) minIndexKeyAndIndex = [resultIndexKey, i];
1112
+ let minIndexKeyAndIndex;
1113
+ for (let i = 0; i < results.length; i++) {
1114
+ const result = results[i];
1115
+ if (result.done || !result.value) continue;
1116
+ const [_, resultIndexKey] = result.value;
1117
+ if (minIndexKeyAndIndex === void 0) {
1118
+ minIndexKeyAndIndex = [resultIndexKey, i];
1119
+ continue;
1120
+ }
1121
+ const [prevMin, _prevMinIndex] = minIndexKeyAndIndex;
1122
+ if (compareKeys({
1123
+ value: resultIndexKey,
1124
+ kind: "exact"
1125
+ }, {
1126
+ value: prevMin,
1127
+ kind: "exact"
1128
+ }) * comparisonInversion < 0) minIndexKeyAndIndex = [resultIndexKey, i];
1129
+ }
1130
+ if (minIndexKeyAndIndex === void 0) return {
1131
+ done: true,
1132
+ value: void 0
1133
+ };
1134
+ const [_, minIndex] = minIndexKeyAndIndex;
1135
+ const result = results[minIndex].value;
1136
+ results[minIndex].value = void 0;
1137
+ refillIndex = minIndex;
1138
+ return {
1139
+ done: false,
1140
+ value: result
1141
+ };
1142
+ },
1143
+ async return() {
1144
+ await Promise.all(iterators.map((iterator) => iterator.return?.()));
1145
+ return {
1146
+ done: true,
1147
+ value: void 0
1148
+ };
1089
1149
  }
1090
- if (minIndexKeyAndIndex === void 0) return {
1091
- done: true,
1092
- value: void 0
1093
- };
1094
- const [_, minIndex] = minIndexKeyAndIndex;
1095
- const result = results[minIndex].value;
1096
- results[minIndex].value = void 0;
1097
- return {
1098
- done: false,
1099
- value: result
1100
- };
1101
- } };
1150
+ };
1102
1151
  } };
1103
1152
  }
1104
1153
  getOrder() {
@@ -1111,7 +1160,7 @@ var MergedStream = class MergedStream extends QueryStream {
1111
1160
  return this.#indexFields;
1112
1161
  }
1113
1162
  narrow(indexBounds) {
1114
- return new MergedStream(this.#streams.map((stream) => stream.narrow(indexBounds)), this.#indexFields);
1163
+ return new MergedStream(this.#streams.map((stream) => stream.narrow(indexBounds)), this.#indexFields, PRE_ORDERED_STREAMS);
1115
1164
  }
1116
1165
  };
1117
1166
  function allSame(values, errorMessage) {
@@ -1159,16 +1208,22 @@ var ConcatStreams = class ConcatStreams extends QueryStream {
1159
1208
  this.#equalityIndexFilter = commonPrefix(streams.map((stream) => stream.getEqualityIndexFilter()));
1160
1209
  }
1161
1210
  iterWithKeys() {
1162
- const iterables = this.#streams.map((stream) => stream.iterWithKeys());
1211
+ const streams = this.#streams;
1163
1212
  const comparisonInversion = this.#order === "asc" ? 1 : -1;
1164
- let previousIndexKey;
1165
1213
  return { [Symbol.asyncIterator]() {
1166
- const iterators = iterables.map((iterable) => iterable[Symbol.asyncIterator]());
1167
- return { async next() {
1168
- while (iterators.length > 0) {
1169
- const result = await iterators[0].next();
1170
- if (result.done) iterators.shift();
1171
- else {
1214
+ let index = 0;
1215
+ let iterator;
1216
+ let previousIndexKey;
1217
+ return {
1218
+ async next() {
1219
+ while (index < streams.length) {
1220
+ iterator ??= streams[index].iterWithKeys()[Symbol.asyncIterator]();
1221
+ const result = await iterator.next();
1222
+ if (result.done) {
1223
+ index++;
1224
+ iterator = void 0;
1225
+ continue;
1226
+ }
1172
1227
  const [_, indexKey] = result.value;
1173
1228
  if (previousIndexKey !== void 0 && compareKeys({
1174
1229
  value: previousIndexKey,
@@ -1180,12 +1235,21 @@ var ConcatStreams = class ConcatStreams extends QueryStream {
1180
1235
  previousIndexKey = indexKey;
1181
1236
  return result;
1182
1237
  }
1238
+ return {
1239
+ done: true,
1240
+ value: void 0
1241
+ };
1242
+ },
1243
+ async return() {
1244
+ await iterator?.return?.();
1245
+ index = streams.length;
1246
+ iterator = void 0;
1247
+ return {
1248
+ done: true,
1249
+ value: void 0
1250
+ };
1183
1251
  }
1184
- return {
1185
- done: true,
1186
- value: void 0
1187
- };
1188
- } };
1252
+ };
1189
1253
  } };
1190
1254
  }
1191
1255
  getOrder() {
@@ -1258,6 +1322,18 @@ var FlatMapStreamIterator = class {
1258
1322
  value: [u, [...this.#currentOuterItem.indexKey, ...indexKey]]
1259
1323
  };
1260
1324
  }
1325
+ async return() {
1326
+ try {
1327
+ await this.#currentOuterItem?.innerIterator.return?.();
1328
+ } finally {
1329
+ this.#currentOuterItem = null;
1330
+ await this.#outerIterator.return?.();
1331
+ }
1332
+ return {
1333
+ done: true,
1334
+ value: void 0
1335
+ };
1336
+ }
1261
1337
  };
1262
1338
  var FlatMapStream = class FlatMapStream extends QueryStream {
1263
1339
  #stream;
@@ -1477,15 +1553,24 @@ var OrderByStream = class OrderByStream extends QueryStream {
1477
1553
  const staticFilter = this.#staticFilter;
1478
1554
  return { [Symbol.asyncIterator]() {
1479
1555
  const iterator = iterable[Symbol.asyncIterator]();
1480
- return { async next() {
1481
- const result = await iterator.next();
1482
- if (result.done) return result;
1483
- const [doc, indexKey] = result.value;
1484
- return {
1485
- done: false,
1486
- value: [doc, indexKey.slice(staticFilter.length)]
1487
- };
1488
- } };
1556
+ return {
1557
+ async next() {
1558
+ const result = await iterator.next();
1559
+ if (result.done) return result;
1560
+ const [doc, indexKey] = result.value;
1561
+ return {
1562
+ done: false,
1563
+ value: [doc, indexKey.slice(staticFilter.length)]
1564
+ };
1565
+ },
1566
+ async return() {
1567
+ await iterator.return?.();
1568
+ return {
1569
+ done: true,
1570
+ value: void 0
1571
+ };
1572
+ }
1573
+ };
1489
1574
  } };
1490
1575
  }
1491
1576
  narrow(indexBounds) {
@@ -1516,36 +1601,57 @@ var DistinctStream = class DistinctStream extends QueryStream {
1516
1601
  iterWithKeys() {
1517
1602
  const stream = this.#stream;
1518
1603
  const distinctIndexFieldsLength = this.#distinctIndexFieldsLength;
1604
+ const order = stream.getOrder();
1605
+ const comparisonInversion = order === "asc" ? 1 : -1;
1519
1606
  return { [Symbol.asyncIterator]() {
1520
- let currentStream = stream;
1521
- let currentIterator = currentStream.iterWithKeys()[Symbol.asyncIterator]();
1522
- return { async next() {
1523
- const result = await currentIterator.next();
1524
- if (result.done) return {
1525
- done: true,
1526
- value: void 0
1527
- };
1528
- const [doc, indexKey] = result.value;
1529
- if (doc === null) return {
1530
- done: false,
1531
- value: [null, indexKey]
1532
- };
1533
- const distinctIndexKey = indexKey.slice(0, distinctIndexFieldsLength);
1534
- if (stream.getOrder() === "asc") currentStream = currentStream.narrow({
1535
- lowerBound: distinctIndexKey,
1536
- lowerBoundInclusive: false,
1537
- upperBound: [],
1538
- upperBoundInclusive: true
1539
- });
1540
- else currentStream = currentStream.narrow({
1541
- lowerBound: [],
1542
- lowerBoundInclusive: true,
1543
- upperBound: distinctIndexKey,
1544
- upperBoundInclusive: false
1545
- });
1546
- currentIterator = currentStream.iterWithKeys()[Symbol.asyncIterator]();
1547
- return result;
1548
- } };
1607
+ let currentIterator = stream.iterWithKeys()[Symbol.asyncIterator]();
1608
+ let previousDistinctIndexKey;
1609
+ return {
1610
+ async next() {
1611
+ const result = await currentIterator.next();
1612
+ if (result.done) return {
1613
+ done: true,
1614
+ value: void 0
1615
+ };
1616
+ const [doc, indexKey] = result.value;
1617
+ if (doc === null) return {
1618
+ done: false,
1619
+ value: [null, indexKey]
1620
+ };
1621
+ const distinctIndexKey = indexKey.slice(0, distinctIndexFieldsLength);
1622
+ if (previousDistinctIndexKey !== void 0 && compareKeys({
1623
+ value: previousDistinctIndexKey,
1624
+ kind: "exact"
1625
+ }, {
1626
+ value: distinctIndexKey,
1627
+ kind: "exact"
1628
+ }) * comparisonInversion >= 0) throw new Error(`DistinctStream in wrong order: ${JSON.stringify(previousDistinctIndexKey)}, ${JSON.stringify(distinctIndexKey)}`);
1629
+ previousDistinctIndexKey = distinctIndexKey;
1630
+ let narrowed;
1631
+ if (order === "asc") narrowed = stream.narrow({
1632
+ lowerBound: distinctIndexKey,
1633
+ lowerBoundInclusive: false,
1634
+ upperBound: [],
1635
+ upperBoundInclusive: true
1636
+ });
1637
+ else narrowed = stream.narrow({
1638
+ lowerBound: [],
1639
+ lowerBoundInclusive: true,
1640
+ upperBound: distinctIndexKey,
1641
+ upperBoundInclusive: false
1642
+ });
1643
+ await currentIterator.return?.();
1644
+ currentIterator = narrowed.iterWithKeys()[Symbol.asyncIterator]();
1645
+ return result;
1646
+ },
1647
+ async return() {
1648
+ await currentIterator.return?.();
1649
+ return {
1650
+ done: true,
1651
+ value: void 0
1652
+ };
1653
+ }
1654
+ };
1549
1655
  } };
1550
1656
  }
1551
1657
  narrow(indexBounds) {
@@ -2539,15 +2539,25 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2539
2539
  * The where-clause compiler is built from declared indexes only, and `_id` is
2540
2540
  * never one of them, so an `id` filter can never be index-selected: it lands
2541
2541
  * in the post-filters and the stream walks the creation-time index until it
2542
- * happens on the row. `db.get()` reads exactly the rows asked for, so the ids
2543
- * are fetched directly and replayed as a creation-time-ordered stream — the
2544
- * order the scan would have produced, so stage order and cursors are the same.
2542
+ * happens on the row. `db.get()` reads exactly the rows asked for.
2543
+ *
2544
+ * Rows come back in the order the ids were given, one read at a time. Missing
2545
+ * or policy-filtered ids still cost a read, but a page does not reread the
2546
+ * complete list. An `orderBy` on creation time is the exception: an id carries
2547
+ * no creation time, so every id must be read before the first row is placed.
2545
2548
  *
2546
2549
  * Returns null when something else already owns the read: a pinned index, an
2547
2550
  * index the compiler did select, a `where(predicate)`, or an `orderBy` that
2548
2551
  * walks a different index.
2549
2552
  */
2550
2553
  private _buildIdLookupStream;
2554
+ /**
2555
+ * The declared index a stream read can walk to emit `field` in order.
2556
+ *
2557
+ * A stream orders by the index it scans, so only an index that leads with
2558
+ * the field produces that order.
2559
+ */
2560
+ private _findStreamOrderIndex;
2551
2561
  private _buildBasePipelineStream;
2552
2562
  /**
2553
2563
  * Stream equivalent of the `db.query(...)` chain, used when a post-fetch
@@ -4367,6 +4377,19 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4367
4377
  readonly aggregate_state: ConvexTableWithColumns<{
4368
4378
  name: "aggregate_state";
4369
4379
  columns: {
4380
+ status: ConvexTextBuilderInitial<""> & {
4381
+ _: {
4382
+ notNull: true;
4383
+ };
4384
+ } & {
4385
+ _: {
4386
+ tableName: "aggregate_state";
4387
+ };
4388
+ } & {
4389
+ _: {
4390
+ fieldName: "status";
4391
+ };
4392
+ };
4370
4393
  kind: ConvexTextBuilderInitial<""> & {
4371
4394
  _: {
4372
4395
  notNull: true;
@@ -4454,19 +4477,6 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4454
4477
  fieldName: "metricDefinitionHash";
4455
4478
  };
4456
4479
  };
4457
- status: ConvexTextBuilderInitial<""> & {
4458
- _: {
4459
- notNull: true;
4460
- };
4461
- } & {
4462
- _: {
4463
- tableName: "aggregate_state";
4464
- };
4465
- } & {
4466
- _: {
4467
- fieldName: "status";
4468
- };
4469
- };
4470
4480
  processed: ConvexNumberBuilderInitial<""> & {
4471
4481
  _: {
4472
4482
  notNull: true;
@@ -4521,38 +4531,38 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4521
4531
  readonly migration_state: ConvexTableWithColumns<{
4522
4532
  name: "migration_state";
4523
4533
  columns: {
4524
- cursor: ConvexTextBuilderInitial<""> & {
4534
+ status: ConvexTextBuilderInitial<""> & {
4535
+ _: {
4536
+ notNull: true;
4537
+ };
4538
+ } & {
4525
4539
  _: {
4526
4540
  tableName: "migration_state";
4527
4541
  };
4528
4542
  } & {
4529
4543
  _: {
4530
- fieldName: "cursor";
4544
+ fieldName: "status";
4531
4545
  };
4532
4546
  };
4533
- direction: ConvexTextBuilderInitial<""> & {
4547
+ cursor: ConvexTextBuilderInitial<""> & {
4534
4548
  _: {
4535
4549
  tableName: "migration_state";
4536
4550
  };
4537
4551
  } & {
4538
4552
  _: {
4539
- fieldName: "direction";
4553
+ fieldName: "cursor";
4540
4554
  };
4541
4555
  };
4542
- updatedAt: ConvexNumberBuilderInitial<""> & {
4543
- _: {
4544
- notNull: true;
4545
- };
4546
- } & {
4556
+ direction: ConvexTextBuilderInitial<""> & {
4547
4557
  _: {
4548
4558
  tableName: "migration_state";
4549
4559
  };
4550
4560
  } & {
4551
4561
  _: {
4552
- fieldName: "updatedAt";
4562
+ fieldName: "direction";
4553
4563
  };
4554
4564
  };
4555
- status: ConvexTextBuilderInitial<""> & {
4565
+ updatedAt: ConvexNumberBuilderInitial<""> & {
4556
4566
  _: {
4557
4567
  notNull: true;
4558
4568
  };
@@ -4562,7 +4572,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4562
4572
  };
4563
4573
  } & {
4564
4574
  _: {
4565
- fieldName: "status";
4575
+ fieldName: "updatedAt";
4566
4576
  };
4567
4577
  };
4568
4578
  processed: ConvexNumberBuilderInitial<""> & {
@@ -4675,7 +4685,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4675
4685
  readonly migration_run: ConvexTableWithColumns<{
4676
4686
  name: "migration_run";
4677
4687
  columns: {
4678
- direction: ConvexTextBuilderInitial<""> & {
4688
+ status: ConvexTextBuilderInitial<""> & {
4679
4689
  _: {
4680
4690
  notNull: true;
4681
4691
  };
@@ -4685,10 +4695,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4685
4695
  };
4686
4696
  } & {
4687
4697
  _: {
4688
- fieldName: "direction";
4698
+ fieldName: "status";
4689
4699
  };
4690
4700
  };
4691
- updatedAt: ConvexNumberBuilderInitial<""> & {
4701
+ direction: ConvexTextBuilderInitial<""> & {
4692
4702
  _: {
4693
4703
  notNull: true;
4694
4704
  };
@@ -4698,10 +4708,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4698
4708
  };
4699
4709
  } & {
4700
4710
  _: {
4701
- fieldName: "updatedAt";
4711
+ fieldName: "direction";
4702
4712
  };
4703
4713
  };
4704
- status: ConvexTextBuilderInitial<""> & {
4714
+ updatedAt: ConvexNumberBuilderInitial<""> & {
4705
4715
  _: {
4706
4716
  notNull: true;
4707
4717
  };
@@ -4711,7 +4721,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4711
4721
  };
4712
4722
  } & {
4713
4723
  _: {
4714
- fieldName: "status";
4724
+ fieldName: "updatedAt";
4715
4725
  };
4716
4726
  };
4717
4727
  startedAt: ConvexNumberBuilderInitial<""> & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -721,7 +721,7 @@ const filtered = results.filter((a) => a.publishedAt >= startDate);
721
721
  ### Performance
722
722
 
723
723
  1. **Index first** — constrain leading index fields. Compound indexes follow prefix rules. Put the `orderBy` column right after the constrained prefix so the scan is already sorted and `limit` bounds the read.
724
- 2. **Bound scans** — use `maxScan` for predicate `where` (cursor mode only).
724
+ 2. **Bound scans** — use `maxScan` for predicate `where` (cursor mode only). A `.select()` ID-list query with `orderBy` needs a single field that an index leads with.
725
725
  3. **Limit results** — always use `limit` or cursor pagination.
726
726
  4. **Cursor stability** — keep same `where`/`orderBy` between page requests.
727
727
  5. **`allowFullScan`** — non-cursor only. Cursor mode uses `maxScan` instead.