arkormx 2.8.0 → 2.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/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as applyOperationsToPersistedColumnMappingsState, $t as resolvePrismaType, A as getRuntimePrismaClient, An as writeAppliedMigrationsStateToStore, At as buildInverseRelationLine, B as getRegisteredModels, Bt as deriveRelationFieldName, C as getActiveTransactionClient, Cn as markMigrationRun, Ct as applyMigrationRollbackToPrismaSchema, D as getRuntimeDebugHandler, Dn as resolveMigrationStateFilePath, Dt as buildEnumBlock, E as getRuntimeClient, En as removeAppliedMigration, Et as applyOperationsToPrismaSchema, F as loadArkormConfig, Fn as RelationResolutionException, Ft as buildUniqueConstraintLine, G as loadModelsFrom, Gt as formatDefaultValue, H as getRegisteredSeeders, Ht as escapeRegex, I as resetArkormRuntimeForTests, In as ArkormCollection, It as createMigrationTimestamp, J as registerMigrations, Jt as generateMigrationFile, K as loadSeedersFrom, Kt as formatEnumDefaultValue, L as runArkormTransaction, Ln as ArkormException, Lt as deriveCollectionFieldName, M as isDelegateLike, Mn as UnsupportedAdapterFeatureException, Mt as buildModelBlock, N as isQuerySchemaLike, Nn as SetBasedEagerLoader, Nt as buildPrimaryKeyLine, O as getRuntimePaginationCurrentPageResolver, On as supportsDatabaseMigrationState, Ot as buildFieldLine, P as isTransactionCapableClient, Pt as buildRelationLine, Q as resetRuntimeRegistryForTests, Qt as resolveMigrationClassName, R as getRegisteredFactories, Rt as deriveInverseRelationAlias, S as getActiveTransactionAdapter, Sn as markMigrationApplied, St as applyMigrationRollbackToDatabase, T as getRuntimeAdapter, Tn as readAppliedMigrationsStateFromStore, Tt as applyMigrationToPrismaSchema, U as loadFactoriesFrom, Ut as findEnumBlock, V as getRegisteredPaths, Vt as deriveSingularFieldName, W as loadMigrationsFrom, Wt as findModelBlock, X as registerPaths, Xt as pad, Y as registerModels, Yt as getMigrationPlan, Z as registerSeeders, Zt as resolveEnumName, _ as bindAdapterToModels, _n as deleteAppliedMigrationsStateFromStore, _t as PRISMA_ENUM_REGEX, a as HasOneThroughRelation, an as supportsDatabaseReset, at as getPersistedPrimaryKeyGeneration, b as emitRuntimeDebugEvent, bn as getLatestAppliedMigrations, bt as applyCreateTableOperation, c as HasManyRelation, cn as SchemaBuilder, ct as readPersistedColumnMappingsState, d as BelongsToManyRelation, dn as PrimaryKeyGenerationPlanner, dt as resolveColumnMappingsFilePath, en as runMigrationWithPrisma, et as createEmptyPersistedColumnMappingsState, f as Relation, fn as ForeignKeyBuilder, ft as resolvePersistedMetadataFeatures, g as awaitConfiguredModelsRegistration, gn as createEmptyAppliedMigrationsState, gt as PRISMA_ENUM_MEMBER_REGEX, h as URLDriver, hn as computeMigrationChecksum, ht as writePersistedColumnMappingsState, i as MorphManyRelation, in as supportsDatabaseMigrationExecution, it as getPersistedEnumTsType, j as getUserConfig, jn as RuntimeModuleLoader, jt as buildMigrationSource, k as getRuntimePaginationURLDriverFactory, kn as writeAppliedMigrationsState, kt as buildIndexLine, l as BelongsToRelation, ln as EnumBuilder, lt as rebuildPersistedColumnMappingsState, m as Paginator, mn as buildMigrationRunId, mt as validatePersistedMetadataFeaturesForMigrations, n as MorphToManyRelation, nn as stripPrismaSchemaModelsAndEnums, nt as getPersistedColumnMap, o as HasOneRelation, on as toMigrationFileSlug, ot as getPersistedTableMetadata, p as LengthAwarePaginator, pn as buildMigrationIdentity, pt as syncPersistedColumnMappingsFromState, q as registerFactories, qt as formatRelationAction, r as MorphOneRelation, rn as supportsDatabaseCreation, rt as getPersistedEnumMap, s as HasManyThroughRelation, sn as toModelName, st as getPersistedTimestampColumns, t as MorphToRelation, tn as runPrismaCommand, tt as deletePersistedColumnMappingsState, un as TableBuilder, ut as resetPersistedColumnMappingsCache, v as configureArkormRuntime, vn as findAppliedMigration, vt as PRISMA_MODEL_REGEX, w as getDefaultStubsPath, wn as readAppliedMigrationsState, wt as applyMigrationToDatabase, x as ensureArkormConfigLoading, xn as isMigrationApplied, xt as applyDropTableOperation, y as defineConfig, yn as getLastMigrationRun, yt as applyAlterTableOperation, z as getRegisteredMigrations, zt as deriveRelationAlias } from "./relationship--l8RA_yy.mjs";
1
+ import { $ as applyOperationsToPersistedColumnMappingsState, $t as resolvePrismaType, A as getRuntimePrismaClient, An as writeAppliedMigrationsStateToStore, At as buildInverseRelationLine, B as getRegisteredModels, Bt as deriveRelationFieldName, C as getActiveTransactionClient, Cn as markMigrationRun, Ct as applyMigrationRollbackToPrismaSchema, D as getRuntimeDebugHandler, Dn as resolveMigrationStateFilePath, Dt as buildEnumBlock, E as getRuntimeClient, En as removeAppliedMigration, Et as applyOperationsToPrismaSchema, F as loadArkormConfig, Fn as RelationResolutionException, Ft as buildUniqueConstraintLine, G as loadModelsFrom, Gt as formatDefaultValue, H as getRegisteredSeeders, Ht as escapeRegex, I as resetArkormRuntimeForTests, In as ArkormCollection, It as createMigrationTimestamp, J as registerMigrations, Jt as generateMigrationFile, K as loadSeedersFrom, Kt as formatEnumDefaultValue, L as runArkormTransaction, Ln as ArkormException, Lt as deriveCollectionFieldName, M as isDelegateLike, Mn as UnsupportedAdapterFeatureException, Mt as buildModelBlock, N as isQuerySchemaLike, Nn as SetBasedEagerLoader, Nt as buildPrimaryKeyLine, O as getRuntimePaginationCurrentPageResolver, On as supportsDatabaseMigrationState, Ot as buildFieldLine, P as isTransactionCapableClient, Pt as buildRelationLine, Q as resetRuntimeRegistryForTests, Qt as resolveMigrationClassName, R as getRegisteredFactories, Rt as deriveInverseRelationAlias, S as getActiveTransactionAdapter, Sn as markMigrationApplied, St as applyMigrationRollbackToDatabase, T as getRuntimeAdapter, Tn as readAppliedMigrationsStateFromStore, Tt as applyMigrationToPrismaSchema, U as loadFactoriesFrom, Ut as findEnumBlock, V as getRegisteredPaths, Vt as deriveSingularFieldName, W as loadMigrationsFrom, Wt as findModelBlock, X as registerPaths, Xt as pad, Y as registerModels, Yt as getMigrationPlan, Z as registerSeeders, Zt as resolveEnumName, _ as bindAdapterToModels, _n as deleteAppliedMigrationsStateFromStore, _t as PRISMA_ENUM_REGEX, a as HasOneThroughRelation, an as supportsDatabaseReset, at as getPersistedPrimaryKeyGeneration, b as emitRuntimeDebugEvent, bn as getLatestAppliedMigrations, bt as applyCreateTableOperation, c as HasManyRelation, cn as SchemaBuilder, ct as readPersistedColumnMappingsState, d as BelongsToManyRelation, dn as PrimaryKeyGenerationPlanner, dt as resolveColumnMappingsFilePath, en as runMigrationWithPrisma, et as createEmptyPersistedColumnMappingsState, f as Relation, fn as ForeignKeyBuilder, ft as resolvePersistedMetadataFeatures, g as awaitConfiguredModelsRegistration, gn as createEmptyAppliedMigrationsState, gt as PRISMA_ENUM_MEMBER_REGEX, h as URLDriver, hn as computeMigrationChecksum, ht as writePersistedColumnMappingsState, i as MorphManyRelation, in as supportsDatabaseMigrationExecution, it as getPersistedEnumTsType, j as getUserConfig, jn as RuntimeModuleLoader, jt as buildMigrationSource, k as getRuntimePaginationURLDriverFactory, kn as writeAppliedMigrationsState, kt as buildIndexLine, l as BelongsToRelation, ln as EnumBuilder, lt as rebuildPersistedColumnMappingsState, m as Paginator, mn as buildMigrationRunId, mt as validatePersistedMetadataFeaturesForMigrations, n as MorphToManyRelation, nn as stripPrismaSchemaModelsAndEnums, nt as getPersistedColumnMap, o as HasOneRelation, on as toMigrationFileSlug, ot as getPersistedTableMetadata, p as LengthAwarePaginator, pn as buildMigrationIdentity, pt as syncPersistedColumnMappingsFromState, q as registerFactories, qt as formatRelationAction, r as MorphOneRelation, rn as supportsDatabaseCreation, rt as getPersistedEnumMap, s as HasManyThroughRelation, sn as toModelName, st as getPersistedTimestampColumns, t as MorphToRelation, tn as runPrismaCommand, tt as deletePersistedColumnMappingsState, un as TableBuilder, ut as resetPersistedColumnMappingsCache, v as configureArkormRuntime, vn as findAppliedMigration, vt as PRISMA_MODEL_REGEX, w as getDefaultStubsPath, wn as readAppliedMigrationsState, wt as applyMigrationToDatabase, x as ensureArkormConfigLoading, xn as isMigrationApplied, xt as applyDropTableOperation, y as defineConfig, yn as getLastMigrationRun, yt as applyAlterTableOperation, z as getRegisteredMigrations, zt as deriveRelationAlias } from "./relationship-DtNgcxxv.mjs";
2
2
  import { Pool } from "pg";
3
3
  import { join, resolve } from "node:path";
4
4
  import { createRequire } from "module";
@@ -614,6 +614,10 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
614
614
  if (!groupBy || groupBy.length === 0) return sql``;
615
615
  return sql` group by ${sql.join(groupBy.map((column) => sql.ref(this.mapColumn(target, column))), sql`, `)}`;
616
616
  }
617
+ buildHavingClause(target, having) {
618
+ if (!having) return sql``;
619
+ return sql` having ${this.buildWhereCondition(target, having)}`;
620
+ }
617
621
  buildJoinClause(target, joins) {
618
622
  if (!joins || joins.length === 0) return sql``;
619
623
  return sql` ${sql.join(joins.map((join) => this.buildSingleJoin(target, join)), sql` `)}`;
@@ -739,6 +743,24 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
739
743
  return sql`coalesce(${sql.ref(this.mapColumn(target, column))}::text, '')`;
740
744
  }), sql` || ' ' || `)}) @@ plainto_tsquery(${language}, ${condition.value})`;
741
745
  }
746
+ buildJsonAccessor(target, column, path) {
747
+ const base = sql`${sql.ref(this.mapColumn(target, column))}::jsonb`;
748
+ if (!path || path.length === 0) return base;
749
+ return sql`(${base} #> ${`{${path.join(",")}}`}::text[])`;
750
+ }
751
+ buildJsonCondition(target, condition) {
752
+ const accessor = this.buildJsonAccessor(target, condition.column, condition.path);
753
+ if (condition.kind === "contains-key") return condition.not ? sql`${accessor} is null` : sql`${accessor} is not null`;
754
+ if (condition.kind === "length") return sql`jsonb_array_length(${accessor}) ${sql.raw(condition.operator ?? "=")} ${condition.value}`;
755
+ const jsonValue = JSON.stringify(condition.value ?? null);
756
+ if (condition.kind === "overlaps") return sql`exists (
757
+ select 1
758
+ from jsonb_array_elements(${accessor}) as _arkorm_overlap
759
+ where _arkorm_overlap in (select jsonb_array_elements(${jsonValue}::jsonb))
760
+ )`;
761
+ const contains = sql`${accessor} @> ${jsonValue}::jsonb`;
762
+ return condition.not ? sql`not (${contains})` : contains;
763
+ }
742
764
  buildWhereCondition(target, condition) {
743
765
  if (!condition) return sql`1 = 1`;
744
766
  if (condition.type === "comparison") return this.buildComparisonCondition(target, condition);
@@ -747,6 +769,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
747
769
  if (condition.type === "day") return this.buildDayCondition(target, condition);
748
770
  if (condition.type === "exists") return this.buildExistsCondition(condition);
749
771
  if (condition.type === "full-text") return this.buildFullTextCondition(target, condition);
772
+ if (condition.type === "json") return this.buildJsonCondition(target, condition);
750
773
  if (condition.type === "group") {
751
774
  const group = condition;
752
775
  const conditions = group.conditions.map((entry) => {
@@ -974,6 +997,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
974
997
  ${this.buildJoinClause(spec.target, spec.joins)}
975
998
  ${this.buildCombinedWhereClause(spec.target, spec.where, spec.relationFilters)}
976
999
  ${this.buildGroupBy(spec.target, spec.groupBy)}
1000
+ ${this.buildHavingClause(spec.target, spec.having)}
977
1001
  ${this.buildOrderBy(spec.target, spec.orderBy)}
978
1002
  ${this.buildPaginationClause(spec)}
979
1003
  `;
@@ -1723,6 +1747,10 @@ var PrismaDatabaseAdapter = class PrismaDatabaseAdapter {
1723
1747
  operation: "adapter.select",
1724
1748
  meta: { feature: "groupBy" }
1725
1749
  });
1750
+ if (spec.having) throw new UnsupportedAdapterFeatureException("Having clauses are not supported by the Prisma compatibility adapter; use a SQL-backed adapter.", {
1751
+ operation: "adapter.select",
1752
+ meta: { feature: "having" }
1753
+ });
1726
1754
  if (spec.joins?.length) throw new UnsupportedAdapterFeatureException("Join clauses are not supported by the Prisma compatibility adapter; use a SQL-backed adapter or DB.raw().", {
1727
1755
  operation: "adapter.select",
1728
1756
  meta: { feature: "joins" }
@@ -3322,6 +3350,7 @@ var MigrateCommand = class extends Command {
3322
3350
  */
3323
3351
  async handle() {
3324
3352
  this.app.command = this;
3353
+ await loadArkormConfig();
3325
3354
  const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join(process.cwd(), "database", "migrations");
3326
3355
  const migrationDirs = this.resolveMigrationDirectories(configuredMigrationsDir);
3327
3356
  if (migrationDirs.length === 0 && getRegisteredMigrations().length === 0) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
@@ -3362,14 +3391,17 @@ var MigrateCommand = class extends Command {
3362
3391
  this.success("No pending migration classes to apply.");
3363
3392
  return;
3364
3393
  }
3365
- if (useDatabaseMigrations) try {
3366
- await validatePersistedMetadataFeaturesForMigrations(pending, persistedFeatures);
3367
- } catch (error) {
3368
- this.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
3369
- return;
3370
- }
3394
+ let columnMappingsState = createEmptyPersistedColumnMappingsState();
3371
3395
  for (const [MigrationClassItem] of pending) {
3372
3396
  if (useDatabaseMigrations) {
3397
+ const planned = await this.runWithDatabaseCreationRetry(adapter, () => getMigrationPlan(MigrationClassItem, "up"));
3398
+ if (!planned.ok) return;
3399
+ try {
3400
+ columnMappingsState = applyOperationsToPersistedColumnMappingsState(columnMappingsState, planned.value, persistedFeatures);
3401
+ } catch (error) {
3402
+ this.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
3403
+ return;
3404
+ }
3373
3405
  if (!(await this.runWithDatabaseCreationRetry(adapter, () => applyMigrationToDatabase(adapter, MigrationClassItem))).ok) return;
3374
3406
  continue;
3375
3407
  }
@@ -4665,6 +4697,27 @@ var QueryBuilder = class QueryBuilder {
4665
4697
  return this;
4666
4698
  }
4667
4699
  /**
4700
+ * Adds an OR fulltext clause for columns that have full text indexes.
4701
+ *
4702
+ * @param columns
4703
+ * @param value
4704
+ * @param options
4705
+ * @returns
4706
+ */
4707
+ orWhereFullText(columns, value, options = {}) {
4708
+ const normalizedColumns = Array.isArray(columns) ? columns : [columns];
4709
+ if (normalizedColumns.length === 0) throw new ArkormException("orWhereFullText() expects at least one column.");
4710
+ const language = options.language ?? "simple";
4711
+ if (!/^[a-z][a-z0-9_]*$/i.test(language)) throw new ArkormException("orWhereFullText() language must be a valid PostgreSQL text search configuration name.");
4712
+ this.appendQueryCondition("OR", {
4713
+ type: "full-text",
4714
+ columns: normalizedColumns,
4715
+ value,
4716
+ language
4717
+ });
4718
+ return this;
4719
+ }
4720
+ /**
4668
4721
  * Adds a strongly-typed inequality where clause for a single attribute key.
4669
4722
  *
4670
4723
  * @param key
@@ -4705,6 +4758,188 @@ var QueryBuilder = class QueryBuilder {
4705
4758
  return this.where({ [key]: { contains: value } });
4706
4759
  }
4707
4760
  /**
4761
+ * Adds an OR string contains clause for a single attribute key.
4762
+ *
4763
+ * @param key
4764
+ * @param value
4765
+ * @returns
4766
+ */
4767
+ orWhereLike(key, value) {
4768
+ return this.orWhere({ [key]: { contains: value } });
4769
+ }
4770
+ /**
4771
+ * Adds a negated string contains (NOT LIKE) clause for a single attribute key.
4772
+ *
4773
+ * @param key
4774
+ * @param value
4775
+ * @returns
4776
+ */
4777
+ whereNotLike(key, value) {
4778
+ return this.where({ NOT: { [key]: { contains: value } } });
4779
+ }
4780
+ /**
4781
+ * Adds an OR negated string contains (NOT LIKE) clause for a single attribute key.
4782
+ *
4783
+ * @param key
4784
+ * @param value
4785
+ * @returns
4786
+ */
4787
+ orWhereNotLike(key, value) {
4788
+ return this.orWhere({ NOT: { [key]: { contains: value } } });
4789
+ }
4790
+ /**
4791
+ * Append a structured JSON predicate, splitting a `column->path->key`
4792
+ * expression into its base column and nested path segments.
4793
+ *
4794
+ * @param boolean
4795
+ * @param kind
4796
+ * @param column
4797
+ * @param options
4798
+ * @returns
4799
+ */
4800
+ appendJsonCondition(boolean, kind, column, options = {}) {
4801
+ const [base, ...path] = column.split("->").map((segment) => segment.trim());
4802
+ if (!base) throw new ArkormException("JSON where clauses require a column name.");
4803
+ this.appendQueryCondition(boolean, {
4804
+ type: "json",
4805
+ kind,
4806
+ column: base,
4807
+ path: path.length > 0 ? path : void 0,
4808
+ not: options.not,
4809
+ value: options.value,
4810
+ operator: options.operator
4811
+ });
4812
+ return this;
4813
+ }
4814
+ /**
4815
+ * Adds a clause asserting the JSON column contains the given value
4816
+ * (PostgreSQL `@>` containment).
4817
+ *
4818
+ * @param column
4819
+ * @param value
4820
+ * @returns
4821
+ */
4822
+ whereJsonContains(column, value) {
4823
+ return this.appendJsonCondition("AND", "contains", column, { value });
4824
+ }
4825
+ /**
4826
+ * OR variant of whereJsonContains().
4827
+ *
4828
+ * @param column
4829
+ * @param value
4830
+ * @returns
4831
+ */
4832
+ orWhereJsonContains(column, value) {
4833
+ return this.appendJsonCondition("OR", "contains", column, { value });
4834
+ }
4835
+ /**
4836
+ * Adds a clause asserting the JSON column does not contain the given value.
4837
+ *
4838
+ * @param column
4839
+ * @param value
4840
+ * @returns
4841
+ */
4842
+ whereJsonDoesntContain(column, value) {
4843
+ return this.appendJsonCondition("AND", "contains", column, {
4844
+ value,
4845
+ not: true
4846
+ });
4847
+ }
4848
+ /**
4849
+ * OR variant of whereJsonDoesntContain().
4850
+ *
4851
+ * @param column
4852
+ * @param value
4853
+ * @returns
4854
+ */
4855
+ orWhereJsonDoesntContain(column, value) {
4856
+ return this.appendJsonCondition("OR", "contains", column, {
4857
+ value,
4858
+ not: true
4859
+ });
4860
+ }
4861
+ /**
4862
+ * Adds a clause asserting the JSON document contains the given key/path.
4863
+ *
4864
+ * @param column
4865
+ * @returns
4866
+ */
4867
+ whereJsonContainsKey(column) {
4868
+ return this.appendJsonCondition("AND", "contains-key", column);
4869
+ }
4870
+ /**
4871
+ * OR variant of whereJsonContainsKey().
4872
+ *
4873
+ * @param column
4874
+ * @returns
4875
+ */
4876
+ orWhereJsonContainsKey(column) {
4877
+ return this.appendJsonCondition("OR", "contains-key", column);
4878
+ }
4879
+ /**
4880
+ * Adds a clause asserting the JSON document does not contain the given key/path.
4881
+ *
4882
+ * @param column
4883
+ * @returns
4884
+ */
4885
+ whereJsonDoesntContainKey(column) {
4886
+ return this.appendJsonCondition("AND", "contains-key", column, { not: true });
4887
+ }
4888
+ /**
4889
+ * OR variant of whereJsonDoesntContainKey().
4890
+ *
4891
+ * @param column
4892
+ * @returns
4893
+ */
4894
+ orWhereJsonDoesntContainKey(column) {
4895
+ return this.appendJsonCondition("OR", "contains-key", column, { not: true });
4896
+ }
4897
+ whereJsonLength(column, operatorOrValue, maybeValue) {
4898
+ const { operator, value } = this.resolveJsonLengthArgs(operatorOrValue, maybeValue);
4899
+ return this.appendJsonCondition("AND", "length", column, {
4900
+ operator,
4901
+ value
4902
+ });
4903
+ }
4904
+ orWhereJsonLength(column, operatorOrValue, maybeValue) {
4905
+ const { operator, value } = this.resolveJsonLengthArgs(operatorOrValue, maybeValue);
4906
+ return this.appendJsonCondition("OR", "length", column, {
4907
+ operator,
4908
+ value
4909
+ });
4910
+ }
4911
+ resolveJsonLengthArgs(operatorOrValue, maybeValue) {
4912
+ const hasOperator = maybeValue !== void 0;
4913
+ const operator = hasOperator ? operatorOrValue : "=";
4914
+ const value = hasOperator ? maybeValue : operatorOrValue;
4915
+ if (!Number.isInteger(value) || value < 0) throw new ArkormException("whereJsonLength() expects a non-negative integer length.");
4916
+ return {
4917
+ operator,
4918
+ value
4919
+ };
4920
+ }
4921
+ /**
4922
+ * Adds a clause asserting the JSON array column overlaps with the given
4923
+ * array (shares at least one element).
4924
+ *
4925
+ * @param column
4926
+ * @param value
4927
+ * @returns
4928
+ */
4929
+ whereJsonOverlaps(column, value) {
4930
+ return this.appendJsonCondition("AND", "overlaps", column, { value });
4931
+ }
4932
+ /**
4933
+ * OR variant of whereJsonOverlaps().
4934
+ *
4935
+ * @param column
4936
+ * @param value
4937
+ * @returns
4938
+ */
4939
+ orWhereJsonOverlaps(column, value) {
4940
+ return this.appendJsonCondition("OR", "overlaps", column, { value });
4941
+ }
4942
+ /**
4708
4943
  * Adds a string starts-with clause for a single attribute key.
4709
4944
  *
4710
4945
  * @param key
@@ -5249,6 +5484,65 @@ var QueryBuilder = class QueryBuilder {
5249
5484
  this.queryGroupBy = [...normalized];
5250
5485
  return this;
5251
5486
  }
5487
+ appendHavingCondition(boolean, condition) {
5488
+ if (!this.queryHaving) {
5489
+ this.queryHaving = condition;
5490
+ return;
5491
+ }
5492
+ this.queryHaving = {
5493
+ type: "group",
5494
+ operator: boolean === "AND" ? "and" : "or",
5495
+ conditions: [this.queryHaving, condition]
5496
+ };
5497
+ }
5498
+ buildHavingComparison(operatorOrValue, maybeValue, column) {
5499
+ const hasOperator = maybeValue !== void 0;
5500
+ return {
5501
+ type: "comparison",
5502
+ column,
5503
+ operator: hasOperator ? operatorOrValue : "=",
5504
+ value: hasOperator ? maybeValue : operatorOrValue
5505
+ };
5506
+ }
5507
+ having(column, operatorOrValue, maybeValue) {
5508
+ this.appendHavingCondition("AND", this.buildHavingComparison(operatorOrValue, maybeValue, column));
5509
+ return this;
5510
+ }
5511
+ orHaving(column, operatorOrValue, maybeValue) {
5512
+ this.appendHavingCondition("OR", this.buildHavingComparison(operatorOrValue, maybeValue, column));
5513
+ return this;
5514
+ }
5515
+ /**
5516
+ * Adds a raw HAVING clause, useful for filtering on aggregate expressions
5517
+ * such as `count(*)`. Combines with previous HAVING clauses using AND.
5518
+ *
5519
+ * @param sql
5520
+ * @param bindings
5521
+ * @returns
5522
+ */
5523
+ havingRaw(sql, bindings = []) {
5524
+ this.appendHavingCondition("AND", {
5525
+ type: "raw",
5526
+ sql,
5527
+ bindings
5528
+ });
5529
+ return this;
5530
+ }
5531
+ /**
5532
+ * Adds a raw OR HAVING clause.
5533
+ *
5534
+ * @param sql
5535
+ * @param bindings
5536
+ * @returns
5537
+ */
5538
+ orHavingRaw(sql, bindings = []) {
5539
+ this.appendHavingCondition("OR", {
5540
+ type: "raw",
5541
+ sql,
5542
+ bindings
5543
+ });
5544
+ return this;
5545
+ }
5252
5546
  /**
5253
5547
  * Adds a join clause to the query.
5254
5548
  *
@@ -6301,6 +6595,7 @@ var QueryBuilder = class QueryBuilder {
6301
6595
  builder.querySelect = this.querySelect ? [...this.querySelect] : void 0;
6302
6596
  builder.queryDistinct = this.queryDistinct;
6303
6597
  builder.queryGroupBy = this.queryGroupBy ? [...this.queryGroupBy] : void 0;
6598
+ builder.queryHaving = this.queryHaving;
6304
6599
  builder.offsetValue = this.offsetValue;
6305
6600
  builder.limitValue = this.limitValue;
6306
6601
  builder.includeTrashed = this.includeTrashed;
@@ -6825,6 +7120,7 @@ var QueryBuilder = class QueryBuilder {
6825
7120
  columns,
6826
7121
  distinct: this.queryDistinct || void 0,
6827
7122
  groupBy: this.queryGroupBy ? [...this.queryGroupBy] : void 0,
7123
+ having: this.queryHaving,
6828
7124
  joins: this.queryJoins ? [...this.queryJoins] : void 0,
6829
7125
  where: condition,
6830
7126
  orderBy,
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_relationship = require('../relationship-WiXlopzY.cjs');
2
+ const require_relationship = require('../relationship-BVYP9lU2.cjs');
3
3
 
4
4
  exports.BelongsToManyRelation = require_relationship.BelongsToManyRelation;
5
5
  exports.BelongsToRelation = require_relationship.BelongsToRelation;
@@ -1,2 +1,2 @@
1
- import { Ao as MorphManyRelation, Do as MorphToRelation, Eo as SetBasedEagerLoader, Fo as BelongsToRelation, Io as SingleResultRelation, Lo as BelongsToManyRelation, Mo as HasOneRelation, No as HasManyThroughRelation, Oo as MorphToManyRelation, Po as HasManyRelation, Ro as Relation, jo as HasOneThroughRelation, ko as MorphOneRelation, zo as RelationTableLoader } from "../index-4mi5sLRA.cjs";
1
+ import { Ao as MorphToManyRelation, Bo as Relation, Fo as HasManyThroughRelation, Io as HasManyRelation, Lo as BelongsToRelation, Mo as MorphManyRelation, No as HasOneThroughRelation, Oo as SetBasedEagerLoader, Po as HasOneRelation, Ro as SingleResultRelation, Vo as RelationTableLoader, jo as MorphOneRelation, ko as MorphToRelation, zo as BelongsToManyRelation } from "../index-wYvd4F2M.cjs";
2
2
  export { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, HasOneThroughRelation, MorphManyRelation, MorphOneRelation, MorphToManyRelation, MorphToRelation, Relation, RelationTableLoader, SetBasedEagerLoader, SingleResultRelation };
@@ -1,2 +1,2 @@
1
- import { Ao as MorphManyRelation, Do as MorphToRelation, Eo as SetBasedEagerLoader, Fo as BelongsToRelation, Io as SingleResultRelation, Lo as BelongsToManyRelation, Mo as HasOneRelation, No as HasManyThroughRelation, Oo as MorphToManyRelation, Po as HasManyRelation, Ro as Relation, jo as HasOneThroughRelation, ko as MorphOneRelation, zo as RelationTableLoader } from "../index-De8zXqTD.mjs";
1
+ import { Ao as MorphToManyRelation, Bo as Relation, Fo as HasManyThroughRelation, Io as HasManyRelation, Lo as BelongsToRelation, Mo as MorphManyRelation, No as HasOneThroughRelation, Oo as SetBasedEagerLoader, Po as HasOneRelation, Ro as SingleResultRelation, Vo as RelationTableLoader, jo as MorphOneRelation, ko as MorphToRelation, zo as BelongsToManyRelation } from "../index-C7r00xN5.mjs";
2
2
  export { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, HasOneThroughRelation, MorphManyRelation, MorphOneRelation, MorphToManyRelation, MorphToRelation, Relation, RelationTableLoader, SetBasedEagerLoader, SingleResultRelation };
@@ -1,3 +1,3 @@
1
- import { Nn as SetBasedEagerLoader, Pn as RelationTableLoader, a as HasOneThroughRelation, c as HasManyRelation, d as BelongsToManyRelation, f as Relation, i as MorphManyRelation, l as BelongsToRelation, n as MorphToManyRelation, o as HasOneRelation, r as MorphOneRelation, s as HasManyThroughRelation, t as MorphToRelation, u as SingleResultRelation } from "../relationship--l8RA_yy.mjs";
1
+ import { Nn as SetBasedEagerLoader, Pn as RelationTableLoader, a as HasOneThroughRelation, c as HasManyRelation, d as BelongsToManyRelation, f as Relation, i as MorphManyRelation, l as BelongsToRelation, n as MorphToManyRelation, o as HasOneRelation, r as MorphOneRelation, s as HasManyThroughRelation, t as MorphToRelation, u as SingleResultRelation } from "../relationship-DtNgcxxv.mjs";
2
2
 
3
3
  export { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, HasOneThroughRelation, MorphManyRelation, MorphOneRelation, MorphToManyRelation, MorphToRelation, Relation, RelationTableLoader, SetBasedEagerLoader, SingleResultRelation };
@@ -4015,6 +4015,17 @@ var Relation = class {
4015
4015
  return this.constrain((query) => query.whereFullText(columns, value, options));
4016
4016
  }
4017
4017
  /**
4018
+ * Add an OR fulltext clause to the relationship query.
4019
+ *
4020
+ * @param columns
4021
+ * @param value
4022
+ * @param options
4023
+ * @returns
4024
+ */
4025
+ orWhereFullText(columns, value, options = {}) {
4026
+ return this.constrain((query) => query.orWhereFullText(columns, value, options));
4027
+ }
4028
+ /**
4018
4029
  * Add a strongly-typed where key clause to the relationship query.
4019
4030
  *
4020
4031
  * @param key
@@ -4085,6 +4096,155 @@ var Relation = class {
4085
4096
  return this.constrain((query) => query.whereLike(key, value));
4086
4097
  }
4087
4098
  /**
4099
+ * Add an OR string contains clause to the relationship query.
4100
+ *
4101
+ * @param key
4102
+ * @param value
4103
+ * @returns
4104
+ */
4105
+ orWhereLike(key, value) {
4106
+ return this.constrain((query) => query.orWhereLike(key, value));
4107
+ }
4108
+ /**
4109
+ * Add a negated string contains (NOT LIKE) clause to the relationship query.
4110
+ *
4111
+ * @param key
4112
+ * @param value
4113
+ * @returns
4114
+ */
4115
+ whereNotLike(key, value) {
4116
+ return this.constrain((query) => query.whereNotLike(key, value));
4117
+ }
4118
+ /**
4119
+ * Add an OR negated string contains (NOT LIKE) clause to the relationship query.
4120
+ *
4121
+ * @param key
4122
+ * @param value
4123
+ * @returns
4124
+ */
4125
+ orWhereNotLike(key, value) {
4126
+ return this.constrain((query) => query.orWhereNotLike(key, value));
4127
+ }
4128
+ /**
4129
+ * Add a JSON containment clause to the relationship query.
4130
+ *
4131
+ * @param key
4132
+ * @param value
4133
+ * @returns
4134
+ */
4135
+ whereJsonContains(column, value) {
4136
+ return this.constrain((query) => query.whereJsonContains(column, value));
4137
+ }
4138
+ /**
4139
+ * OR variant of whereJsonContains().
4140
+ *
4141
+ * @param column
4142
+ * @param value
4143
+ * @returns
4144
+ */
4145
+ orWhereJsonContains(column, value) {
4146
+ return this.constrain((query) => query.orWhereJsonContains(column, value));
4147
+ }
4148
+ /**
4149
+ * Add a negated JSON containment clause to the relationship query.
4150
+ *
4151
+ * @param column
4152
+ * @param value
4153
+ * @returns
4154
+ */
4155
+ whereJsonDoesntContain(column, value) {
4156
+ return this.constrain((query) => query.whereJsonDoesntContain(column, value));
4157
+ }
4158
+ /**
4159
+ * OR variant of whereJsonDoesntContain().
4160
+ *
4161
+ * @param column
4162
+ * @param value
4163
+ * @returns
4164
+ */
4165
+ orWhereJsonDoesntContain(column, value) {
4166
+ return this.constrain((query) => query.orWhereJsonDoesntContain(column, value));
4167
+ }
4168
+ /**
4169
+ * Add a JSON key-existence clause to the relationship query.
4170
+ *
4171
+ * @param column
4172
+ * @param value
4173
+ * @returns
4174
+ */
4175
+ whereJsonContainsKey(column) {
4176
+ return this.constrain((query) => query.whereJsonContainsKey(column));
4177
+ }
4178
+ /**
4179
+ * OR variant of whereJsonContainsKey().
4180
+ *
4181
+ * @param column
4182
+ * @returns
4183
+ */
4184
+ orWhereJsonContainsKey(column) {
4185
+ return this.constrain((query) => query.orWhereJsonContainsKey(column));
4186
+ }
4187
+ /**
4188
+ * Add a negated JSON key-existence clause to the relationship query.
4189
+ *
4190
+ * @param column
4191
+ * @returns
4192
+ */
4193
+ whereJsonDoesntContainKey(column) {
4194
+ return this.constrain((query) => query.whereJsonDoesntContainKey(column));
4195
+ }
4196
+ /**
4197
+ * OR variant of whereJsonDoesntContainKey().
4198
+ *
4199
+ * @param column
4200
+ * @returns
4201
+ */
4202
+ orWhereJsonDoesntContainKey(column) {
4203
+ return this.constrain((query) => query.orWhereJsonDoesntContainKey(column));
4204
+ }
4205
+ whereJsonLength(column, operatorOrValue, maybeValue) {
4206
+ return this.constrain((query) => maybeValue === void 0 ? query.whereJsonLength(column, operatorOrValue) : query.whereJsonLength(column, operatorOrValue, maybeValue));
4207
+ }
4208
+ orWhereJsonLength(column, operatorOrValue, maybeValue) {
4209
+ return this.constrain((query) => maybeValue === void 0 ? query.orWhereJsonLength(column, operatorOrValue) : query.orWhereJsonLength(column, operatorOrValue, maybeValue));
4210
+ }
4211
+ /**
4212
+ * Add a JSON array overlap clause to the relationship query.
4213
+ *
4214
+ * @param column
4215
+ * @param value
4216
+ */
4217
+ whereJsonOverlaps(column, value) {
4218
+ return this.constrain((query) => query.whereJsonOverlaps(column, value));
4219
+ }
4220
+ /**
4221
+ * OR variant of whereJsonOverlaps().
4222
+ *
4223
+ * @param column
4224
+ * @param value
4225
+ */
4226
+ orWhereJsonOverlaps(column, value) {
4227
+ return this.constrain((query) => query.orWhereJsonOverlaps(column, value));
4228
+ }
4229
+ having(column, operatorOrValue, maybeValue) {
4230
+ return this.constrain((query) => maybeValue === void 0 ? query.having(column, operatorOrValue) : query.having(column, operatorOrValue, maybeValue));
4231
+ }
4232
+ orHaving(column, operatorOrValue, maybeValue) {
4233
+ return this.constrain((query) => maybeValue === void 0 ? query.orHaving(column, operatorOrValue) : query.orHaving(column, operatorOrValue, maybeValue));
4234
+ }
4235
+ /**
4236
+ * Add a raw HAVING clause to the relationship query.
4237
+ */
4238
+ havingRaw(sql, bindings = []) {
4239
+ return this.constrain((query) => query.havingRaw(sql, bindings));
4240
+ }
4241
+ /**
4242
+ * Add a raw OR HAVING clause to the relationship query.
4243
+ */
4244
+ orHavingRaw(sql, bindings = []) {
4245
+ return this.constrain((query) => query.orHavingRaw(sql, bindings));
4246
+ }
4247
+ /**
4088
4248
  * Add a string starts-with clause to the relationship query.
4089
4249
  *
4090
4250
  * @param key