@dbsp/core 1.0.2 → 1.0.4

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.js CHANGED
@@ -2146,6 +2146,7 @@ function plan(intent, model, options = {}) {
2146
2146
  throw new Error(`Unknown table: ${intent.from}`);
2147
2147
  }
2148
2148
  const optimizedWhere = intent.where ? optimizeInToExists(intent.where, intent.from, model) : void 0;
2149
+ const plannedIntent = optimizedWhere !== void 0 && optimizedWhere !== intent.where ? { ...intent, where: optimizedWhere } : intent;
2149
2150
  if (optimizedWhere) {
2150
2151
  processWhere(optimizedWhere, intent.from, model, state, opts, "where");
2151
2152
  }
@@ -2188,7 +2189,13 @@ function plan(intent, model, options = {}) {
2188
2189
  decisions: Object.freeze(state.decisions.slice()),
2189
2190
  warnings: Object.freeze(state.warnings.slice()),
2190
2191
  ctes: Object.freeze(state.ctes.slice()),
2192
+ // intent is ALWAYS the original submitted intent (contract: observable via dump()).
2193
+ // executableIntent carries the optimized WHERE (e.g. IN→EXISTS) when the
2194
+ // optimizer rewrote it, so the adapter compiles the correct SQL from that field.
2195
+ // When no optimization applies, executableIntent is left undefined and the
2196
+ // adapter falls back to intent.
2191
2197
  intent,
2198
+ ...plannedIntent !== intent && { executableIntent: plannedIntent },
2192
2199
  metadata
2193
2200
  };
2194
2201
  return Object.freeze(report);
@@ -2326,11 +2333,15 @@ function isSubquerySelectedColumnNonNullable(existsIntent, sourceTable, model) {
2326
2333
  if (!column) return false;
2327
2334
  return !column.nullable;
2328
2335
  }
2329
- function optimizeInToExists(where, sourceTable, model) {
2336
+ function optimizeInToExists(where, sourceTable, model, negated = false) {
2330
2337
  switch (where.kind) {
2331
2338
  case "in": {
2332
2339
  const inWhere = where;
2333
2340
  if (!inWhere.subquery) return where;
2341
+ const sq = inWhere.subquery;
2342
+ if (sq.limit != null || sq.orderBy?.length || sq.offset != null || sq.groupBy?.length || sq.having != null || sq.distinct || sq.distinctOn?.length || sq.joins?.length || sq.include?.length || sq.batchValuesSource != null || sq.existsWrap || sq.lock != null || sq.select != null && sq.select.type !== "fields") {
2343
+ return where;
2344
+ }
2334
2345
  const subSelect = inWhere.subquery.select;
2335
2346
  if (!subSelect || subSelect.type !== "fields") return where;
2336
2347
  const fields = "fields" in subSelect ? subSelect.fields : void 0;
@@ -2350,18 +2361,24 @@ function optimizeInToExists(where, sourceTable, model) {
2350
2361
  }
2351
2362
  }
2352
2363
  if (!matchedRelation) return where;
2353
- const existsWhere = {
2354
- kind: "exists",
2364
+ const effectiveNegated = negated !== Boolean(inWhere.not);
2365
+ if (effectiveNegated) {
2366
+ const existsIntent = { relation: matchedRelation };
2367
+ if (!isSubquerySelectedColumnNonNullable(existsIntent, sourceTable, model)) {
2368
+ return where;
2369
+ }
2370
+ }
2371
+ const targetKind = inWhere.not ? "notExists" : "exists";
2372
+ return {
2373
+ kind: targetKind,
2355
2374
  relation: matchedRelation,
2356
- // Forward the subquery's inner WHERE conditions
2357
2375
  ...inWhere.subquery.where && { where: inWhere.subquery.where }
2358
2376
  };
2359
- return existsWhere;
2360
2377
  }
2361
2378
  case "and": {
2362
2379
  const andWhere = where;
2363
2380
  const optimized = andWhere.conditions.map(
2364
- (c) => optimizeInToExists(c, sourceTable, model)
2381
+ (c) => optimizeInToExists(c, sourceTable, model, negated)
2365
2382
  );
2366
2383
  if (optimized.every((c, i) => c === andWhere.conditions[i])) return where;
2367
2384
  return { kind: "and", conditions: optimized };
@@ -2369,7 +2386,7 @@ function optimizeInToExists(where, sourceTable, model) {
2369
2386
  case "or": {
2370
2387
  const orWhere = where;
2371
2388
  const optimized = orWhere.conditions.map(
2372
- (c) => optimizeInToExists(c, sourceTable, model)
2389
+ (c) => optimizeInToExists(c, sourceTable, model, negated)
2373
2390
  );
2374
2391
  if (optimized.every((c, i) => c === orWhere.conditions[i])) return where;
2375
2392
  return { kind: "or", conditions: optimized };
@@ -2379,22 +2396,10 @@ function optimizeInToExists(where, sourceTable, model) {
2379
2396
  const optimized = optimizeInToExists(
2380
2397
  notWhere.condition,
2381
2398
  sourceTable,
2382
- model
2399
+ model,
2400
+ !negated
2383
2401
  );
2384
2402
  if (optimized === notWhere.condition) return where;
2385
- if (optimized.kind === "exists") {
2386
- if (!isSubquerySelectedColumnNonNullable(
2387
- optimized,
2388
- sourceTable,
2389
- model
2390
- )) {
2391
- return where;
2392
- }
2393
- return {
2394
- ...optimized,
2395
- kind: "notExists"
2396
- };
2397
- }
2398
2403
  return { kind: "not", condition: optimized };
2399
2404
  }
2400
2405
  default:
@@ -2476,6 +2481,26 @@ function processWhere(where, sourceTable, model, state, opts, intentPath) {
2476
2481
  break;
2477
2482
  case "expression":
2478
2483
  break;
2484
+ // Custom expression — no relation analysis, pass through
2485
+ // Adapter-only kinds: planner records no decisions; the adapter compiles
2486
+ // them directly from the intent. Explicit cases here prevent silent
2487
+ // fallthrough and keep the switch exhaustive.
2488
+ case "rawExists":
2489
+ case "rawNotExists":
2490
+ break;
2491
+ case "subquery":
2492
+ break;
2493
+ case "range":
2494
+ break;
2495
+ case "jsonContains":
2496
+ case "jsonExists":
2497
+ break;
2498
+ default: {
2499
+ const _exhaustive = where;
2500
+ throw new Error(
2501
+ `processWhere: unhandled WhereIntent kind '${_exhaustive.kind}'`
2502
+ );
2503
+ }
2479
2504
  }
2480
2505
  }
2481
2506
  function processRelationFilter(relationPath, sourceTable, model, state, opts, intentPath, nestedWhere, mode) {
@@ -3012,6 +3037,60 @@ function assertCapability(adapter, capability, operation) {
3012
3037
  }
3013
3038
 
3014
3039
  // src/dx/batch-values.ts
3040
+ var MULTIWORD_BASE_TYPES = [
3041
+ "timestamp with time zone",
3042
+ "timestamp without time zone",
3043
+ "time with time zone",
3044
+ "time without time zone",
3045
+ "double precision",
3046
+ "character varying",
3047
+ "bit varying"
3048
+ ];
3049
+ var IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
3050
+ function validateTypeName(typeName) {
3051
+ const raw2 = typeName.trim();
3052
+ if (raw2.length === 0) {
3053
+ throw new Error(
3054
+ `batchValues: invalid type name '${typeName}'. Type names must not be empty.`
3055
+ );
3056
+ }
3057
+ let rest = raw2;
3058
+ if (rest.endsWith("[]")) {
3059
+ rest = rest.slice(0, -2);
3060
+ if (rest.endsWith("[]")) {
3061
+ throw new Error(
3062
+ `batchValues: invalid type name '${typeName}'. At most one array suffix "[]" is allowed as a raw type-name input. Use "int4[]" not "int4[][]".`
3063
+ );
3064
+ }
3065
+ }
3066
+ const modifierMatch = rest.match(/\(([^)]*)\)$/);
3067
+ if (modifierMatch) {
3068
+ const inner = modifierMatch[1] ?? "";
3069
+ if (!/^\d+(?:,\d+)?$/.test(inner)) {
3070
+ throw new Error(
3071
+ `batchValues: invalid type name '${typeName}'. Type modifier must be "(N)" or "(N,M)" with digits only; got "(${inner})".`
3072
+ );
3073
+ }
3074
+ rest = rest.slice(0, rest.length - modifierMatch[0].length).trimEnd();
3075
+ }
3076
+ const baseLower = rest.toLowerCase();
3077
+ if (MULTIWORD_BASE_TYPES.includes(baseLower)) {
3078
+ return;
3079
+ }
3080
+ const parts = rest.split(".");
3081
+ if (parts.length > 2) {
3082
+ throw new Error(
3083
+ `batchValues: invalid type name '${typeName}'. Schema-qualified types allow at most one dot (schema.type).`
3084
+ );
3085
+ }
3086
+ for (const part of parts) {
3087
+ if (!IDENT_RE.test(part)) {
3088
+ throw new Error(
3089
+ `batchValues: invalid type name '${typeName}'. Base type "${part}" is not a valid SQL identifier ([A-Za-z_][A-Za-z0-9_]*) and is not in the multi-word type allowlist.`
3090
+ );
3091
+ }
3092
+ }
3093
+ }
3015
3094
  function isBatchValuesRef(value) {
3016
3095
  return typeof value === "object" && value !== null && "__kind" in value && value.__kind === "batchValues";
3017
3096
  }
@@ -3024,20 +3103,28 @@ function batchValues(data, columns, types, opts) {
3024
3103
  if (columns.length === 0) {
3025
3104
  throw new Error("batchValues: at least one column is required");
3026
3105
  }
3027
- const invalidType = types.find((t) => !/^[a-zA-Z0-9_]+$/.test(t));
3028
- if (invalidType !== void 0) {
3029
- throw new Error(
3030
- `batchValues: invalid type name '${invalidType}'. Type names must contain only letters, digits, and underscores.`
3031
- );
3106
+ const normalizedTypes = types.map((t) => t.trim());
3107
+ for (const t of normalizedTypes) {
3108
+ validateTypeName(t);
3032
3109
  }
3033
- return {
3110
+ const alias = opts?.alias ?? "batch";
3111
+ validateIdentifier(alias, "alias");
3112
+ for (const col2 of columns) {
3113
+ validateIdentifier(col2, "column");
3114
+ }
3115
+ const frozenData = Object.freeze(
3116
+ data.map((row) => Object.freeze([...row]))
3117
+ );
3118
+ const frozenColumns = Object.freeze([...columns]);
3119
+ const frozenTypes = Object.freeze([...normalizedTypes]);
3120
+ return Object.freeze({
3034
3121
  __kind: "batchValues",
3035
- data,
3036
- columns,
3037
- types,
3038
- alias: opts?.alias ?? "batch",
3122
+ data: frozenData,
3123
+ columns: frozenColumns,
3124
+ types: frozenTypes,
3125
+ alias,
3039
3126
  ordinality: opts?.ordinality ?? false
3040
- };
3127
+ });
3041
3128
  }
3042
3129
 
3043
3130
  // src/dx/expressions.ts
@@ -3662,6 +3749,23 @@ var DEFAULT_FEATURE_CHECKERS = Object.freeze([
3662
3749
  }
3663
3750
  return usages;
3664
3751
  }
3752
+ },
3753
+ // -----------------------------------------------------------------------
3754
+ // Row-Level Security
3755
+ // -----------------------------------------------------------------------
3756
+ {
3757
+ capability: "supportsDDLRowLevelSecurity",
3758
+ feature: "rowLevelSecurity",
3759
+ detectUsage(model) {
3760
+ if (!model.tables) return [];
3761
+ const usages = [];
3762
+ for (const [tableName, table] of model.tables) {
3763
+ if (table.rlsEnabled || table.policies?.length) {
3764
+ usages.push({ table: tableName, detail: tableName });
3765
+ }
3766
+ }
3767
+ return usages;
3768
+ }
3665
3769
  }
3666
3770
  ]);
3667
3771
 
@@ -3772,11 +3876,12 @@ var WindowBuilder = class _WindowBuilder {
3772
3876
  };
3773
3877
  }
3774
3878
  /**
3775
- * Convert builder state to WindowIntent
3879
+ * Convert builder state to WindowIntent — produces the correct discriminated branch.
3880
+ * - ranking → RankingWindowIntent (no field)
3881
+ * - aggregate → AggregateWindowIntent (field required; COUNT uses '*' when omitted)
3882
+ * - offset → OffsetWindowIntent (field required)
3776
3883
  */
3777
3884
  toWindowIntent(alias) {
3778
- const fn2 = this.fnKind.fn;
3779
- const field = this.fnKind.type === "aggregate" || this.fnKind.type === "offset" ? this.fnKind.field : void 0;
3780
3885
  const over = {};
3781
3886
  if (this.partitions.length > 0) {
3782
3887
  over.partitionBy = this.partitions;
@@ -3784,16 +3889,31 @@ var WindowBuilder = class _WindowBuilder {
3784
3889
  if (this.orders.length > 0) {
3785
3890
  over.orderBy = this.orders;
3786
3891
  }
3787
- const intent = {
3892
+ if (this.fnKind.type === "ranking") {
3893
+ return {
3894
+ kind: "window",
3895
+ function: this.fnKind.fn,
3896
+ alias,
3897
+ over
3898
+ };
3899
+ }
3900
+ if (this.fnKind.type === "offset") {
3901
+ return {
3902
+ kind: "window",
3903
+ function: this.fnKind.fn,
3904
+ field: this.fnKind.field,
3905
+ alias,
3906
+ over
3907
+ };
3908
+ }
3909
+ const { field } = this.fnKind;
3910
+ return {
3788
3911
  kind: "window",
3789
- function: fn2,
3912
+ function: this.fnKind.fn,
3913
+ ...field !== void 0 && { field },
3790
3914
  alias,
3791
3915
  over
3792
3916
  };
3793
- if (field !== void 0) {
3794
- return { ...intent, field };
3795
- }
3796
- return intent;
3797
3917
  }
3798
3918
  };
3799
3919
  function rowNumber() {
@@ -3871,7 +3991,6 @@ function inSubquery(field, query) {
3871
3991
  return {
3872
3992
  kind: "in",
3873
3993
  field: getColumnName(field),
3874
- values: [],
3875
3994
  subquery: expr.toIntent()
3876
3995
  };
3877
3996
  }
@@ -3986,36 +4105,31 @@ function coalesce(fields, as) {
3986
4105
  };
3987
4106
  }
3988
4107
  function raw(sqlFragment, as) {
3989
- if (!as || as.trim() === "") {
3990
- throw new Error("raw() requires a non-empty alias");
3991
- }
4108
+ validateIdentifier(as, "column");
3992
4109
  return {
3993
4110
  __expr: true,
3994
4111
  intent: { kind: "raw", sql: sqlFragment, as }
3995
4112
  };
3996
4113
  }
3997
4114
  function col(column, alias) {
3998
- if (!column || column.trim() === "") {
3999
- throw new Error("col() requires a non-empty column name");
4000
- }
4001
- if (!alias || alias.trim() === "") {
4002
- throw new Error("col() requires a non-empty alias");
4003
- }
4115
+ validateIdentifier(column, "column");
4116
+ validateIdentifier(alias, "column");
4004
4117
  return {
4005
4118
  __expr: true,
4006
4119
  intent: { kind: "columnAlias", column, alias }
4007
4120
  };
4008
4121
  }
4009
4122
  function relationColumn(relation, column, as) {
4010
- if (!relation || relation.trim() === "") {
4123
+ if (!relation) {
4011
4124
  throw new Error("relationColumn() requires a non-empty relation path");
4012
4125
  }
4013
- if (!column || column.trim() === "") {
4014
- throw new Error("relationColumn() requires a non-empty column name");
4126
+ for (const segment of relation.split(".")) {
4127
+ validateIdentifier(segment, "relation");
4015
4128
  }
4016
- if (!as || as.trim() === "") {
4017
- throw new Error("relationColumn() requires a non-empty alias");
4129
+ if (column !== "*") {
4130
+ validateIdentifier(column, "column");
4018
4131
  }
4132
+ validateIdentifier(as, "column");
4019
4133
  return {
4020
4134
  __expr: true,
4021
4135
  intent: { kind: "relationColumn", relation, column, as }
@@ -4374,7 +4488,7 @@ async function runAfterMutationHooks(hooks, ctx, result, onHookError) {
4374
4488
  error,
4375
4489
  hook.name || "anonymous",
4376
4490
  frozen,
4377
- "beforeMutation"
4491
+ "afterMutation"
4378
4492
  );
4379
4493
  if (action === "continue") continue;
4380
4494
  }
@@ -4587,7 +4701,8 @@ function subquery(table) {
4587
4701
  function outerRef(column) {
4588
4702
  return {
4589
4703
  kind: "ref",
4590
- column
4704
+ column,
4705
+ outer: true
4591
4706
  };
4592
4707
  }
4593
4708
  function isSubqueryExpression(value) {
@@ -4901,17 +5016,24 @@ var IntentBuilder = class _IntentBuilder {
4901
5016
  * DX-034: Now supports distinct flag for COUNT(DISTINCT field), etc.
4902
5017
  */
4903
5018
  addAggregate(func, field, options) {
4904
- const agg = { function: func };
4905
- if (field !== void 0) {
4906
- agg.field = field;
4907
- } else if (options?.field !== void 0) {
4908
- agg.field = options.field;
4909
- }
4910
- if (options?.as !== void 0) {
4911
- agg.as = options.as;
4912
- }
4913
- if (options?.distinct) {
4914
- agg.distinct = true;
5019
+ const resolvedField = field ?? options?.field;
5020
+ const as = options?.as;
5021
+ const distinct2 = options?.distinct ? true : void 0;
5022
+ let agg;
5023
+ if (func === "count") {
5024
+ agg = {
5025
+ function: "count",
5026
+ ...resolvedField !== void 0 && { field: resolvedField },
5027
+ ...as !== void 0 && { as },
5028
+ ...distinct2 !== void 0 && { distinct: distinct2 }
5029
+ };
5030
+ } else {
5031
+ agg = {
5032
+ function: func,
5033
+ field: resolvedField ?? "",
5034
+ ...as !== void 0 && { as },
5035
+ ...distinct2 !== void 0 && { distinct: distinct2 }
5036
+ };
4915
5037
  }
4916
5038
  this.state.aggregates.push(agg);
4917
5039
  }
@@ -5956,7 +6078,20 @@ var UpsertBuilder = class _UpsertBuilder extends MutationBuilderBase {
5956
6078
  };
5957
6079
 
5958
6080
  // src/dx/negotiate-features.ts
5959
- import { UnsupportedFeatureError } from "@dbsp/types";
6081
+ var UnsupportedFeatureError = class extends Error {
6082
+ constructor(feature, adapter, element) {
6083
+ super(
6084
+ `Unsupported feature "${feature}" on adapter "${adapter}" for "${element}"`
6085
+ );
6086
+ this.feature = feature;
6087
+ this.adapter = adapter;
6088
+ this.element = element;
6089
+ this.name = "UnsupportedFeatureError";
6090
+ }
6091
+ feature;
6092
+ adapter;
6093
+ element;
6094
+ };
5960
6095
  function resolveBehavior(feature, config) {
5961
6096
  if (typeof config === "string") return config;
5962
6097
  return config.overrides?.[feature] ?? config.default;
@@ -7004,10 +7139,9 @@ function stream(builder, options) {
7004
7139
  };
7005
7140
  let hookIntent = rawIntent;
7006
7141
  try {
7007
- const afterHookCtx = await runBeforeQueryHooks(
7008
- hookStore.beforeQuery,
7009
- ctx,
7010
- onHookError
7142
+ const afterHookCtx = await withReentrancyGuard(
7143
+ hookStore,
7144
+ (s) => runBeforeQueryHooks(s.beforeQuery, ctx, onHookError)
7011
7145
  );
7012
7146
  hookIntent = afterHookCtx.intent;
7013
7147
  } catch (error) {
@@ -7210,27 +7344,25 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
7210
7344
  }
7211
7345
  count(fieldOrOptions, as) {
7212
7346
  const builder = this.clone();
7213
- const agg = { function: "count" };
7347
+ let field;
7348
+ let alias = as;
7349
+ let distinct2;
7214
7350
  if (fieldOrOptions === void 0) {
7215
7351
  } else if (typeof fieldOrOptions === "string") {
7216
- agg.field = fieldOrOptions;
7217
- if (as !== void 0) {
7218
- agg.as = as;
7219
- }
7352
+ field = fieldOrOptions;
7220
7353
  } else if (isDistinctField(fieldOrOptions)) {
7221
- agg.field = fieldOrOptions.field;
7222
- agg.distinct = true;
7223
- if (as !== void 0) {
7224
- agg.as = as;
7225
- }
7354
+ field = fieldOrOptions.field;
7355
+ distinct2 = true;
7226
7356
  } else {
7227
- if (fieldOrOptions.field !== void 0) {
7228
- agg.field = fieldOrOptions.field;
7229
- }
7230
- if (fieldOrOptions.as !== void 0) {
7231
- agg.as = fieldOrOptions.as;
7232
- }
7233
- }
7357
+ field = fieldOrOptions.field;
7358
+ alias = fieldOrOptions.as ?? as;
7359
+ }
7360
+ const agg = {
7361
+ function: "count",
7362
+ ...field !== void 0 && { field },
7363
+ ...alias !== void 0 && { as: alias },
7364
+ ...distinct2 !== void 0 && { distinct: distinct2 }
7365
+ };
7234
7366
  builder.aggregates.push(agg);
7235
7367
  return builder;
7236
7368
  }
@@ -7238,13 +7370,12 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
7238
7370
  const builder = this.clone();
7239
7371
  const isDistinct = isDistinctField(field);
7240
7372
  const fieldName = isDistinct ? field.field : field;
7241
- const agg = { function: "sum", field: fieldName };
7242
- if (isDistinct) {
7243
- agg.distinct = true;
7244
- }
7245
- if (as !== void 0) {
7246
- agg.as = as;
7247
- }
7373
+ const agg = {
7374
+ function: "sum",
7375
+ field: fieldName,
7376
+ ...isDistinct && { distinct: true },
7377
+ ...as !== void 0 && { as }
7378
+ };
7248
7379
  builder.aggregates.push(agg);
7249
7380
  return builder;
7250
7381
  }
@@ -7252,31 +7383,32 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
7252
7383
  const builder = this.clone();
7253
7384
  const isDistinct = isDistinctField(field);
7254
7385
  const fieldName = isDistinct ? field.field : field;
7255
- const agg = { function: "avg", field: fieldName };
7256
- if (isDistinct) {
7257
- agg.distinct = true;
7258
- }
7259
- if (as !== void 0) {
7260
- agg.as = as;
7261
- }
7386
+ const agg = {
7387
+ function: "avg",
7388
+ field: fieldName,
7389
+ ...isDistinct && { distinct: true },
7390
+ ...as !== void 0 && { as }
7391
+ };
7262
7392
  builder.aggregates.push(agg);
7263
7393
  return builder;
7264
7394
  }
7265
7395
  min(field, as) {
7266
7396
  const builder = this.clone();
7267
- const agg = { function: "min", field };
7268
- if (as !== void 0) {
7269
- agg.as = as;
7270
- }
7397
+ const agg = {
7398
+ function: "min",
7399
+ field,
7400
+ ...as !== void 0 && { as }
7401
+ };
7271
7402
  builder.aggregates.push(agg);
7272
7403
  return builder;
7273
7404
  }
7274
7405
  max(field, as) {
7275
7406
  const builder = this.clone();
7276
- const agg = { function: "max", field };
7277
- if (as !== void 0) {
7278
- agg.as = as;
7279
- }
7407
+ const agg = {
7408
+ function: "max",
7409
+ field,
7410
+ ...as !== void 0 && { as }
7411
+ };
7280
7412
  builder.aggregates.push(agg);
7281
7413
  return builder;
7282
7414
  }
@@ -7465,6 +7597,13 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
7465
7597
  "join(batchValuesRef): an `on` condition is required for BatchValues joins"
7466
7598
  );
7467
7599
  }
7600
+ validateIdentifier(bv.alias, "alias");
7601
+ for (const col2 of bv.columns) {
7602
+ validateIdentifier(col2, "column");
7603
+ }
7604
+ if (opts.as !== void 0) {
7605
+ validateIdentifier(opts.as, "alias");
7606
+ }
7468
7607
  const joinIntent = {
7469
7608
  batchValues: {
7470
7609
  data: bv.data,
@@ -7480,6 +7619,9 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
7480
7619
  builder.joinIntents.push(joinIntent);
7481
7620
  } else {
7482
7621
  validateIdentifier(relationOrTableOrBatch, "table");
7622
+ if (opts?.as !== void 0) {
7623
+ validateIdentifier(opts.as, "alias");
7624
+ }
7483
7625
  const joinIntent = opts?.on ? {
7484
7626
  table: relationOrTableOrBatch,
7485
7627
  on: opts.on,
@@ -8281,7 +8423,9 @@ var QueryBuilderImpl = class _QueryBuilderImpl {
8281
8423
  const builder = new _QueryBuilderImpl(
8282
8424
  { ...this.ctx, ...ctxOverride },
8283
8425
  this.from,
8284
- { ...this.relationHints }
8426
+ {
8427
+ ...this.relationHints
8428
+ }
8285
8429
  );
8286
8430
  builder.includes.push(...this.includes);
8287
8431
  builder.recursiveIncludes.push(...this.recursiveIncludes);
@@ -9255,6 +9399,7 @@ function rangeOverlaps(fieldOrColumn, valueOrRange, rangeType = "daterange") {
9255
9399
  kind: "range",
9256
9400
  field: fieldOrColumn,
9257
9401
  operator: "overlaps",
9402
+ // Cast: non-array branch is RangeOperand (tuple path already returned above)
9258
9403
  value: valueOrRange
9259
9404
  };
9260
9405
  }
@@ -10064,7 +10209,8 @@ var FEATURE_TO_FLAG = {
10064
10209
  indexOpclass: "supportsDDLIndexOpclass",
10065
10210
  indexInclude: "supportsDDLIndexInclude",
10066
10211
  partialIndex: "supportsDDLPartialIndexes",
10067
- expressionIndex: "supportsDDLExpressionIndexes"
10212
+ expressionIndex: "supportsDDLExpressionIndexes",
10213
+ rowLevelSecurity: "supportsDDLRowLevelSecurity"
10068
10214
  };
10069
10215
  function createDialectCapabilities(overrides, options) {
10070
10216
  const result = {
@@ -11278,6 +11424,7 @@ export {
11278
11424
  UnknownDialectError,
11279
11425
  UnsafeOperationError,
11280
11426
  UnsupportedCapabilityError,
11427
+ UnsupportedFeatureError,
11281
11428
  UnsupportedStrategyError,
11282
11429
  UpdateBuilder,
11283
11430
  UpsertBuilder,