kitcn 0.32.0 → 0.32.1
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.
- package/CHANGELOG.md +20 -0
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/{capabilities-CD-Ij91k.d.ts → capabilities-Ctcw2VRq.d.ts} +14 -0
- package/dist/orm/aggregate-index/index.d.ts +1 -1
- package/dist/orm/index.d.ts +2 -2
- package/dist/orm/index.js +109 -20
- package/dist/orm/migrations/index.d.ts +2 -2
- package/dist/{where-clause-compiler-FDJTqLDC.d.ts → where-clause-compiler-BHGHbfb9.d.ts} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# kitcn
|
|
2
2
|
|
|
3
|
+
## 0.32.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#427](https://github.com/udecode/kitcn/pull/427) [`92381f5`](https://github.com/udecode/kitcn/commit/92381f56a660dfcd4679674f612e64c1518bcf75) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
|
|
8
|
+
|
|
9
|
+
- Improve the read cost of filtering parents by whether a related child exists.
|
|
10
|
+
`where: { posts: { type: 'wanted' } }` now stops at the first matching child
|
|
11
|
+
instead of loading the whole per-parent child window and testing it afterwards.
|
|
12
|
+
On one parent with 61 posts and a match sorting first, that is 2 document reads
|
|
13
|
+
instead of 62 — the same cost as the hand-written
|
|
14
|
+
`with: { posts: { where: { type: 'wanted' }, limit: 1 } }`. The same applies to
|
|
15
|
+
`where: { posts: true }`, to a relation existence test under `NOT`, and to
|
|
16
|
+
`through` relations, where it also stops at the first matching junction row.
|
|
17
|
+
Results are unchanged: the filter still decides from the same window it read
|
|
18
|
+
before, so a match past `defaultLimit` is excluded exactly as it was.
|
|
19
|
+
- A relation named more than once in one `where` — across `OR`, `AND` and `NOT`
|
|
20
|
+
branches — keeps the previous single unbounded load, because those branches
|
|
21
|
+
share it and each needs to read it in full.
|
|
22
|
+
|
|
3
23
|
## 0.32.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Vn as ConvexTextBuilderInitial, Zt as ConvexTableWithColumns } from "../capabilities-
|
|
2
|
-
import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-
|
|
1
|
+
import { Vn as ConvexTextBuilderInitial, Zt as ConvexTableWithColumns } from "../capabilities-Ctcw2VRq.js";
|
|
2
|
+
import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-BHGHbfb9.js";
|
|
3
3
|
import * as convex_values0 from "convex/values";
|
|
4
4
|
import { GenericId, Infer, Value } from "convex/values";
|
|
5
5
|
import { DocumentByName, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, TableNamesInDataModel } from "convex/server";
|
|
@@ -3014,7 +3014,21 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
|
|
|
3014
3014
|
private _buildFieldFilterExpression;
|
|
3015
3015
|
private _buildFilterExpression;
|
|
3016
3016
|
private _mergeWithConfig;
|
|
3017
|
+
/**
|
|
3018
|
+
* Relation keys the filter tree mentions exactly once, across every OR/AND/NOT
|
|
3019
|
+
* branch at this table level.
|
|
3020
|
+
*
|
|
3021
|
+
* `_mergeWithConfig` collapses the whole tree into one load per relation key,
|
|
3022
|
+
* so a key two branches disagree about has to be loaded the way both branches
|
|
3023
|
+
* can read. Only a key with a single occurrence has one predicate to satisfy,
|
|
3024
|
+
* and only then can that predicate be pushed into the read plan.
|
|
3025
|
+
*
|
|
3026
|
+
* Relation values are not descended into: they belong to the target table and
|
|
3027
|
+
* get their own count when that level is lowered.
|
|
3028
|
+
*/
|
|
3029
|
+
private _collectSingleOccurrenceRelations;
|
|
3017
3030
|
private _buildFilterWithConfig;
|
|
3031
|
+
private _buildFilterWithConfigForLevel;
|
|
3018
3032
|
private _stripFilterRelations;
|
|
3019
3033
|
private _hasSearchDisallowedRelationFilter;
|
|
3020
3034
|
private _searchFilterValuesEqual;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as RankIndexDefinition, G as CountBackfillChunkArgs, J as CountBackfillStatusArgs, K as CountBackfillKickoffArgs, Q as CountIndexDefinition, X as CountQueryPlan, Y as AggregateQueryPlan, Z as AggregateIndexDefinition, et as RankOrderField, q as CountBackfillMode, r as OrmCapability } from "../../capabilities-
|
|
1
|
+
import { $ as RankIndexDefinition, G as CountBackfillChunkArgs, J as CountBackfillStatusArgs, K as CountBackfillKickoffArgs, Q as CountIndexDefinition, X as CountQueryPlan, Y as AggregateQueryPlan, Z as AggregateIndexDefinition, et as RankOrderField, q as CountBackfillMode, r as OrmCapability } from "../../capabilities-Ctcw2VRq.js";
|
|
2
2
|
|
|
3
3
|
//#region src/orm/aggregate-index/capability.d.ts
|
|
4
4
|
/**
|
package/dist/orm/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $n as TableName, $t as OrmLifecycleChange, An as ConvexCheckBuilder, At as UpdateSet, Bn as ConvexTextBuilder, Br as IsPrimaryKey, Bt as RelationsBuilderColumnBase, C as MigrationStep, Cn as ConvexVectorIndexConfig, Cr as not, Ct as OrderByClause, D as defineMigration, Dn as searchIndex, Dr as startsWith, Dt as ReturningAll, E as buildMigrationPlan, En as rankIndex, Er as or, Et as PredicateWhereIndexConfig, Fn as ConvexUniqueConstraintBuilderOn, Fr as ColumnBuilderTypeConfig, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, H as RlsMode, Hn as text, Hr as NotNull, In as ConvexUniqueConstraintConfig, Ir as ColumnBuilderWithTableName, It as ExtractTablesWithRelations, Jn as OrmSchemaExtensionTables, Jt as ConvexDeletionBuilder, Kt as defineRelations, Ln as check, Lr as ColumnDataType, Lt as ManyConfig, M as DatabaseWithQuery, Mn as ConvexForeignKeyBuilder, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader$1, Nn as ConvexForeignKeyConfig, Nr as ColumnBuilderBaseConfig, Nt as unsetToken, O as defineMigrationSet, On as uniqueIndex, Ot as ReturningResult, P as OrmWriter$1, Pn as ConvexUniqueConstraintBuilder, Pr as ColumnBuilderRuntimeConfig, Qn as OrmSchemaTriggers, Qt as DiscriminatorBuilderConfig, Rn as foreignKey, Rr as DrizzleEntity, Rt as OneConfig, S as MigrationStateMap, Sn as ConvexVectorIndexBuilderOn, Sr as ne, St as MutationRunMode, T as MigrationWriteMode, Tn as index, Tr as notInArray, Tt as PaginatedResult, U as EdgeMetadata, V as RlsContext, Vn as ConvexTextBuilderInitial, Vr as IsUnique, Vt as RelationsBuilderColumnConfig, W as extractRelationsConfig, Wn as Brand, Wt as TableRelationalConfig, Xn as OrmSchemaExtensions, Xt as ConvexTable, Yt as ConvexDeletionConfig, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, _ as MigrationManifestEntry, _n as ConvexRankIndexBuilderOn, _r as isNotNull, _t as MutationExecutionMode, an as RlsPolicy, ar as UnaryExpression, at as BuildRelationResult, b as MigrationRunStatus, bn as ConvexSearchIndexConfig, br as lt, bt as MutationResult, cn as rlsPolicy, cr as contains, ct as DBQueryConfig, d as MigrationAppliedState, dn as rlsRole, dr as fieldRef, dt as InferInsertModel, en as OrmLifecycleOperation, er as BinaryExpression, f as MigrationDefinition, fn as ConvexAggregateIndexBuilder, fr as gt, ft as InferModelFromColumns, g as MigrationDriftIssue, gn as ConvexRankIndexBuilder, gr as isFieldReference, gt as MutationExecuteResult, h as MigrationDocContext, hn as ConvexIndexBuilderOn, hr as inArray, ht as MutationExecuteConfig, i as OrmMigrationCapability, in as discriminator, ir as LogicalExpression, it as BuildQueryResult, j as DatabaseWithMutations, jn as ConvexCheckConfig, jr as AnyColumn, jt as VectorQueryConfig, k as detectMigrationDrift, kn as vectorIndex, kr as SystemFields, kt as ReturningSelection, ln as RlsRole, lr as endsWith, lt as FilterOperators, m as MigrationDoc, mn as ConvexIndexBuilder, mr as ilike, mt as InsertValue, n as OrmCapabilities, nn as convexTable, nr as FieldReference, nt as AggregateFieldValue, on as RlsPolicyConfig, or as and, ot as CountConfig, p as MigrationDirection, pn as ConvexAggregateIndexBuilderOn, pr as gte, pt as InferSelectModel, qt as defineRelationsPart, r as OrmCapability, rn as deletion, rr as FilterExpression, rt as AggregateResult, sn as RlsPolicyToOption, sr as between, st as CountResult, t as OrmAggregateCapability, tn as TableConfig, tr as ExpressionVisitor, tt as AggregateConfig, un as RlsRoleConfig, ur as eq, ut as GetColumnData, v as MigrationMigrateOne, vn as ConvexSearchIndexBuilder, vr as isNull, vt as MutationPaginateConfig, w as MigrationTableName, wn as aggregateIndex, wr as notBetween, wt as OrderDirection, x as MigrationSet, xn as ConvexVectorIndexBuilder, xr as lte, xt as MutationReturning, y as MigrationPlan, yn as ConvexSearchIndexBuilderOn, yr as like, yt as MutationPaginatedResult, zn as unique, zr as HasDefault, zt as RelationsBuilder } from "../capabilities-
|
|
2
|
-
import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-
|
|
1
|
+
import { $n as TableName, $t as OrmLifecycleChange, An as ConvexCheckBuilder, At as UpdateSet, Bn as ConvexTextBuilder, Br as IsPrimaryKey, Bt as RelationsBuilderColumnBase, C as MigrationStep, Cn as ConvexVectorIndexConfig, Cr as not, Ct as OrderByClause, D as defineMigration, Dn as searchIndex, Dr as startsWith, Dt as ReturningAll, E as buildMigrationPlan, En as rankIndex, Er as or, Et as PredicateWhereIndexConfig, Fn as ConvexUniqueConstraintBuilderOn, Fr as ColumnBuilderTypeConfig, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, H as RlsMode, Hn as text, Hr as NotNull, In as ConvexUniqueConstraintConfig, Ir as ColumnBuilderWithTableName, It as ExtractTablesWithRelations, Jn as OrmSchemaExtensionTables, Jt as ConvexDeletionBuilder, Kt as defineRelations, Ln as check, Lr as ColumnDataType, Lt as ManyConfig, M as DatabaseWithQuery, Mn as ConvexForeignKeyBuilder, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader$1, Nn as ConvexForeignKeyConfig, Nr as ColumnBuilderBaseConfig, Nt as unsetToken, O as defineMigrationSet, On as uniqueIndex, Ot as ReturningResult, P as OrmWriter$1, Pn as ConvexUniqueConstraintBuilder, Pr as ColumnBuilderRuntimeConfig, Qn as OrmSchemaTriggers, Qt as DiscriminatorBuilderConfig, Rn as foreignKey, Rr as DrizzleEntity, Rt as OneConfig, S as MigrationStateMap, Sn as ConvexVectorIndexBuilderOn, Sr as ne, St as MutationRunMode, T as MigrationWriteMode, Tn as index, Tr as notInArray, Tt as PaginatedResult, U as EdgeMetadata, V as RlsContext, Vn as ConvexTextBuilderInitial, Vr as IsUnique, Vt as RelationsBuilderColumnConfig, W as extractRelationsConfig, Wn as Brand, Wt as TableRelationalConfig, Xn as OrmSchemaExtensions, Xt as ConvexTable, Yt as ConvexDeletionConfig, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, _ as MigrationManifestEntry, _n as ConvexRankIndexBuilderOn, _r as isNotNull, _t as MutationExecutionMode, an as RlsPolicy, ar as UnaryExpression, at as BuildRelationResult, b as MigrationRunStatus, bn as ConvexSearchIndexConfig, br as lt, bt as MutationResult, cn as rlsPolicy, cr as contains, ct as DBQueryConfig, d as MigrationAppliedState, dn as rlsRole, dr as fieldRef, dt as InferInsertModel, en as OrmLifecycleOperation, er as BinaryExpression, f as MigrationDefinition, fn as ConvexAggregateIndexBuilder, fr as gt, ft as InferModelFromColumns, g as MigrationDriftIssue, gn as ConvexRankIndexBuilder, gr as isFieldReference, gt as MutationExecuteResult, h as MigrationDocContext, hn as ConvexIndexBuilderOn, hr as inArray, ht as MutationExecuteConfig, i as OrmMigrationCapability, in as discriminator, ir as LogicalExpression, it as BuildQueryResult, j as DatabaseWithMutations, jn as ConvexCheckConfig, jr as AnyColumn, jt as VectorQueryConfig, k as detectMigrationDrift, kn as vectorIndex, kr as SystemFields, kt as ReturningSelection, ln as RlsRole, lr as endsWith, lt as FilterOperators, m as MigrationDoc, mn as ConvexIndexBuilder, mr as ilike, mt as InsertValue, n as OrmCapabilities, nn as convexTable, nr as FieldReference, nt as AggregateFieldValue, on as RlsPolicyConfig, or as and, ot as CountConfig, p as MigrationDirection, pn as ConvexAggregateIndexBuilderOn, pr as gte, pt as InferSelectModel, qt as defineRelationsPart, r as OrmCapability, rn as deletion, rr as FilterExpression, rt as AggregateResult, sn as RlsPolicyToOption, sr as between, st as CountResult, t as OrmAggregateCapability, tn as TableConfig, tr as ExpressionVisitor, tt as AggregateConfig, un as RlsRoleConfig, ur as eq, ut as GetColumnData, v as MigrationMigrateOne, vn as ConvexSearchIndexBuilder, vr as isNull, vt as MutationPaginateConfig, w as MigrationTableName, wn as aggregateIndex, wr as notBetween, wt as OrderDirection, x as MigrationSet, xn as ConvexVectorIndexBuilder, xr as lte, xt as MutationReturning, y as MigrationPlan, yn as ConvexSearchIndexBuilderOn, yr as like, yt as MutationPaginatedResult, zn as unique, zr as HasDefault, zt as RelationsBuilder } from "../capabilities-Ctcw2VRq.js";
|
|
2
|
+
import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-BHGHbfb9.js";
|
|
3
3
|
import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-0I-Ik1EN.js";
|
|
4
4
|
import { a as QueryCtxWithPreferredOrmQueryTable, i as QueryCtxWithOrmQueryTable, n as LookupByIdResultByCtx, o as getByIdWithOrmQueryFallback, r as QueryCtxWithOptionalOrmQueryTable, t as DocByCtx } from "../query-context-BkNjkDCk.js";
|
|
5
5
|
import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
|
package/dist/orm/index.js
CHANGED
|
@@ -1322,6 +1322,20 @@ const DEFAULT_RELATION_FAN_OUT_MAX_KEYS = 1e3;
|
|
|
1322
1322
|
* satisfies the limit.
|
|
1323
1323
|
*/
|
|
1324
1324
|
const RELATION_FILTER_STREAM_CHUNK = 32;
|
|
1325
|
+
/**
|
|
1326
|
+
* Marks a relation config that only exists to answer "does a matching child
|
|
1327
|
+
* exist?" for a `where` clause. The lowered load may stop at the first
|
|
1328
|
+
* surviving child, but it must not widen the window it walks to find one --
|
|
1329
|
+
* that window is what decides the answer, so changing it would change results
|
|
1330
|
+
* rather than just their cost.
|
|
1331
|
+
*
|
|
1332
|
+
* A symbol, not a field: the emitted object is fed to the same relation loader
|
|
1333
|
+
* that serves a caller's `with`, and nothing a caller can write should be able
|
|
1334
|
+
* to claim this.
|
|
1335
|
+
*/
|
|
1336
|
+
const RELATION_EXISTENCE_PROBE = Symbol("kitcn.relationExistenceProbe");
|
|
1337
|
+
/** Lowering a subtree with this set emits no existence probes anywhere in it. */
|
|
1338
|
+
const NO_PROBE_RELATIONS = /* @__PURE__ */ new Set();
|
|
1325
1339
|
const DEFAULT_AGGREGATE_CARTESIAN_MAX_KEYS = 4096;
|
|
1326
1340
|
const DEFAULT_AGGREGATE_WORK_BUDGET = 16384;
|
|
1327
1341
|
const PUBLIC_ID_FIELD = "id";
|
|
@@ -2391,7 +2405,47 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
2391
2405
|
}
|
|
2392
2406
|
}
|
|
2393
2407
|
}
|
|
2408
|
+
/**
|
|
2409
|
+
* Relation keys the filter tree mentions exactly once, across every OR/AND/NOT
|
|
2410
|
+
* branch at this table level.
|
|
2411
|
+
*
|
|
2412
|
+
* `_mergeWithConfig` collapses the whole tree into one load per relation key,
|
|
2413
|
+
* so a key two branches disagree about has to be loaded the way both branches
|
|
2414
|
+
* can read. Only a key with a single occurrence has one predicate to satisfy,
|
|
2415
|
+
* and only then can that predicate be pushed into the read plan.
|
|
2416
|
+
*
|
|
2417
|
+
* Relation values are not descended into: they belong to the target table and
|
|
2418
|
+
* get their own count when that level is lowered.
|
|
2419
|
+
*/
|
|
2420
|
+
_collectSingleOccurrenceRelations(filter, tableConfig) {
|
|
2421
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2422
|
+
const walk = (node) => {
|
|
2423
|
+
if (!this._isRecord(node)) return;
|
|
2424
|
+
for (const [key, value] of Object.entries(node)) {
|
|
2425
|
+
if (value === void 0) continue;
|
|
2426
|
+
if (key === "OR" || key === "AND") {
|
|
2427
|
+
if (!Array.isArray(value)) continue;
|
|
2428
|
+
for (const sub of value) walk(sub);
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
if (key === "NOT") {
|
|
2432
|
+
walk(value);
|
|
2433
|
+
continue;
|
|
2434
|
+
}
|
|
2435
|
+
if (!tableConfig.relations[key]) continue;
|
|
2436
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
2437
|
+
}
|
|
2438
|
+
};
|
|
2439
|
+
walk(filter);
|
|
2440
|
+
const single = /* @__PURE__ */ new Set();
|
|
2441
|
+
for (const [key, count] of counts) if (count === 1) single.add(key);
|
|
2442
|
+
return single;
|
|
2443
|
+
}
|
|
2394
2444
|
_buildFilterWithConfig(filter, tableConfig) {
|
|
2445
|
+
if (!this._isRecord(filter)) return {};
|
|
2446
|
+
return this._buildFilterWithConfigForLevel(filter, tableConfig, this._collectSingleOccurrenceRelations(filter, tableConfig));
|
|
2447
|
+
}
|
|
2448
|
+
_buildFilterWithConfigForLevel(filter, tableConfig, probeEligible) {
|
|
2395
2449
|
if (!this._isRecord(filter)) return {};
|
|
2396
2450
|
const result = {};
|
|
2397
2451
|
const entries = Object.entries(filter);
|
|
@@ -2401,27 +2455,36 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
2401
2455
|
if (key === "OR" || key === "AND") {
|
|
2402
2456
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
2403
2457
|
for (const sub of value) {
|
|
2404
|
-
const nested = this.
|
|
2458
|
+
const nested = this._buildFilterWithConfigForLevel(sub, tableConfig, probeEligible);
|
|
2405
2459
|
this._mergeWithConfig(result, nested);
|
|
2406
2460
|
}
|
|
2407
2461
|
continue;
|
|
2408
2462
|
}
|
|
2409
2463
|
if (key === "NOT") {
|
|
2410
|
-
const nested = this.
|
|
2464
|
+
const nested = this._buildFilterWithConfigForLevel(value, tableConfig, probeEligible);
|
|
2411
2465
|
this._mergeWithConfig(result, nested);
|
|
2412
2466
|
continue;
|
|
2413
2467
|
}
|
|
2414
2468
|
this._assertNoLegacyPublicFieldName(key);
|
|
2415
2469
|
const relation = tableConfig.relations[key];
|
|
2416
2470
|
if (!relation) continue;
|
|
2471
|
+
const probe = relation.relationType !== "one" && probeEligible.has(key) ? { [RELATION_EXISTENCE_PROBE]: true } : void 0;
|
|
2417
2472
|
if (typeof value === "boolean") {
|
|
2418
|
-
result[key] = true;
|
|
2473
|
+
result[key] = probe ?? true;
|
|
2419
2474
|
continue;
|
|
2420
2475
|
}
|
|
2421
2476
|
const targetTableConfig = this._getTableConfigByDbName(relation.targetTableName);
|
|
2422
2477
|
if (!targetTableConfig) continue;
|
|
2423
|
-
const nested = this.
|
|
2424
|
-
|
|
2478
|
+
const nested = this._buildFilterWithConfigForLevel(value, targetTableConfig, probe ? this._collectSingleOccurrenceRelations(value, targetTableConfig) : NO_PROBE_RELATIONS);
|
|
2479
|
+
const hasNested = Object.keys(nested).length > 0;
|
|
2480
|
+
if (!probe) {
|
|
2481
|
+
result[key] = hasNested ? { with: nested } : true;
|
|
2482
|
+
continue;
|
|
2483
|
+
}
|
|
2484
|
+
const emitted = { ...probe };
|
|
2485
|
+
if (Object.keys(value).length > 0) emitted.where = value;
|
|
2486
|
+
if (hasNested) emitted.with = nested;
|
|
2487
|
+
result[key] = emitted;
|
|
2425
2488
|
}
|
|
2426
2489
|
return result;
|
|
2427
2490
|
}
|
|
@@ -4955,9 +5018,10 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
4955
5018
|
* parents in the round.
|
|
4956
5019
|
*/
|
|
4957
5020
|
async _readBoundedThroughLinks(params) {
|
|
4958
|
-
const {
|
|
5021
|
+
const { applyAmbientTargetFilters, applyConfigTargetFilter, edge, enforceTargetKeyCap, entries, fetchLimit, fetchTargets, scanLimit, targetFields, throughIndexName, throughTableConfig } = params;
|
|
4959
5022
|
const throughTargetFields = edge.through.targetFields;
|
|
4960
5023
|
const cursors = entries.map(([key, values]) => ({
|
|
5024
|
+
ambientLinks: 0,
|
|
4961
5025
|
buffered: [],
|
|
4962
5026
|
exhausted: false,
|
|
4963
5027
|
iterator: this._queryByFields(this.db.query(edge.through.table), edge.through.sourceFields, values, throughIndexName)[Symbol.asyncIterator](),
|
|
@@ -4984,10 +5048,12 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
4984
5048
|
};
|
|
4985
5049
|
/** Target key -> the surviving document, absent when it did not survive. */
|
|
4986
5050
|
const survivorByKey = /* @__PURE__ */ new Map();
|
|
5051
|
+
/** Target keys that cleared the ambient filters, survivors or not. */
|
|
5052
|
+
const ambientKeys = /* @__PURE__ */ new Set();
|
|
4987
5053
|
const resolvedKeys = /* @__PURE__ */ new Set();
|
|
4988
5054
|
const survivors = [];
|
|
4989
5055
|
while (true) {
|
|
4990
|
-
const active = cursors.filter((cursor) => cursor.links.length < fetchLimit && !(cursor.exhausted && cursor.buffered.length === 0));
|
|
5056
|
+
const active = cursors.filter((cursor) => cursor.links.length < fetchLimit && (scanLimit === void 0 || cursor.ambientLinks < scanLimit) && !(cursor.exhausted && cursor.buffered.length === 0));
|
|
4991
5057
|
if (active.length === 0) break;
|
|
4992
5058
|
const candidatesPerCursor = await this._mapWithConcurrency(active, async (cursor) => {
|
|
4993
5059
|
const need = fetchLimit - cursor.links.length;
|
|
@@ -5006,7 +5072,12 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5006
5072
|
enforceTargetKeyCap(resolvedKeys.size + newKeys.size);
|
|
5007
5073
|
const fetched = await fetchTargets(Array.from(newKeys.entries()));
|
|
5008
5074
|
for (const key of newKeys.keys()) resolvedKeys.add(key);
|
|
5009
|
-
const
|
|
5075
|
+
const ambientTargets = await applyAmbientTargetFilters(fetched.map((entry) => entry.target).filter((target) => !!target));
|
|
5076
|
+
for (const target of ambientTargets) {
|
|
5077
|
+
const key = this._buildRelationKey(target, targetFields);
|
|
5078
|
+
if (key) ambientKeys.add(key);
|
|
5079
|
+
}
|
|
5080
|
+
const surviving = await applyConfigTargetFilter(ambientTargets);
|
|
5010
5081
|
for (const target of surviving) {
|
|
5011
5082
|
const key = this._buildRelationKey(target, targetFields);
|
|
5012
5083
|
if (!key || survivorByKey.has(key)) continue;
|
|
@@ -5018,8 +5089,11 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5018
5089
|
const cursor = active[i];
|
|
5019
5090
|
for (const link of candidatesPerCursor[i]) {
|
|
5020
5091
|
if (cursor.links.length >= fetchLimit) break;
|
|
5092
|
+
if (scanLimit !== void 0 && cursor.ambientLinks >= scanLimit) break;
|
|
5021
5093
|
const key = this._buildRelationKey(link, throughTargetFields);
|
|
5022
|
-
if (!key
|
|
5094
|
+
if (!key) continue;
|
|
5095
|
+
if (ambientKeys.has(key)) cursor.ambientLinks += 1;
|
|
5096
|
+
if (!survivorByKey.has(key)) continue;
|
|
5023
5097
|
cursor.links.push(link);
|
|
5024
5098
|
}
|
|
5025
5099
|
}
|
|
@@ -5072,6 +5146,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5072
5146
|
const relationDefinition = tableConfig.relations[relationName];
|
|
5073
5147
|
const strict = tableConfig.strict !== false;
|
|
5074
5148
|
const hasPostFetchTargetFilter = this.rls?.mode !== "skip" && isRlsEnabled(targetTableConfig.table) || Boolean(relationDefinition?.where) || Boolean(relationConfig && typeof relationConfig === "object" && "where" in relationConfig && relationConfig.where);
|
|
5149
|
+
const isExistenceProbe = Boolean(relationConfig) && typeof relationConfig === "object" && relationConfig[RELATION_EXISTENCE_PROBE] === true;
|
|
5075
5150
|
let orderSpecs = [];
|
|
5076
5151
|
if (relationConfig && typeof relationConfig === "object" && "orderBy" in relationConfig) {
|
|
5077
5152
|
let orderByValue = relationConfig.orderBy;
|
|
@@ -5086,15 +5161,22 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5086
5161
|
if (effectivePerParentLimit === void 0 && !this.allowFullScan) throw new Error(`Relation "${tableConfig.name}.${relationName}" requires limit, allowFullScan: true, or defineSchema(..., { defaults: { defaultLimit } }).`);
|
|
5087
5162
|
const perParentOffset = relationConfig && typeof relationConfig === "object" && "offset" in relationConfig ? relationConfig.offset : void 0;
|
|
5088
5163
|
if (perParentOffset !== void 0 && typeof perParentOffset !== "number") throw new Error("Only numeric offset is supported in kitcn ORM.");
|
|
5164
|
+
const probeFetchLimit = isExistenceProbe ? 1 : void 0;
|
|
5165
|
+
const probeScanLimit = isExistenceProbe ? effectivePerParentLimit : void 0;
|
|
5166
|
+
const canBoundPerParentRead = effectivePerParentLimit !== void 0 || isExistenceProbe;
|
|
5089
5167
|
const applyOffsetAndLimit = (items) => {
|
|
5090
5168
|
let result = items;
|
|
5091
5169
|
if (perParentOffset !== void 0 && perParentOffset > 0) result = result.slice(perParentOffset);
|
|
5092
5170
|
if (effectivePerParentLimit !== void 0) result = result.slice(0, effectivePerParentLimit);
|
|
5093
5171
|
return result;
|
|
5094
5172
|
};
|
|
5095
|
-
const
|
|
5096
|
-
|
|
5097
|
-
if (relationDefinition?.where)
|
|
5173
|
+
const applyAmbientTargetFilters = async (candidateTargets) => {
|
|
5174
|
+
const visibleTargets = await this._applyRlsSelectFilter(candidateTargets, targetTableConfig);
|
|
5175
|
+
if (!relationDefinition?.where) return visibleTargets;
|
|
5176
|
+
return visibleTargets.filter((target) => this._evaluateTableFilter(target, targetTableConfig, relationDefinition.where));
|
|
5177
|
+
};
|
|
5178
|
+
const applyConfigTargetFilter = async (ambientTargets) => {
|
|
5179
|
+
let filteredTargets = ambientTargets;
|
|
5098
5180
|
if (relationConfig && typeof relationConfig === "object" && "where" in relationConfig) {
|
|
5099
5181
|
const whereFilter = relationConfig.where;
|
|
5100
5182
|
if (typeof whereFilter === "function") {
|
|
@@ -5107,6 +5189,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5107
5189
|
}
|
|
5108
5190
|
return filteredTargets;
|
|
5109
5191
|
};
|
|
5192
|
+
const applyPostFetchTargetFilters = async (candidateTargets) => applyConfigTargetFilter(await applyAmbientTargetFilters(candidateTargets));
|
|
5110
5193
|
let targets = [];
|
|
5111
5194
|
let throughBySourceKey;
|
|
5112
5195
|
let targetFiltersApplied = false;
|
|
@@ -5141,14 +5224,16 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5141
5224
|
};
|
|
5142
5225
|
});
|
|
5143
5226
|
};
|
|
5144
|
-
if (orderSpecs.length === 0 &&
|
|
5227
|
+
if (orderSpecs.length === 0 && canBoundPerParentRead) {
|
|
5145
5228
|
const bounded = await this._readBoundedThroughLinks({
|
|
5146
|
-
|
|
5229
|
+
applyAmbientTargetFilters,
|
|
5230
|
+
applyConfigTargetFilter,
|
|
5147
5231
|
edge,
|
|
5148
5232
|
enforceTargetKeyCap,
|
|
5149
5233
|
entries,
|
|
5150
|
-
fetchLimit: Math.max(perParentOffset ?? 0, 0) + effectivePerParentLimit,
|
|
5234
|
+
fetchLimit: probeFetchLimit ?? Math.max(perParentOffset ?? 0, 0) + effectivePerParentLimit,
|
|
5151
5235
|
fetchTargets: fetchThroughTargets,
|
|
5236
|
+
scanLimit: probeScanLimit,
|
|
5152
5237
|
targetFields,
|
|
5153
5238
|
throughIndexName,
|
|
5154
5239
|
throughTableConfig
|
|
@@ -5188,22 +5273,25 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5188
5273
|
});
|
|
5189
5274
|
const orderServedByIndex = orderSpecs.length === 0 || orderPushdownDirection !== null;
|
|
5190
5275
|
const applyPushdownOrder = (query) => orderPushdownDirection ? query.order(orderPushdownDirection) : query;
|
|
5191
|
-
const streamPostFetchTargetFilters = orderServedByIndex && hasPostFetchTargetFilter &&
|
|
5276
|
+
const streamPostFetchTargetFilters = orderServedByIndex && hasPostFetchTargetFilter && canBoundPerParentRead;
|
|
5192
5277
|
targetFiltersApplied = streamPostFetchTargetFilters;
|
|
5193
5278
|
targets = (await this._mapWithConcurrency(entries, async ([, values]) => {
|
|
5194
5279
|
const query = this._queryByFields(this.db.query(edge.targetTable), targetFields, values, indexName);
|
|
5195
|
-
if (orderServedByIndex && !hasPostFetchTargetFilter &&
|
|
5196
|
-
const fetchLimit = (perParentOffset ?? 0) + (effectivePerParentLimit ?? 0);
|
|
5280
|
+
if (orderServedByIndex && !hasPostFetchTargetFilter && canBoundPerParentRead) {
|
|
5281
|
+
const fetchLimit = probeFetchLimit ?? (perParentOffset ?? 0) + (effectivePerParentLimit ?? 0);
|
|
5197
5282
|
return await applyPushdownOrder(query).take(fetchLimit);
|
|
5198
5283
|
}
|
|
5199
5284
|
if (streamPostFetchTargetFilters) {
|
|
5200
5285
|
const visibleTargets = [];
|
|
5201
|
-
const fetchLimit = Math.max(perParentOffset ?? 0, 0) + (effectivePerParentLimit ?? 0);
|
|
5286
|
+
const fetchLimit = probeFetchLimit ?? Math.max(perParentOffset ?? 0, 0) + (effectivePerParentLimit ?? 0);
|
|
5202
5287
|
let batch = [];
|
|
5288
|
+
let ambientSeen = 0;
|
|
5203
5289
|
const drain = async () => {
|
|
5204
5290
|
if (batch.length === 0) return;
|
|
5205
|
-
const
|
|
5291
|
+
const ambientTargets = await applyAmbientTargetFilters(batch);
|
|
5206
5292
|
batch = [];
|
|
5293
|
+
ambientSeen += ambientTargets.length;
|
|
5294
|
+
const filtered = await applyConfigTargetFilter(ambientTargets);
|
|
5207
5295
|
for (const row of filtered) {
|
|
5208
5296
|
if (visibleTargets.length >= fetchLimit) return;
|
|
5209
5297
|
visibleTargets.push(row);
|
|
@@ -5215,6 +5303,7 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
|
|
|
5215
5303
|
if (batch.length < chunk) continue;
|
|
5216
5304
|
await drain();
|
|
5217
5305
|
if (visibleTargets.length >= fetchLimit) break;
|
|
5306
|
+
if (probeScanLimit !== void 0 && ambientSeen >= probeScanLimit) break;
|
|
5218
5307
|
}
|
|
5219
5308
|
if (visibleTargets.length < fetchLimit) await drain();
|
|
5220
5309
|
return visibleTargets;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as MigrationStep, D as defineMigration, E as buildMigrationPlan, O as defineMigrationSet, S as MigrationStateMap, T as MigrationWriteMode, _ as MigrationManifestEntry, a as MAX_STATUS_RUN_LIMIT, b as MigrationRunStatus, c as MigrationRunChunkArgs, d as MigrationAppliedState, f as MigrationDefinition, g as MigrationDriftIssue, h as MigrationDocContext, k as detectMigrationDrift, l as MigrationStatusArgs, m as MigrationDoc, o as MigrationCancelArgs, p as MigrationDirection, s as MigrationRunArgs, u as createMigrationHandlers, v as MigrationMigrateOne, w as MigrationTableName, x as MigrationSet, y as MigrationPlan } from "../../capabilities-
|
|
2
|
-
import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-
|
|
1
|
+
import { C as MigrationStep, D as defineMigration, E as buildMigrationPlan, O as defineMigrationSet, S as MigrationStateMap, T as MigrationWriteMode, _ as MigrationManifestEntry, a as MAX_STATUS_RUN_LIMIT, b as MigrationRunStatus, c as MigrationRunChunkArgs, d as MigrationAppliedState, f as MigrationDefinition, g as MigrationDriftIssue, h as MigrationDocContext, k as detectMigrationDrift, l as MigrationStatusArgs, m as MigrationDoc, o as MigrationCancelArgs, p as MigrationDirection, s as MigrationRunArgs, u as createMigrationHandlers, v as MigrationMigrateOne, w as MigrationTableName, x as MigrationSet, y as MigrationPlan } from "../../capabilities-Ctcw2VRq.js";
|
|
2
|
+
import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-BHGHbfb9.js";
|
|
3
3
|
export { MAX_STATUS_RUN_LIMIT, MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, type MigrationAppliedState, type MigrationCancelArgs, type MigrationDefinition, type MigrationDirection, type MigrationDoc, type MigrationDocContext, type MigrationDriftIssue, type MigrationManifestEntry, type MigrationMigrateOne, type MigrationPlan, type MigrationRunArgs, type MigrationRunChunkArgs, type MigrationRunStatus, type MigrationSet, type MigrationStateMap, type MigrationStatusArgs, type MigrationStep, type MigrationTableName, type MigrationWriteMode, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $t as OrmLifecycleChange, A as CreateDatabaseOptions, Ar as $Type, B as getUniqueIndexes, Ct as OrderByClause, F as CascadeMode, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, Ht as RelationsBuilderConfigValue, I as DeleteMode, Kn as OrmRuntimeDefaults, L as SerializedFilterExpression, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader, Nr as ColumnBuilderBaseConfig, Or as SystemFieldAliases, P as OrmWriter, Pt as AnyRelationsBuilderConfig, Qn as OrmSchemaTriggers, R as getChecks, U as EdgeMetadata, Un as ConvexColumnBuilder, Ur as entityKind, Ut as RelationsConfigWithSchema, Vn as ConvexTextBuilderInitial, Wt as TableRelationalConfig, Xt as ConvexTable, Yn as OrmSchemaExtensionTriggers, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, an as RlsPolicy, dt as InferInsertModel, kr as SystemFields, pt as InferSelectModel, qn as OrmSchemaExtensionRelations, r as OrmCapability, rr as FilterExpression$1, x as MigrationSet, z as getForeignKeys, zr as HasDefault, zt as RelationsBuilder } from "./capabilities-
|
|
1
|
+
import { $t as OrmLifecycleChange, A as CreateDatabaseOptions, Ar as $Type, B as getUniqueIndexes, Ct as OrderByClause, F as CascadeMode, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, Ht as RelationsBuilderConfigValue, I as DeleteMode, Kn as OrmRuntimeDefaults, L as SerializedFilterExpression, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader, Nr as ColumnBuilderBaseConfig, Or as SystemFieldAliases, P as OrmWriter, Pt as AnyRelationsBuilderConfig, Qn as OrmSchemaTriggers, R as getChecks, U as EdgeMetadata, Un as ConvexColumnBuilder, Ur as entityKind, Ut as RelationsConfigWithSchema, Vn as ConvexTextBuilderInitial, Wt as TableRelationalConfig, Xt as ConvexTable, Yn as OrmSchemaExtensionTriggers, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, an as RlsPolicy, dt as InferInsertModel, kr as SystemFields, pt as InferSelectModel, qn as OrmSchemaExtensionRelations, r as OrmCapability, rr as FilterExpression$1, x as MigrationSet, z as getForeignKeys, zr as HasDefault, zt as RelationsBuilder } from "./capabilities-Ctcw2VRq.js";
|
|
2
2
|
import * as convex_values0 from "convex/values";
|
|
3
3
|
import { GenericId, Validator, Value } from "convex/values";
|
|
4
4
|
import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchedulableFunctionReference, Scheduler, SchemaDefinition, internalActionGeneric, internalMutationGeneric, internalQueryGeneric } from "convex/server";
|