better-convex 0.8.3 → 0.9.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.
package/dist/orm/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { t as DirectAggregate } from "../runtime-C0WcYGY0.js";
2
- import { C as integer, S as createSystemFields, T as entityKind, _ as rankIndex, a as EnableRLS, b as vectorIndex, c as OrmSchemaOptions, d as TableDeleteConfig, f as TableName, g as index, h as aggregateIndex, i as Columns, l as OrmSchemaPluginTables, m as rlsPolicy, n as deletion, o as OrmContext, p as RlsPolicy, r as Brand, s as OrmSchemaDefinition, t as convexTable, u as RlsPolicies, v as searchIndex, w as ConvexColumnBuilder, x as text, y as uniqueIndex } from "../table-B7yzBihE.js";
3
- import { a as AGGREGATE_EXTREMA_TABLE, c as aggregatePlugin, i as AGGREGATE_BUCKET_TABLE, l as boolean, n as MIGRATION_STATE_TABLE, o as AGGREGATE_MEMBER_TABLE, r as migrationPlugin, s as AGGREGATE_STATE_TABLE, t as MIGRATION_RUN_TABLE } from "../schema-Bx6j2doh.js";
1
+ import { t as DirectAggregate } from "../runtime-B20PP4Qr.js";
2
+ import { C as text, D as entityKind, E as ConvexColumnBuilder, S as vectorIndex, T as integer, _ as aggregateIndex, a as Columns, b as searchIndex, c as OrmSchemaDefinition, d as RlsPolicies, f as TableDeleteConfig, g as rlsPolicy, h as RlsPolicy, i as Brand, l as OrmSchemaOptions, m as TablePolymorphic, n as deletion, o as EnableRLS, p as TableName, r as discriminator, s as OrmContext, t as convexTable, u as OrmSchemaPluginTables, v as index, w as createSystemFields, x as uniqueIndex, y as rankIndex } from "../table-Bxqm450r.js";
3
+ import { a as AGGREGATE_EXTREMA_TABLE, c as aggregatePlugin, i as AGGREGATE_BUCKET_TABLE, l as boolean, n as MIGRATION_STATE_TABLE, o as AGGREGATE_MEMBER_TABLE, r as migrationPlugin, s as AGGREGATE_STATE_TABLE, t as MIGRATION_RUN_TABLE } from "../schema-Cw5-LWTg.js";
4
4
  import { a as pretendRequired, i as pretend, n as deprecated } from "../validators-D_i3BK7v.js";
5
- import { a as objectOf, i as json, n as arrayOf, r as custom, t as id } from "../id-BcBb900m.js";
6
- import { t as textEnum } from "../text-enum-CFdcLUuw.js";
5
+ import { a as objectOf, i as json, n as arrayOf, r as custom, t as id } from "../id-BF_SaWhQ.js";
6
+ import { t as textEnum } from "../text-enum-KyijdQ8Q.js";
7
7
  import { A as ne, C as inArray, D as like, E as isNull, F as notLike, I as or, L as startsWith, M as notBetween, N as notIlike, O as lt, P as notInArray, S as ilike, T as isNotNull, _ as endsWith, a as mergedStream, b as gt, c as isUnsetToken, d as arrayContained, f as arrayContains, g as contains, h as column, i as getIndexFields, j as not, k as lte, l as unsetToken, m as between, n as EmptyStream, o as stream, p as arrayOverlaps, r as QueryStream, s as streamIndexRange, t as getByIdWithOrmQueryFallback, u as and, v as eq, w as isFieldReference, x as gte, y as fieldRef } from "../query-context-DEUFBhXS.js";
8
8
  import { v } from "convex/values";
9
9
  import { defineSchema as defineSchema$1, internalActionGeneric, internalMutationGeneric } from "convex/server";
@@ -2485,6 +2485,36 @@ function getColumnName$1(column) {
2485
2485
  function getTableColumns$2(table) {
2486
2486
  return table[Columns] ?? {};
2487
2487
  }
2488
+ function getTablePolymorphicConfigs(table) {
2489
+ const fromMethod = table.getPolymorphicConfigs?.();
2490
+ if (Array.isArray(fromMethod)) return fromMethod;
2491
+ const fromSymbol = table[TablePolymorphic];
2492
+ return Array.isArray(fromSymbol) ? fromSymbol : [];
2493
+ }
2494
+ function enforcePolymorphicWrite(table, candidate, options) {
2495
+ const configs = getTablePolymorphicConfigs(table);
2496
+ if (configs.length === 0) return;
2497
+ for (const config of configs) {
2498
+ const changedFields = options?.changedFields;
2499
+ const discriminatorChanged = !changedFields || changedFields.has(config.discriminator);
2500
+ const generatedFieldChanged = !changedFields || config.generatedFieldNames.some((fieldName) => changedFields.has(fieldName));
2501
+ if (!discriminatorChanged && !generatedFieldChanged) continue;
2502
+ const discriminatorValue = candidate[config.discriminator];
2503
+ if (typeof discriminatorValue !== "string" || !Object.hasOwn(config.variants, discriminatorValue)) throw new Error(`Invalid discriminator '${config.discriminator}' on '${getTableName(table)}'. Expected one of: ${Object.keys(config.variants).join(", ")}.`);
2504
+ const activeVariant = config.variants[discriminatorValue];
2505
+ if (!activeVariant) throw new Error(`Invalid discriminator '${config.discriminator}' value '${discriminatorValue}' on '${getTableName(table)}'.`);
2506
+ for (const requiredFieldName of activeVariant.requiredFieldNames) {
2507
+ const value = candidate[requiredFieldName];
2508
+ if (value === null || value === void 0) throw new Error(`discriminator branch '${discriminatorValue}' requires '${requiredFieldName}' on '${getTableName(table)}'.`);
2509
+ }
2510
+ const activeFieldSet = new Set(activeVariant.fieldNames);
2511
+ for (const generatedFieldName of config.generatedFieldNames) {
2512
+ if (activeFieldSet.has(generatedFieldName)) continue;
2513
+ const value = candidate[generatedFieldName];
2514
+ if (value !== null && value !== void 0) throw new Error(`discriminator branch '${discriminatorValue}' cannot set '${generatedFieldName}' on '${getTableName(table)}' because it belongs to another variant.`);
2515
+ }
2516
+ }
2517
+ }
2488
2518
  function getColumnConfig(table, columnName) {
2489
2519
  const builder = getTableColumns$2(table)[columnName];
2490
2520
  if (!builder) return null;
@@ -2494,8 +2524,20 @@ function applyDefaults(table, value) {
2494
2524
  const columns = table[Columns];
2495
2525
  if (!columns) return value;
2496
2526
  const result = { ...value };
2527
+ const polymorphicConfigs = getTablePolymorphicConfigs(table);
2528
+ const activeGeneratedFields = /* @__PURE__ */ new Set();
2529
+ const generatedFields = /* @__PURE__ */ new Set();
2530
+ for (const config of polymorphicConfigs) {
2531
+ for (const fieldName of config.generatedFieldNames) generatedFields.add(fieldName);
2532
+ const discriminatorValue = result[config.discriminator];
2533
+ if (typeof discriminatorValue !== "string") continue;
2534
+ const activeVariant = config.variants[discriminatorValue];
2535
+ if (!activeVariant) continue;
2536
+ for (const fieldName of activeVariant.fieldNames) activeGeneratedFields.add(fieldName);
2537
+ }
2497
2538
  for (const [columnName, builder] of Object.entries(columns)) {
2498
2539
  if (result[columnName] !== void 0) continue;
2540
+ if (generatedFields.has(columnName) && !activeGeneratedFields.has(columnName)) continue;
2499
2541
  const config = builder.config;
2500
2542
  if (!config) continue;
2501
2543
  if (typeof config.defaultFn === "function") {
@@ -4816,85 +4858,57 @@ var GelRelationalQuery = class extends QueryPromise {
4816
4858
  return filtered;
4817
4859
  }
4818
4860
  _resolvePolymorphicFinalizeState() {
4819
- const rawPolymorphic = this.config.polymorphic;
4820
- if (rawPolymorphic === void 0) return null;
4821
- if (!this._isRecord(rawPolymorphic)) throw new Error("polymorphic must be an object.");
4822
- const discriminator = rawPolymorphic.discriminator;
4823
- if (typeof discriminator !== "string" || discriminator.length === 0) throw new Error("polymorphic.discriminator must be a non-empty string.");
4824
- const aliasRaw = rawPolymorphic.as;
4825
- const alias = aliasRaw === void 0 ? "target" : typeof aliasRaw === "string" && aliasRaw.length > 0 ? aliasRaw : null;
4826
- if (!alias) throw new Error("polymorphic.as must be a non-empty string when set.");
4827
- const schema = rawPolymorphic.schema;
4828
- if (!schema || typeof schema.safeParse !== "function" && typeof schema.parse !== "function") throw new Error("polymorphic.schema must provide safeParse() or parse().");
4829
- const rawCases = rawPolymorphic.cases;
4830
- if (!this._isRecord(rawCases) || Object.keys(rawCases).length === 0) throw new Error("polymorphic.cases must be a non-empty object of discriminator-to-relation mappings.");
4831
- const cases = {};
4832
- for (const [caseKey, caseRelation] of Object.entries(rawCases)) {
4833
- if (typeof caseRelation !== "string" || caseRelation.length === 0) throw new Error(`polymorphic.cases.${caseKey} must be a relation name string.`);
4834
- const relation = this.tableConfig.relations[caseRelation];
4835
- if (!relation) throw new Error(`polymorphic.cases.${caseKey} references unknown relation '${caseRelation}' on '${this.tableConfig.name}'.`);
4836
- if (relation.relationType !== "one") throw new Error(`polymorphic.cases.${caseKey} must map to a one() relation; received '${caseRelation}'.`);
4837
- cases[caseKey] = caseRelation;
4838
- }
4839
- const requestedWith = this.config.with;
4840
- const effectiveWith = requestedWith ? { ...requestedWith } : {};
4841
- const autoLoadedCaseRelations = /* @__PURE__ */ new Set();
4842
- for (const relationName of new Set(Object.values(cases))) if (effectiveWith[relationName] === void 0) {
4843
- effectiveWith[relationName] = true;
4844
- autoLoadedCaseRelations.add(relationName);
4845
- }
4846
- return {
4847
- requestedWith,
4848
- effectiveWith: Object.keys(effectiveWith).length ? effectiveWith : void 0,
4849
- autoLoadedCaseRelations,
4850
- discriminator,
4851
- alias,
4852
- cases,
4853
- schema
4854
- };
4855
- }
4856
- _extractPolymorphicSchemaErrorMessage(error) {
4857
- if (!error || typeof error !== "object") return String(error);
4858
- const issueMessage = error.issues?.[0]?.message;
4859
- if (issueMessage) return issueMessage;
4860
- return error.message ?? String(error);
4861
- }
4862
- _synthesizePolymorphicRows(rows, config) {
4863
- for (const row of rows) {
4861
+ const configs = this.tableConfig.polymorphic;
4862
+ if (!configs || configs.length === 0) return null;
4863
+ return { configs };
4864
+ }
4865
+ _resolveWithVariantsState(requestedWith, polymorphicState) {
4866
+ const withVariants = this.config.withVariants;
4867
+ if (withVariants === void 0 || withVariants === false) return { effectiveWith: requestedWith };
4868
+ if (withVariants !== true) throw new Error("withVariants currently supports only `true`.");
4869
+ if (!polymorphicState) throw new Error(`withVariants is only available on tables with discriminator(...) columns ('${this.tableConfig.name}').`);
4870
+ const oneRelations = Object.entries(this.tableConfig.relations).filter(([, relation]) => relation.relationType === "one");
4871
+ if (oneRelations.length === 0) return { effectiveWith: requestedWith };
4872
+ const autoWith = Object.fromEntries(oneRelations.map(([relationName]) => [relationName, true]));
4873
+ return { effectiveWith: requestedWith ? {
4874
+ ...autoWith,
4875
+ ...requestedWith
4876
+ } : autoWith };
4877
+ }
4878
+ _assertPolymorphicAliasCollisions(configs, requestedWith, resolvedExtras) {
4879
+ const tableColumns = this._getColumns(this.tableConfig);
4880
+ const extras = this._isRecord(resolvedExtras) ? resolvedExtras : void 0;
4881
+ for (const config of configs) {
4882
+ if (config.alias in tableColumns) throw new Error(`discriminator alias '${config.alias}' on '${this.tableConfig.name}' conflicts with an existing column.`);
4883
+ if (config.alias in this.tableConfig.relations) throw new Error(`discriminator alias '${config.alias}' on '${this.tableConfig.name}' conflicts with a relation.`);
4884
+ if (requestedWith && config.alias in requestedWith) throw new Error(`discriminator alias '${config.alias}' on '${this.tableConfig.name}' conflicts with with.${config.alias}.`);
4885
+ if (extras && config.alias in extras) throw new Error(`discriminator alias '${config.alias}' on '${this.tableConfig.name}' conflicts with extras.${config.alias}.`);
4886
+ }
4887
+ }
4888
+ _synthesizePolymorphicRows(rows, configs) {
4889
+ for (const row of rows) for (const config of configs) {
4864
4890
  const discriminatorValue = row[config.discriminator];
4865
4891
  const caseKey = String(discriminatorValue);
4866
- const relationName = config.cases[caseKey];
4867
- if (!relationName) throw new Error(`polymorphic discriminator '${config.discriminator}' value '${caseKey}' has no matching case mapping.`);
4868
- const targetValue = row[relationName];
4869
- if (targetValue === null || targetValue === void 0) throw new Error(`polymorphic case '${caseKey}' resolved relation '${relationName}' but no target row was loaded.`);
4870
- row[config.alias] = targetValue;
4871
- const payload = {
4872
- [config.discriminator]: discriminatorValue,
4873
- [config.alias]: targetValue
4874
- };
4875
- if (typeof config.schema.safeParse === "function") {
4876
- const result = config.schema.safeParse(payload);
4877
- if (!result.success) throw new Error(`polymorphic schema parse failed: ${this._extractPolymorphicSchemaErrorMessage(result.error)}`);
4878
- } else if (typeof config.schema.parse === "function") try {
4879
- config.schema.parse(payload);
4880
- } catch (error) {
4881
- throw new Error(`polymorphic schema parse failed: ${this._extractPolymorphicSchemaErrorMessage(error)}`);
4882
- }
4883
- }
4884
- for (const relationName of config.autoLoadedCaseRelations) {
4885
- if (relationName === config.alias) continue;
4886
- for (const row of rows) delete row[relationName];
4892
+ const variant = config.variants[caseKey];
4893
+ if (!variant) throw new Error(`discriminator '${config.discriminator}' value '${caseKey}' has no matching variant on '${this.tableConfig.name}'.`);
4894
+ const nested = {};
4895
+ for (const fieldName of variant.fieldNames) nested[fieldName] = row[fieldName];
4896
+ row[config.alias] = nested;
4887
4897
  }
4888
4898
  }
4889
4899
  async _finalizeRows(rows) {
4890
4900
  const polymorphicState = this._resolvePolymorphicFinalizeState();
4891
- const requestedWith = polymorphicState?.requestedWith ?? this.config.with;
4892
- const effectiveWith = polymorphicState?.effectiveWith ?? this.config.with;
4901
+ const requestedWith = this.config.with;
4902
+ const effectiveWith = this._resolveWithVariantsState(requestedWith, polymorphicState).effectiveWith;
4903
+ const tableColumns = this._getColumns(this.tableConfig);
4904
+ const extrasConfig = this.config.extras;
4905
+ const resolvedExtras = typeof extrasConfig === "function" ? extrasConfig(tableColumns) : extrasConfig;
4906
+ if (polymorphicState) this._assertPolymorphicAliasCollisions(polymorphicState.configs, requestedWith, resolvedExtras);
4893
4907
  let rowsWithRelations = rows;
4894
4908
  if (effectiveWith) rowsWithRelations = await this._loadRelations(rowsWithRelations, effectiveWith, 0, 3, this.edgeMetadata, this.tableConfig);
4895
- if (polymorphicState) this._synthesizePolymorphicRows(rowsWithRelations, polymorphicState);
4896
- if (this.config.extras) rowsWithRelations = this._applyExtras(rowsWithRelations, this.config.extras, this._getColumns(this.tableConfig), requestedWith, this.tableConfig.name, this.tableConfig);
4897
- return this._selectColumns(rowsWithRelations, this.config.columns, this._getColumns(this.tableConfig), this.tableConfig);
4909
+ if (polymorphicState) this._synthesizePolymorphicRows(rowsWithRelations, polymorphicState.configs);
4910
+ if (resolvedExtras) rowsWithRelations = this._applyExtras(rowsWithRelations, resolvedExtras, tableColumns, effectiveWith, this.tableConfig.name, this.tableConfig);
4911
+ return this._selectColumns(rowsWithRelations, this.config.columns, tableColumns, this.tableConfig);
4898
4912
  }
4899
4913
  _getSchemaDefinitionOrThrow() {
4900
4914
  const schemaDefinition = this.schema[OrmSchemaDefinition];
@@ -6036,7 +6050,6 @@ var GelRelationalQuery = class extends QueryPromise {
6036
6050
  if (config.with !== void 0) throw new Error("pipeline cannot be combined with with in findMany().");
6037
6051
  if (config.extras !== void 0) throw new Error("pipeline cannot be combined with extras in findMany().");
6038
6052
  if (config.columns !== void 0) throw new Error("pipeline cannot be combined with columns in findMany().");
6039
- if (config.polymorphic !== void 0) throw new Error("pipeline cannot be combined with polymorphic in findMany().");
6040
6053
  }
6041
6054
  if (pageByKey) {
6042
6055
  if (this.mode !== "many") throw new Error("pageByKey is only supported on findMany().");
@@ -7534,6 +7547,7 @@ var ConvexInsertBuilder = class extends QueryPromise {
7534
7547
  const results = [];
7535
7548
  for (const value of this.valuesList) {
7536
7549
  const preparedValue = normalizeDateFieldsForWrite(this.table, applyDefaults(this.table, value));
7550
+ enforcePolymorphicWrite(this.table, preparedValue);
7537
7551
  const rls = ormContext?.rls;
7538
7552
  const tableName = getTableName(this.table);
7539
7553
  if (!await canInsertRow({
@@ -8265,27 +8279,18 @@ var RelationalQueryBuilder = class RelationalQueryBuilder {
8265
8279
  return new GelRankQuery(this.db, this.tableConfig, indexName, config, this.rls);
8266
8280
  }
8267
8281
  findMany(config) {
8268
- if (config && config.pipeline !== void 0) {
8269
- if (config.polymorphic !== void 0) throw new Error("polymorphic cannot be combined with pipeline in findMany().");
8270
- throw new Error("findMany({ pipeline }) is removed; use db.query.<table>.select() chain instead");
8271
- }
8282
+ if (config && config.pipeline !== void 0) throw new Error("findMany({ pipeline }) is removed; use db.query.<table>.select() chain instead");
8272
8283
  return this.createQuery(config ? config : {}, "many");
8273
8284
  }
8274
8285
  findFirst(config) {
8275
- if (config && config.pipeline !== void 0) {
8276
- if (config.polymorphic !== void 0) throw new Error("polymorphic cannot be combined with pipeline in findFirst().");
8277
- throw new Error("findMany({ pipeline }) is removed; use db.query.<table>.select() chain instead");
8278
- }
8286
+ if (config && config.pipeline !== void 0) throw new Error("findMany({ pipeline }) is removed; use db.query.<table>.select() chain instead");
8279
8287
  return this.createQuery({
8280
8288
  ...config ? config : {},
8281
8289
  limit: 1
8282
8290
  }, "first");
8283
8291
  }
8284
8292
  findFirstOrThrow(config) {
8285
- if (config && config.pipeline !== void 0) {
8286
- if (config.polymorphic !== void 0) throw new Error("polymorphic cannot be combined with pipeline in findFirstOrThrow().");
8287
- throw new Error("findMany({ pipeline }) is removed; use db.query.<table>.select() chain instead");
8288
- }
8293
+ if (config && config.pipeline !== void 0) throw new Error("findMany({ pipeline }) is removed; use db.query.<table>.select() chain instead");
8289
8294
  return this.createQuery({
8290
8295
  ...config ? config : {},
8291
8296
  limit: 1
@@ -8593,6 +8598,7 @@ var ConvexUpdateBuilder = class extends QueryPromise {
8593
8598
  const fkBatchSize = isPaginated ? pagination.limit : batchSize;
8594
8599
  for (const { row, updatedRow, decision } of updates) {
8595
8600
  if (!decision.allowed) continue;
8601
+ enforcePolymorphicWrite(this.table, updatedRow, { changedFields: new Set(Object.keys(effectiveSet)) });
8596
8602
  enforceCheckConstraints(this.table, updatedRow);
8597
8603
  await enforceForeignKeys(this.db, this.table, updatedRow, { changedFields: new Set(Object.keys(effectiveSet)) });
8598
8604
  await applyIncomingForeignKeyActionsOnUpdate(this.db, this.table, row, updatedRow, {
@@ -9974,6 +9980,7 @@ function buildRelations(tables, config, strict, defaults) {
9974
9980
  for (const [tsName, table] of Object.entries(tables)) tablesConfig[tsName] = {
9975
9981
  table,
9976
9982
  name: tsName,
9983
+ polymorphic: table[TablePolymorphic],
9977
9984
  relations: config[tsName] ?? {},
9978
9985
  strict,
9979
9986
  defaults
@@ -9987,6 +9994,7 @@ function buildRelationsParts(tables, config, strict, defaults) {
9987
9994
  tablesConfig[tsName] = {
9988
9995
  table: tables[tsName],
9989
9996
  name: tsName,
9997
+ polymorphic: tables[tsName][TablePolymorphic],
9990
9998
  relations,
9991
9999
  strict,
9992
10000
  defaults
@@ -10234,4 +10242,4 @@ function defineSchema(schema, options) {
10234
10242
  }
10235
10243
 
10236
10244
  //#endregion
10237
- export { Brand, Columns, OrmNotFoundError, OrmSchemaPluginTables, RlsPolicy, RlsRole, TableName, aggregateIndex, and, arrayOf, asc, between, bigint, boolean, buildMigrationPlan, bytes, check, contains, convexTable, createOrm, custom, date, defineMigration, defineMigrationSet, defineRelations, defineRelationsPart, defineSchema, defineTriggers, deletion, deprecated, desc, detectMigrationDrift, endsWith, eq, extractRelationsConfig, fieldRef, foreignKey, getByIdWithOrmQueryFallback, getTableColumns, getTableConfig, gt, gte, id, ilike, inArray, index, integer, isFieldReference, isNotNull, isNull, json, like, lt, lte, ne, not, notBetween, notInArray, objectOf, or, pretend, pretendRequired, rankIndex, rlsPolicy, rlsRole, scheduledDeleteFactory, scheduledMutationBatchFactory, searchIndex, startsWith, text, textEnum, timestamp, unique, uniqueIndex, unsetToken, vector, vectorIndex };
10245
+ export { Brand, Columns, OrmNotFoundError, OrmSchemaPluginTables, RlsPolicy, RlsRole, TableName, aggregateIndex, and, arrayOf, asc, between, bigint, boolean, buildMigrationPlan, bytes, check, contains, convexTable, createOrm, custom, date, defineMigration, defineMigrationSet, defineRelations, defineRelationsPart, defineSchema, defineTriggers, deletion, deprecated, desc, detectMigrationDrift, discriminator, endsWith, eq, extractRelationsConfig, fieldRef, foreignKey, getByIdWithOrmQueryFallback, getTableColumns, getTableConfig, gt, gte, id, ilike, inArray, index, integer, isFieldReference, isNotNull, isNull, json, like, lt, lte, ne, not, notBetween, notInArray, objectOf, or, pretend, pretendRequired, rankIndex, rlsPolicy, rlsRole, scheduledDeleteFactory, scheduledMutationBatchFactory, searchIndex, startsWith, text, textEnum, timestamp, unique, uniqueIndex, unsetToken, vector, vectorIndex };
@@ -1,8 +1,8 @@
1
- import "../validators-BcQFm1oY.js";
2
- import { k as migrationPlugin, ri as OrmSchemaPlugin } from "../where-clause-compiler-m-GQNB_K.js";
3
- import "../query-context-ji7By8u0.js";
4
- import "../orm/index.js";
1
+ import { ii as OrmSchemaPlugin } from "../where-clause-compiler-UavDdMUX.js";
5
2
 
3
+ //#region src/orm/migrations/schema.d.ts
4
+ declare function migrationPlugin(): OrmSchemaPlugin;
5
+ //#endregion
6
6
  //#region src/orm/aggregate-index/schema.d.ts
7
7
  declare function aggregatePlugin(): OrmSchemaPlugin;
8
8
  //#endregion
@@ -1,3 +1,3 @@
1
- import { c as aggregatePlugin, r as migrationPlugin } from "../schema-Bx6j2doh.js";
1
+ import { c as aggregatePlugin, r as migrationPlugin } from "../schema-Cw5-LWTg.js";
2
2
 
3
3
  export { aggregatePlugin, migrationPlugin };
@@ -1,7 +1,4 @@
1
- import "../../validators-BcQFm1oY.js";
2
- import { ri as OrmSchemaPlugin } from "../../where-clause-compiler-m-GQNB_K.js";
3
- import "../../query-context-ji7By8u0.js";
4
- import "../../orm/index.js";
1
+ import { ii as OrmSchemaPlugin } from "../../where-clause-compiler-UavDdMUX.js";
5
2
  import * as convex_server0 from "convex/server";
6
3
 
7
4
  //#region src/plugins/ratelimit/duration.d.ts
@@ -1,5 +1,5 @@
1
- import { C as integer, g as index, t as convexTable, x as text } from "../../table-B7yzBihE.js";
2
- import { t as textEnum } from "../../text-enum-CFdcLUuw.js";
1
+ import { C as text, T as integer, t as convexTable, v as index } from "../../table-Bxqm450r.js";
2
+ import { t as textEnum } from "../../text-enum-KyijdQ8Q.js";
3
3
  import { v } from "convex/values";
4
4
  import { mutationGeneric, queryGeneric } from "convex/server";
5
5
 
@@ -1,5 +1,5 @@
1
- import { C as integer, g as index, t as convexTable, x as text } from "./table-B7yzBihE.js";
2
- import { r as custom, t as id } from "./id-BcBb900m.js";
1
+ import { C as text, T as integer, t as convexTable, v as index } from "./table-Bxqm450r.js";
2
+ import { r as custom, t as id } from "./id-BF_SaWhQ.js";
3
3
  import { ConvexError, convexToJson, jsonToConvex, v } from "convex/values";
4
4
 
5
5
  //#region src/aggregate-core/compare.ts
@@ -1,5 +1,5 @@
1
- import { C as integer, T as entityKind, g as index, t as convexTable, w as ConvexColumnBuilder, x as text } from "./table-B7yzBihE.js";
2
- import { r as custom, t as id } from "./id-BcBb900m.js";
1
+ import { C as text, D as entityKind, E as ConvexColumnBuilder, T as integer, t as convexTable, v as index } from "./table-Bxqm450r.js";
2
+ import { r as custom, t as id } from "./id-BF_SaWhQ.js";
3
3
  import { v } from "convex/values";
4
4
 
5
5
  //#region src/orm/builders/boolean.ts
@@ -1,4 +1,3 @@
1
- import "../validators-BcQFm1oY.js";
2
1
  import { $ as QueryProcedureBuilder, A as GenericCtx, B as ConvexContext, C as CRPC_ERROR_CODE_TO_HTTP, Ct as zodToConvex, D as toCRPCError, E as isCRPCError, F as isRunMutationCtx, G as CallerOpts, H as LazyCaller, I as requireActionCtx, J as createApiLeaf, K as ServerCaller, L as requireMutationCtx, M as isActionCtx, N as isMutationCtx, O as CreateEnvOptions, P as isQueryCtx, Q as ProcedureBuilder, R as requireQueryCtx, S as CRPC_ERROR_CODES_BY_KEY, St as zodOutputToConvexFields, T as getHTTPStatusCodeFromError, U as createLazyCaller, V as createCallerFactory, W as CallerMeta, X as CRPCFunctionTypeHint, Y as ActionProcedureBuilder, Z as MutationProcedureBuilder, _ as WithHttpRouter, _t as zCustomAction, a as ProcedureCaller, at as handleHttpError, b as CRPCError, bt as zid, c as ProcedureFromFunctionReference, ct as ConvexValidatorFromZodOutput, d as createGenericCallerFactory, dt as Zid, et as createMiddlewareFactory, f as createGenericHandlerFactory, ft as ZodFromValidatorBase, g as typedProcedureResolver, gt as withSystemFields, h as defineProcedure, ht as convexToZodFields, i as ProcedureActionCallerFromRegistry, it as extractPathParams, j as RunMutationCtx, k as createEnv, l as ProcedureSchedulableCallerFromRegistry, lt as CustomBuilder, m as createProcedureHandlerFactory, mt as convexToZod, n as GeneratedProcedureRegistry, nt as HttpProcedureBuilder, o as ProcedureCallerFromRegistry, ot as matchPathParams, p as createProcedureCallerFactory, pt as ZodValidatorFromConvex, q as createServerCaller, r as GeneratedProcedureRegistryEntry, rt as createHttpProcedureBuilder, s as ProcedureDefinition, st as ConvexValidatorFromZod, t as CreateProcedureCallerFactoryOptions, tt as initCRPC, u as ProcedureScheduleCallerFromRegistry, ut as ZCustomCtx, v as inferApiInputs, vt as zCustomMutation, w as getCRPCErrorFromUnknown, wt as zodToConvexFields, x as CRPCErrorCode, xt as zodOutputToConvex, y as inferApiOutputs, yt as zCustomQuery, z as requireRunMutationCtx } from "../procedure-caller-DYjpq7rG.js";
3
2
  import { A as GetRawInputFn, B as Simplify, C as HttpProcedure, D as ProcedureMeta, E as InferHttpInput, F as MiddlewareMarker, I as MiddlewareNext, L as MiddlewareResult, M as MergeZodObjects, N as MiddlewareBuilder, O as AnyMiddleware, P as MiddlewareFunction, R as Overwrite, S as HttpMethod, T as HttpRouteDefinition, V as UnsetMarker, _ as extractRouteMap, b as HttpActionHandler, d as CRPCHttpRouter, f as HttpRouterDef, g as createHttpRouterFactory, h as createHttpRouter, j as IntersectIfDefined, k as AnyMiddlewareBuilder, m as HttpRouterWithHono, p as HttpRouterRecord, v as CRPCHonoHandler, w as HttpProcedureBuilderDef, x as HttpHandlerOpts, y as HttpActionConstructor, z as ResolveIfSet } from "../http-types-BK7FuIcR.js";
4
3
  export { ActionProcedureBuilder, AnyMiddleware, AnyMiddlewareBuilder, CRPCError, CRPCErrorCode, CRPCFunctionTypeHint, CRPCHonoHandler, CRPCHttpRouter, CRPC_ERROR_CODES_BY_KEY, CRPC_ERROR_CODE_TO_HTTP, CallerMeta, CallerOpts, ConvexContext, ConvexValidatorFromZod, ConvexValidatorFromZodOutput, CreateEnvOptions, CreateProcedureCallerFactoryOptions, CustomBuilder, GeneratedProcedureRegistry, GeneratedProcedureRegistryEntry, GenericCtx, GetRawInputFn, HttpActionConstructor, HttpActionHandler, HttpHandlerOpts, HttpMethod, HttpProcedure, HttpProcedureBuilder, HttpProcedureBuilderDef, HttpRouteDefinition, HttpRouterDef, HttpRouterRecord, HttpRouterWithHono, InferHttpInput, IntersectIfDefined, LazyCaller, MergeZodObjects, MiddlewareBuilder, MiddlewareFunction, MiddlewareMarker, MiddlewareNext, MiddlewareResult, MutationProcedureBuilder, Overwrite, ProcedureActionCallerFromRegistry, ProcedureBuilder, ProcedureCaller, ProcedureCallerFromRegistry, ProcedureDefinition, ProcedureFromFunctionReference, ProcedureMeta, ProcedureSchedulableCallerFromRegistry, ProcedureScheduleCallerFromRegistry, QueryProcedureBuilder, ResolveIfSet, RunMutationCtx, ServerCaller, Simplify, UnsetMarker, WithHttpRouter, ZCustomCtx, Zid, ZodFromValidatorBase, ZodValidatorFromConvex, convexToZod, convexToZodFields, createApiLeaf, createCallerFactory, createEnv, createGenericCallerFactory, createGenericHandlerFactory, createHttpProcedureBuilder, createHttpRouter, createHttpRouterFactory, createLazyCaller, createMiddlewareFactory, createProcedureCallerFactory, createProcedureHandlerFactory, createServerCaller, defineProcedure, extractPathParams, extractRouteMap, getCRPCErrorFromUnknown, getHTTPStatusCodeFromError, handleHttpError, inferApiInputs, inferApiOutputs, initCRPC, isActionCtx, isCRPCError, isMutationCtx, isQueryCtx, isRunMutationCtx, matchPathParams, requireActionCtx, requireMutationCtx, requireQueryCtx, requireRunMutationCtx, toCRPCError, typedProcedureResolver, withSystemFields, zCustomAction, zCustomMutation, zCustomQuery, zid, zodOutputToConvex, zodOutputToConvexFields, zodToConvex, zodToConvexFields };
@@ -529,6 +529,7 @@ const OrmContext = Symbol.for("better-convex:OrmContext");
529
529
  const RlsPolicies = Symbol.for("better-convex:RlsPolicies");
530
530
  const EnableRLS = Symbol.for("better-convex:EnableRLS");
531
531
  const TableDeleteConfig = Symbol.for("better-convex:TableDeleteConfig");
532
+ const TablePolymorphic = Symbol.for("better-convex:TablePolymorphic");
532
533
  const OrmSchemaOptions = Symbol.for("better-convex:OrmSchemaOptions");
533
534
  const OrmSchemaDefinition = Symbol.for("better-convex:OrmSchemaDefinition");
534
535
  const OrmSchemaPluginTables = Symbol.for("better-convex:OrmSchemaPluginTables");
@@ -544,6 +545,8 @@ const RESERVED_COLUMN_NAMES = new Set([
544
545
  "_id",
545
546
  "_creationTime"
546
547
  ]);
548
+ const DEFAULT_POLYMORPHIC_ALIAS = "details";
549
+ const CONVEX_TABLE_FIELD_LIMIT = 1024;
547
550
  /**
548
551
  * Valid table name pattern: starts with letter/underscore, contains only alphanumeric and underscore
549
552
  */
@@ -568,6 +571,21 @@ function createValidatorFromColumns(columns) {
568
571
  const validatorFields = Object.fromEntries(Object.entries(columns).map(([key, builder]) => [key, builder.convexValidator]));
569
572
  return v.object(validatorFields);
570
573
  }
574
+ function discriminator(config) {
575
+ if (!config || typeof config !== "object") throw new Error("discriminator(...) requires a config object.");
576
+ if (!config.variants || typeof config.variants !== "object" || Object.keys(config.variants).length === 0) throw new Error("discriminator(...).variants must contain at least one case.");
577
+ if (config.as !== void 0 && (typeof config.as !== "string" || config.as.length === 0)) throw new Error("discriminator(...).as must be a non-empty string when set.");
578
+ const builder = text().notNull();
579
+ builder.__polymorphic = {
580
+ as: config.as ?? DEFAULT_POLYMORPHIC_ALIAS,
581
+ variants: config.variants
582
+ };
583
+ builder.config.discriminator = {
584
+ as: config.as,
585
+ variants: config.variants
586
+ };
587
+ return builder;
588
+ }
571
589
  var ConvexDeletionBuilder = class {
572
590
  static [entityKind] = "ConvexDeletionBuilder";
573
591
  [entityKind] = "ConvexDeletionBuilder";
@@ -699,6 +717,86 @@ function assertRankOrderFieldType(column, indexName) {
699
717
  ].includes(columnType)) throw new Error(`rankIndex '${indexName}' orderBy() supports integer()/timestamp()/date() columns only. Field '${getColumnName(column)}' is type '${columnType}'.`);
700
718
  }
701
719
  const dedupeFieldNames = (fields) => [...new Set(fields)];
720
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
721
+ const isColumnBuilder = (value) => isRecord(value) && typeof value.build === "function";
722
+ const getDiscriminatorConfig = (value) => {
723
+ if (!isColumnBuilder(value)) return;
724
+ const discriminator = value.config?.discriminator;
725
+ if (!discriminator) return;
726
+ return discriminator;
727
+ };
728
+ const getPolymorphicFieldSignature = (column) => {
729
+ const validator = column.convexValidator ?? column.build();
730
+ return JSON.stringify({
731
+ columnType: column.config?.columnType,
732
+ validator: validator?.json
733
+ });
734
+ };
735
+ function resolveTableColumns(tableName, columns) {
736
+ const resolvedColumns = {};
737
+ const pendingPolymorphic = [];
738
+ for (const [columnName, rawBuilder] of Object.entries(columns)) {
739
+ if (!isColumnBuilder(rawBuilder)) throw new Error(`Column '${columnName}' on '${tableName}' must be a column builder.`);
740
+ resolvedColumns[columnName] = rawBuilder;
741
+ const discriminatorConfig = getDiscriminatorConfig(rawBuilder);
742
+ if (!discriminatorConfig) continue;
743
+ if (!isRecord(discriminatorConfig.variants) || Object.keys(discriminatorConfig.variants).length === 0) throw new Error(`discriminator('${tableName}.${columnName}') requires at least one variant.`);
744
+ const alias = discriminatorConfig.as === void 0 ? DEFAULT_POLYMORPHIC_ALIAS : discriminatorConfig.as;
745
+ if (typeof alias !== "string" || alias.length === 0) throw new Error(`discriminator('${tableName}.${columnName}').as must be a non-empty string.`);
746
+ pendingPolymorphic.push({
747
+ discriminator: columnName,
748
+ alias,
749
+ variants: discriminatorConfig.variants
750
+ });
751
+ }
752
+ if (pendingPolymorphic.length > 1) throw new Error(`Only one discriminator(...) column is currently supported on '${tableName}'.`);
753
+ const polymorphicConfigs = [];
754
+ for (const pending of pendingPolymorphic) {
755
+ if (pending.alias in resolvedColumns) throw new Error(`discriminator('${tableName}.${pending.discriminator}') alias '${pending.alias}' collides with an existing column.`);
756
+ const generatedFieldMap = /* @__PURE__ */ new Map();
757
+ const variantRuntime = {};
758
+ for (const [variantKey, rawVariantColumns] of Object.entries(pending.variants)) {
759
+ if (!isRecord(rawVariantColumns)) throw new Error(`discriminator('${tableName}.${pending.discriminator}') variant '${variantKey}' must be an object.`);
760
+ const fieldNames = [];
761
+ const requiredFieldNames = [];
762
+ for (const [fieldName, rawFieldBuilder] of Object.entries(rawVariantColumns)) {
763
+ if (!isColumnBuilder(rawFieldBuilder)) throw new Error(`discriminator('${tableName}.${pending.discriminator}').variants.${variantKey}.${fieldName} must be a column builder.`);
764
+ if (fieldName in resolvedColumns) throw new Error(`discriminator('${tableName}.${pending.discriminator}').variants.${variantKey}.${fieldName} collides with an existing table column.`);
765
+ const fieldBuilder = rawFieldBuilder;
766
+ const fieldConfig = fieldBuilder.config;
767
+ const isRequiredForVariant = fieldConfig?.notNull === true && fieldConfig.hasDefault !== true && typeof fieldConfig.defaultFn !== "function";
768
+ const signature = getPolymorphicFieldSignature(fieldBuilder);
769
+ const existing = generatedFieldMap.get(fieldName);
770
+ if (existing && existing.signature !== signature) throw new Error(`discriminator('${tableName}.${pending.discriminator}') field '${fieldName}' has conflicting builder signatures across variants.`);
771
+ if (!existing) {
772
+ if (fieldConfig) fieldConfig.notNull = false;
773
+ generatedFieldMap.set(fieldName, {
774
+ builder: fieldBuilder,
775
+ signature
776
+ });
777
+ }
778
+ fieldNames.push(fieldName);
779
+ if (isRequiredForVariant) requiredFieldNames.push(fieldName);
780
+ }
781
+ variantRuntime[variantKey] = {
782
+ fieldNames,
783
+ requiredFieldNames
784
+ };
785
+ }
786
+ for (const [fieldName, { builder }] of generatedFieldMap.entries()) resolvedColumns[fieldName] = builder;
787
+ polymorphicConfigs.push({
788
+ discriminator: pending.discriminator,
789
+ alias: pending.alias,
790
+ generatedFieldNames: Object.freeze([...generatedFieldMap.keys()]),
791
+ variants: Object.freeze(variantRuntime)
792
+ });
793
+ }
794
+ if (Object.keys(resolvedColumns).length > CONVEX_TABLE_FIELD_LIMIT) throw new Error(`Table '${tableName}' exceeds Convex field count limit (${CONVEX_TABLE_FIELD_LIMIT}) after discriminator expansion.`);
795
+ return {
796
+ columns: resolvedColumns,
797
+ polymorphicConfigs
798
+ };
799
+ }
702
800
  function applyExtraConfig(table, config) {
703
801
  if (!config) return;
704
802
  const entries = Array.isArray(config) ? config : Object.values(config);
@@ -920,11 +1018,12 @@ var ConvexTableImpl = class {
920
1018
  [EnableRLS] = false;
921
1019
  [RlsPolicies] = [];
922
1020
  [TableDeleteConfig];
1021
+ [TablePolymorphic];
923
1022
  /**
924
1023
  * Public tableName for convenience
925
1024
  */
926
1025
  tableName;
927
- constructor(name, columns) {
1026
+ constructor(name, columns, polymorphicConfigs) {
928
1027
  validateTableName(name);
929
1028
  for (const columnName of Object.keys(columns)) if (RESERVED_COLUMN_NAMES.has(columnName)) throw new Error(`Column name '${columnName}' is reserved. System fields are managed by Convex ORM.`);
930
1029
  this[TableName] = name;
@@ -936,6 +1035,7 @@ var ConvexTableImpl = class {
936
1035
  }));
937
1036
  this[Columns] = namedColumns;
938
1037
  this.tableName = name;
1038
+ if (polymorphicConfigs && polymorphicConfigs.length > 0) this[TablePolymorphic] = polymorphicConfigs;
939
1039
  this.validator = createValidatorFromColumns(namedColumns);
940
1040
  for (const [columnName, builder] of Object.entries(namedColumns)) {
941
1041
  const config = builder.config;
@@ -958,6 +1058,9 @@ var ConvexTableImpl = class {
958
1058
  });
959
1059
  }
960
1060
  }
1061
+ getPolymorphicConfigs() {
1062
+ return this[TablePolymorphic];
1063
+ }
961
1064
  /**
962
1065
  * Internal: add index to table from builder extraConfig
963
1066
  *
@@ -1163,7 +1266,8 @@ var ConvexTableImpl = class {
1163
1266
  }
1164
1267
  };
1165
1268
  const convexTableInternal = (name, columns, extraConfig) => {
1166
- const rawTable = new ConvexTableImpl(name, columns);
1269
+ const expanded = resolveTableColumns(name, columns);
1270
+ const rawTable = new ConvexTableImpl(name, expanded.columns, expanded.polymorphicConfigs);
1167
1271
  const systemFields = createSystemFields(name);
1168
1272
  for (const builder of Object.values(systemFields)) builder.config.table = rawTable;
1169
1273
  const table = Object.assign(rawTable, systemFields, rawTable[Columns]);
@@ -1192,4 +1296,4 @@ const convexTableWithRLS = (name, columns, extraConfig) => {
1192
1296
  const convexTable = Object.assign(convexTableInternal, { withRLS: convexTableWithRLS });
1193
1297
 
1194
1298
  //#endregion
1195
- export { integer as C, createSystemFields as S, entityKind as T, rankIndex as _, EnableRLS as a, vectorIndex as b, OrmSchemaOptions as c, TableDeleteConfig as d, TableName as f, index as g, aggregateIndex as h, Columns as i, OrmSchemaPluginTables as l, rlsPolicy as m, deletion as n, OrmContext as o, RlsPolicy as p, Brand as r, OrmSchemaDefinition as s, convexTable as t, RlsPolicies as u, searchIndex as v, ConvexColumnBuilder as w, text as x, uniqueIndex as y };
1299
+ export { text as C, entityKind as D, ConvexColumnBuilder as E, vectorIndex as S, integer as T, aggregateIndex as _, Columns as a, searchIndex as b, OrmSchemaDefinition as c, RlsPolicies as d, TableDeleteConfig as f, rlsPolicy as g, RlsPolicy as h, Brand as i, OrmSchemaOptions as l, TablePolymorphic as m, deletion as n, EnableRLS as o, TableName as p, discriminator as r, OrmContext as s, convexTable as t, OrmSchemaPluginTables as u, index as v, createSystemFields as w, uniqueIndex as x, rankIndex as y };
@@ -1,4 +1,4 @@
1
- import { T as entityKind, w as ConvexColumnBuilder } from "./table-B7yzBihE.js";
1
+ import { D as entityKind, E as ConvexColumnBuilder } from "./table-Bxqm450r.js";
2
2
  import { v } from "convex/values";
3
3
 
4
4
  //#region src/orm/builders/text-enum.ts