kitcn 0.17.4 → 0.18.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.
@@ -2470,6 +2470,11 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2470
2470
  private _orderBySpecs;
2471
2471
  private _resolveNonPaginatedLimit;
2472
2472
  private _compareByOrderSpecs;
2473
+ /**
2474
+ * Physical table name to relational config. Called once per row on the
2475
+ * relation-count path, so the linear schema scan is indexed once per schema
2476
+ * object rather than repeated. The schema is fixed for the process lifetime.
2477
+ */
2473
2478
  private _getTableConfigByDbName;
2474
2479
  private _matchLike;
2475
2480
  /**
@@ -2616,6 +2621,16 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2616
2621
  */
2617
2622
  private _toConvexQuery;
2618
2623
  private _buildRelationKey;
2624
+ /**
2625
+ * How many leading fields of the scanned index are pinned to a single value.
2626
+ *
2627
+ * `splitFilters` emits index filters in index-key order — a run of `eq`, then
2628
+ * at most one range on the first unpinned field — so the leading `eq` run is
2629
+ * the prefix Convex holds constant. A multi-probe plan carries no index
2630
+ * filters; each probe supplies its own bound instead, and the union is only
2631
+ * as pinned as its least pinned probe.
2632
+ */
2633
+ private _indexEqPrefixCount;
2619
2634
  private _buildIndexPredicate;
2620
2635
  private _buildFilterPredicate;
2621
2636
  private _queryByFields;
@@ -2660,9 +2675,7 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2660
2675
  private _createRelationCountError;
2661
2676
  private _remapRelationCountError;
2662
2677
  private _coerceRelationCountWhere;
2663
- private _normalizeRelationCountCacheValue;
2664
2678
  private _getRelationCountParentKey;
2665
- private _buildRelationCountExecutionKey;
2666
2679
  private _readIndexedRelationCount;
2667
2680
  private _countRelationForRow;
2668
2681
  private _loadRelationCounts;
@@ -2672,6 +2685,22 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2672
2685
  * M6.5 Phase 2: Added support for nested relations
2673
2686
  */
2674
2687
  private _loadOneRelation;
2688
+ /**
2689
+ * Junction links per parent, stopped once each parent holds `fetchLimit`
2690
+ * links whose target actually reaches the page.
2691
+ *
2692
+ * A link only contributes if its target exists and survives target RLS and
2693
+ * the relation `where` — all of which run after the junction read. Sizing the
2694
+ * read on links alone therefore under-fills: three dangling or filtered links
2695
+ * first and `{ limit: 3 }` returns nothing. So the read is refilled in rounds,
2696
+ * each round resolving only the targets it newly needs and asking again for
2697
+ * whatever the survivors did not cover.
2698
+ *
2699
+ * Rounds are the unit rather than single links because both the target fetch
2700
+ * and the relation `where` de-duplicate and batch their own reads across the
2701
+ * parents in the round.
2702
+ */
2703
+ private _readBoundedThroughLinks;
2675
2704
  /**
2676
2705
  * Load many() relation (one-to-many)
2677
2706
  * Example: users.posts where posts.authorId → users.id
@@ -4338,19 +4367,6 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4338
4367
  readonly aggregate_state: ConvexTableWithColumns<{
4339
4368
  name: "aggregate_state";
4340
4369
  columns: {
4341
- status: ConvexTextBuilderInitial<""> & {
4342
- _: {
4343
- notNull: true;
4344
- };
4345
- } & {
4346
- _: {
4347
- tableName: "aggregate_state";
4348
- };
4349
- } & {
4350
- _: {
4351
- fieldName: "status";
4352
- };
4353
- };
4354
4370
  kind: ConvexTextBuilderInitial<""> & {
4355
4371
  _: {
4356
4372
  notNull: true;
@@ -4438,6 +4454,19 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4438
4454
  fieldName: "metricDefinitionHash";
4439
4455
  };
4440
4456
  };
4457
+ status: ConvexTextBuilderInitial<""> & {
4458
+ _: {
4459
+ notNull: true;
4460
+ };
4461
+ } & {
4462
+ _: {
4463
+ tableName: "aggregate_state";
4464
+ };
4465
+ } & {
4466
+ _: {
4467
+ fieldName: "status";
4468
+ };
4469
+ };
4441
4470
  processed: ConvexNumberBuilderInitial<""> & {
4442
4471
  _: {
4443
4472
  notNull: true;
@@ -4492,38 +4521,38 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4492
4521
  readonly migration_state: ConvexTableWithColumns<{
4493
4522
  name: "migration_state";
4494
4523
  columns: {
4495
- status: ConvexTextBuilderInitial<""> & {
4496
- _: {
4497
- notNull: true;
4498
- };
4499
- } & {
4524
+ cursor: ConvexTextBuilderInitial<""> & {
4500
4525
  _: {
4501
4526
  tableName: "migration_state";
4502
4527
  };
4503
4528
  } & {
4504
4529
  _: {
4505
- fieldName: "status";
4530
+ fieldName: "cursor";
4506
4531
  };
4507
4532
  };
4508
- cursor: ConvexTextBuilderInitial<""> & {
4533
+ direction: ConvexTextBuilderInitial<""> & {
4509
4534
  _: {
4510
4535
  tableName: "migration_state";
4511
4536
  };
4512
4537
  } & {
4513
4538
  _: {
4514
- fieldName: "cursor";
4539
+ fieldName: "direction";
4515
4540
  };
4516
4541
  };
4517
- direction: ConvexTextBuilderInitial<""> & {
4542
+ updatedAt: ConvexNumberBuilderInitial<""> & {
4543
+ _: {
4544
+ notNull: true;
4545
+ };
4546
+ } & {
4518
4547
  _: {
4519
4548
  tableName: "migration_state";
4520
4549
  };
4521
4550
  } & {
4522
4551
  _: {
4523
- fieldName: "direction";
4552
+ fieldName: "updatedAt";
4524
4553
  };
4525
4554
  };
4526
- updatedAt: ConvexNumberBuilderInitial<""> & {
4555
+ status: ConvexTextBuilderInitial<""> & {
4527
4556
  _: {
4528
4557
  notNull: true;
4529
4558
  };
@@ -4533,7 +4562,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4533
4562
  };
4534
4563
  } & {
4535
4564
  _: {
4536
- fieldName: "updatedAt";
4565
+ fieldName: "status";
4537
4566
  };
4538
4567
  };
4539
4568
  processed: ConvexNumberBuilderInitial<""> & {
@@ -4646,7 +4675,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4646
4675
  readonly migration_run: ConvexTableWithColumns<{
4647
4676
  name: "migration_run";
4648
4677
  columns: {
4649
- status: ConvexTextBuilderInitial<""> & {
4678
+ direction: ConvexTextBuilderInitial<""> & {
4650
4679
  _: {
4651
4680
  notNull: true;
4652
4681
  };
@@ -4656,10 +4685,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4656
4685
  };
4657
4686
  } & {
4658
4687
  _: {
4659
- fieldName: "status";
4688
+ fieldName: "direction";
4660
4689
  };
4661
4690
  };
4662
- direction: ConvexTextBuilderInitial<""> & {
4691
+ updatedAt: ConvexNumberBuilderInitial<""> & {
4663
4692
  _: {
4664
4693
  notNull: true;
4665
4694
  };
@@ -4669,10 +4698,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4669
4698
  };
4670
4699
  } & {
4671
4700
  _: {
4672
- fieldName: "direction";
4701
+ fieldName: "updatedAt";
4673
4702
  };
4674
4703
  };
4675
- updatedAt: ConvexNumberBuilderInitial<""> & {
4704
+ status: ConvexTextBuilderInitial<""> & {
4676
4705
  _: {
4677
4706
  notNull: true;
4678
4707
  };
@@ -4682,7 +4711,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
4682
4711
  };
4683
4712
  } & {
4684
4713
  _: {
4685
- fieldName: "updatedAt";
4714
+ fieldName: "status";
4686
4715
  };
4687
4716
  };
4688
4717
  startedAt: ConvexNumberBuilderInitial<""> & {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.17.4",
3
+ "version": "0.18.0",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -254,6 +254,13 @@ Rules:
254
254
  - `one()` with `to: ...id` → uses `db.get()` (no extra index)
255
255
  - Missing index throws unless `allowFullScan` on parent query
256
256
 
257
+ Relation `limit`/`orderBy` are pushed into the relation index when the index
258
+ already walks in that order. After the FK, `index('by_user').on(t.userId)`
259
+ orders by creation time, so `with: { posts: { limit: 5, orderBy: { createdAt:
260
+ 'desc' } } }` reads 5 posts per parent. Sorting by any other column reads the
261
+ parent's whole child partition and sorts in memory — put the sort column in the
262
+ relation index (`index('by_user_rank').on(t.userId, t.rank)`) to stay bounded.
263
+
257
264
  ## Schema Definition
258
265
 
259
266
  ```ts
@@ -713,7 +720,7 @@ const filtered = results.filter((a) => a.publishedAt >= startDate);
713
720
 
714
721
  ### Performance
715
722
 
716
- 1. **Index first** — constrain leading index fields. Compound indexes follow prefix rules.
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.
717
724
  2. **Bound scans** — use `maxScan` for predicate `where` (cursor mode only).
718
725
  3. **Limit results** — always use `limit` or cursor pagination.
719
726
  4. **Cursor stability** — keep same `where`/`orderBy` between page requests.