@vantreeseba/drizzle-graphql 7.1.0 → 7.3.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.cjs CHANGED
@@ -996,10 +996,10 @@ var runMutation = async (db, context, info, txCtx, body) => {
996
996
  }
997
997
  return runOnSharedTx(state, body);
998
998
  };
999
- var batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, orderCtx) => {
999
+ var batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, orderCtx, whereArgs) => {
1000
1000
  const cols = (0, import_drizzle_orm4.getColumns)(targetTable);
1001
1001
  const orderExprs = [
1002
- ...orderByArg ? extractOrderBy(targetTable, orderByArg, orderCtx) : [],
1002
+ ...orderByArg ? extractOrderBy(targetTable, orderByArg, orderCtx, whereArgs) : [],
1003
1003
  ...primaryKeyOrderExprs(targetTable, pkNames)
1004
1004
  ];
1005
1005
  const orderClause = orderExprs.length ? import_drizzle_orm4.sql` order by ${import_drizzle_orm4.sql.join(orderExprs, import_drizzle_orm4.sql`, `)}` : import_drizzle_orm4.sql``;
@@ -1110,11 +1110,12 @@ var createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limits
1110
1110
  limit ?? null,
1111
1111
  offset ?? null,
1112
1112
  targetPkNames,
1113
- relationFilterCtx(filterCtx, targetTableName)
1113
+ relationFilterCtx(filterCtx, targetTableName),
1114
+ whereArg
1114
1115
  );
1115
1116
  } else {
1116
1117
  let q = executor.select().from(targetTable).where(whereCondition);
1117
- const orderExprs = cursorEntries ? cursorOrderExprs(targetTable, cursorEntries) : orderByArg ? extractOrderBy(targetTable, orderByArg, relationFilterCtx(filterCtx, targetTableName)) : [];
1118
+ const orderExprs = cursorEntries ? cursorOrderExprs(targetTable, cursorEntries) : orderByArg ? extractOrderBy(targetTable, orderByArg, relationFilterCtx(filterCtx, targetTableName), whereArg) : [];
1118
1119
  if (orderExprs.length) {
1119
1120
  q = q.orderBy(...orderExprs);
1120
1121
  }
@@ -1182,6 +1183,30 @@ var resolveLimitPolicy = (global, table) => {
1182
1183
  }
1183
1184
  return { defaultLimit, maxLimit, clampToMax: table?.clampToMax ?? global?.clampToMax ?? false };
1184
1185
  };
1186
+ var excludedColumnRegistry = /* @__PURE__ */ new WeakMap();
1187
+ var registerColumnExclusions = (tables, exclude) => {
1188
+ for (const [tableName, table] of Object.entries(tables)) {
1189
+ const hidden = exclude?.columns?.[tableName];
1190
+ if (hidden?.length) {
1191
+ excludedColumnRegistry.set(table, new Set(hidden));
1192
+ } else {
1193
+ excludedColumnRegistry.delete(table);
1194
+ }
1195
+ }
1196
+ };
1197
+ var hasExcludedColumns = (table) => excludedColumnRegistry.has(table);
1198
+ var excludedColumnsKey = (table) => {
1199
+ const hidden = excludedColumnRegistry.get(table);
1200
+ return hidden ? [...hidden].sort().join(",") : "";
1201
+ };
1202
+ var visibleColumns = (table) => {
1203
+ const columns = (0, import_drizzle_orm4.getColumns)(table);
1204
+ const hidden = excludedColumnRegistry.get(table);
1205
+ if (!hidden) {
1206
+ return columns;
1207
+ }
1208
+ return Object.fromEntries(Object.entries(columns).filter(([columnName]) => !hidden.has(columnName)));
1209
+ };
1185
1210
  var listFieldComplexity = (options, policy) => ({ args, childComplexity }) => {
1186
1211
  const limit = args["limit"];
1187
1212
  const requested = typeof limit === "number" && limit > 0 ? limit : void 0;
@@ -1301,6 +1326,10 @@ var innerOrder = new import_graphql5.GraphQLInputObjectType({
1301
1326
  nulls: {
1302
1327
  type: orderNulls,
1303
1328
  description: "Where NULL values sort. Defaults to the database's own rule (PostgreSQL: last on asc, first on desc; MySQL/SQLite: first on asc, last on desc)"
1329
+ },
1330
+ matchFilterOrder: {
1331
+ type: import_graphql5.GraphQLBoolean,
1332
+ description: "Sort by this column's position in the `inArray` list the same request's `where` gives it, rather than by the column's own value \u2014 `direction: asc` keeps the list's order, `desc` reverses it. Requires an `inArray` filter on the same column at the top level of `where`, and cannot be combined with `after` or `distinct`."
1304
1333
  }
1305
1334
  }
1306
1335
  });
@@ -1366,10 +1395,59 @@ var jsonFilterFields = (column, colType) => {
1366
1395
  description: "Value structurally contains this JSON (Postgres `@>` / MySQL JSON_CONTAINS)"
1367
1396
  }
1368
1397
  } : {},
1398
+ path: {
1399
+ type: new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(jsonPathFilter)),
1400
+ description: "Compares the value at one path inside the document. Several entries are ANDed; a single object may be passed without the list brackets."
1401
+ },
1369
1402
  isNull: { type: import_graphql5.GraphQLBoolean },
1370
1403
  isNotNull: { type: import_graphql5.GraphQLBoolean }
1371
1404
  };
1372
1405
  };
1406
+ var jsonPathCast = new import_graphql5.GraphQLEnumType({
1407
+ name: "JSONPathCast",
1408
+ description: "How to read the value at a JSON path before comparing it",
1409
+ values: {
1410
+ TEXT: { value: "text", description: "Compare as text (lexicographic ordering)" },
1411
+ NUMBER: { value: "number", description: "Compare as a number; a non-numeric value never matches" },
1412
+ BOOLEAN: { value: "boolean", description: "Compare as a boolean" }
1413
+ }
1414
+ });
1415
+ var jsonPathFilter = new import_graphql5.GraphQLInputObjectType({
1416
+ name: "JSONPathFilter",
1417
+ fields: {
1418
+ path: {
1419
+ type: new import_graphql5.GraphQLNonNull(new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(import_graphql5.GraphQLString))),
1420
+ description: 'Keys to walk from the document root, e.g. `["profile", "level"]`. An all-digits key indexes an array.'
1421
+ },
1422
+ as: { type: jsonPathCast, description: "Overrides how the value is read before comparing" },
1423
+ eq: { type: import_graphql_scalars.GraphQLJSON, description: "Equal to" },
1424
+ ne: { type: import_graphql_scalars.GraphQLJSON, description: "Not equal to" },
1425
+ lt: { type: import_graphql_scalars.GraphQLJSON, description: "Less than" },
1426
+ lte: { type: import_graphql_scalars.GraphQLJSON, description: "Less than or equal to" },
1427
+ gt: { type: import_graphql_scalars.GraphQLJSON, description: "Greater than" },
1428
+ gte: { type: import_graphql_scalars.GraphQLJSON, description: "Greater than or equal to" },
1429
+ startsWith: {
1430
+ type: import_graphql5.GraphQLString,
1431
+ description: "Extracted value starts with this string. `%`, `_` and `\\` are matched literally."
1432
+ },
1433
+ endsWith: {
1434
+ type: import_graphql5.GraphQLString,
1435
+ description: "Extracted value ends with this string. `%`, `_` and `\\` are matched literally."
1436
+ },
1437
+ contains: {
1438
+ type: import_graphql5.GraphQLString,
1439
+ description: "Extracted value contains this string. `%`, `_` and `\\` are matched literally."
1440
+ },
1441
+ iStartsWith: { type: import_graphql5.GraphQLString, description: "Case-insensitive `startsWith`." },
1442
+ iEndsWith: { type: import_graphql5.GraphQLString, description: "Case-insensitive `endsWith`." },
1443
+ iContains: { type: import_graphql5.GraphQLString, description: "Case-insensitive `contains`." },
1444
+ isNull: {
1445
+ type: import_graphql5.GraphQLBoolean,
1446
+ description: "When true, matches rows where the path is missing or holds JSON null"
1447
+ },
1448
+ isNotNull: { type: import_graphql5.GraphQLBoolean, description: "When true, matches rows where the path holds a value" }
1449
+ }
1450
+ });
1373
1451
  var IN_ARRAY_DESCRIPTION = "Matches any one of these values (SQL `IN`)";
1374
1452
  var NOT_IN_ARRAY_DESCRIPTION = "Matches none of these values (SQL `NOT IN`)";
1375
1453
  var arrayFilterFields = (colType, colArr) => {
@@ -1491,17 +1569,20 @@ var generateColumnFilterValues = (column, tableName, columnName, cacheCtx) => {
1491
1569
  };
1492
1570
  var orderMap = /* @__PURE__ */ new WeakMap();
1493
1571
  var generateTableOrderCached = (table) => {
1494
- if (orderMap.has(table)) {
1572
+ const cacheable = !hasExcludedColumns(table);
1573
+ if (cacheable && orderMap.has(table)) {
1495
1574
  return orderMap.get(table);
1496
1575
  }
1497
1576
  let remapped = {};
1498
1577
  try {
1499
- const columns = (0, import_drizzle_orm4.getColumns)(table);
1578
+ const columns = visibleColumns(table);
1500
1579
  const columnEntries = Object.entries(columns);
1501
1580
  remapped = Object.fromEntries(
1502
1581
  columnEntries.map(([columnName, _columnDescription]) => [columnName, { type: innerOrder }])
1503
1582
  );
1504
- orderMap.set(table, remapped);
1583
+ if (cacheable) {
1584
+ orderMap.set(table, remapped);
1585
+ }
1505
1586
  } catch (_err) {
1506
1587
  }
1507
1588
  return remapped;
@@ -1510,7 +1591,7 @@ var generateTableFilterValuesCached = (table, tableName, cacheCtx) => {
1510
1591
  if (cacheCtx.filterFieldCache.has(table)) {
1511
1592
  return cacheCtx.filterFieldCache.get(table);
1512
1593
  }
1513
- const columns = (0, import_drizzle_orm4.getColumns)(table);
1594
+ const columns = visibleColumns(table);
1514
1595
  const columnEntries = Object.entries(columns);
1515
1596
  const remapped = Object.fromEntries(
1516
1597
  columnEntries.map(([columnName, column]) => [
@@ -1531,7 +1612,7 @@ var generateTableSelectTypeFieldsCached = (table, tableName, cacheCtx) => {
1531
1612
  if (cacheCtx.selectFieldCache.has(table)) {
1532
1613
  return cacheCtx.selectFieldCache.get(table);
1533
1614
  }
1534
- const columns = (0, import_drizzle_orm4.getColumns)(table);
1615
+ const columns = visibleColumns(table);
1535
1616
  const columnEntries = Object.entries(columns);
1536
1617
  const remapped = Object.fromEntries(
1537
1618
  columnEntries.map(([columnName, column]) => [
@@ -1889,7 +1970,7 @@ var generateTableTypes = (tableName, tables, relationMap, withReturning, relatio
1889
1970
  relationAggregateFactory
1890
1971
  );
1891
1972
  const table = tables[tableName];
1892
- const columns = (0, import_drizzle_orm4.getColumns)(table);
1973
+ const columns = visibleColumns(table);
1893
1974
  const columnEntries = Object.entries(columns);
1894
1975
  const relaxedColumns = nestedWrites?.relaxedColumns(tableName);
1895
1976
  const insertFields = Object.fromEntries(
@@ -1960,6 +2041,9 @@ var orderByEntries = (orderArgs) => Object.entries(orderArgs).sort((a, b) => (b[
1960
2041
  if (typeof config === "object" && config.direction === void 0) {
1961
2042
  throw new import_graphql5.GraphQLError(`ORDER BY ${column}: ordering through a relation is not supported in this query`);
1962
2043
  }
2044
+ if (config.matchFilterOrder) {
2045
+ throw new import_graphql5.GraphQLError(`ORDER BY ${column}: 'matchFilterOrder' is not supported in this query`);
2046
+ }
1963
2047
  return [column, config.direction, config.nulls ?? void 0];
1964
2048
  });
1965
2049
  var orderExpressions = (expr, direction, nulls, dialectColumn) => {
@@ -1994,7 +2078,22 @@ var extendRelationOrderChain = (parentTable, relationName, relEntry, ctx, chain)
1994
2078
  table: aliasedTarget
1995
2079
  };
1996
2080
  };
1997
- var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out) => {
2081
+ var filterOrderExpression = (column, columnName, whereArgs) => {
2082
+ const values = whereArgs?.[columnName]?.inArray;
2083
+ if (!Array.isArray(values)) {
2084
+ throw new import_graphql5.GraphQLError(
2085
+ `ORDER BY ${columnName}: 'matchFilterOrder' needs an 'inArray' filter on the same column in this query's 'where'`
2086
+ );
2087
+ }
2088
+ if (!values.length) {
2089
+ return import_drizzle_orm4.sql`0`;
2090
+ }
2091
+ const branches = values.map(
2092
+ (value, index) => import_drizzle_orm4.sql`when ${column} = ${remapFromGraphQLCore(value, column, columnName)} then ${import_drizzle_orm4.sql.raw(String(index))}`
2093
+ );
2094
+ return import_drizzle_orm4.sql`case ${import_drizzle_orm4.sql.join(branches, import_drizzle_orm4.sql` `)} else ${import_drizzle_orm4.sql.raw(String(values.length))} end`;
2095
+ };
2096
+ var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out, whereArgs) => {
1998
2097
  const columns = (0, import_drizzle_orm4.getColumns)(table);
1999
2098
  const relations = ctx?.relationMap[tableKey];
2000
2099
  for (const [key, config] of Object.entries(orderArgs)) {
@@ -2003,8 +2102,11 @@ var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out) => {
2003
2102
  }
2004
2103
  const column = columns[key];
2005
2104
  if (column) {
2105
+ if (config.matchFilterOrder && chain) {
2106
+ throw new import_graphql5.GraphQLError(`ORDER BY ${key}: 'matchFilterOrder' is not supported through a relation`);
2107
+ }
2006
2108
  out.push({
2007
- expression: chain ? import_drizzle_orm4.sql`(select ${column} from ${import_drizzle_orm4.sql.join(chain.fromParts, import_drizzle_orm4.sql`, `)} where ${(0, import_drizzle_orm4.and)(...chain.conditions)})` : column,
2109
+ expression: config.matchFilterOrder ? filterOrderExpression(column, key, whereArgs) : chain ? import_drizzle_orm4.sql`(select ${column} from ${import_drizzle_orm4.sql.join(chain.fromParts, import_drizzle_orm4.sql`, `)} where ${(0, import_drizzle_orm4.and)(...chain.conditions)})` : column,
2008
2110
  column,
2009
2111
  direction: config.direction,
2010
2112
  nulls: config.nulls ?? void 0,
@@ -2017,12 +2119,12 @@ var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out) => {
2017
2119
  throw new import_graphql5.GraphQLError(`ORDER BY ${key}: Unknown column or relation`);
2018
2120
  }
2019
2121
  const nextChain = extendRelationOrderChain(chain?.table ?? table, key, relEntry, ctx, chain);
2020
- collectOrderEntries(nextChain.table, relEntry.targetTableName, config, ctx, nextChain, out);
2122
+ collectOrderEntries(nextChain.table, relEntry.targetTableName, config, ctx, nextChain, out, void 0);
2021
2123
  }
2022
2124
  };
2023
- var extractOrderBy = (table, orderArgs, ctx) => {
2125
+ var extractOrderBy = (table, orderArgs, ctx, whereArgs) => {
2024
2126
  const entries = [];
2025
- collectOrderEntries(table, ctx?.tableKey ?? "", orderArgs, ctx, void 0, entries);
2127
+ collectOrderEntries(table, ctx?.tableKey ?? "", orderArgs, ctx, void 0, entries, whereArgs);
2026
2128
  return entries.sort((a, b) => b.priority - a.priority).flatMap((entry) => orderExpressions(entry.expression, entry.direction, entry.nulls, entry.column));
2027
2129
  };
2028
2130
  var LIKE_ESCAPE_CHAR = "\\";
@@ -2054,6 +2156,105 @@ var jsonContains = (column, columnName, value) => {
2054
2156
  throw new import_graphql5.GraphQLError(`WHERE ${columnName}: Operator 'contains' is not supported for this dialect!`);
2055
2157
  }
2056
2158
  };
2159
+ var sqlFalse = () => import_drizzle_orm4.sql`1 = 0`;
2160
+ var sqlTrue = () => import_drizzle_orm4.sql`1 = 1`;
2161
+ var jsonPathString = (path) => `$${path.map((part) => /^\d+$/.test(part) ? `[${part}]` : `."${part.replace(/(["\\])/g, "\\$1")}"`).join("")}`;
2162
+ var NUMERIC_TEXT_PATTERN = "^\\s*-?(\\d+\\.?\\d*|\\.\\d+)([eE][-+]?\\d+)?\\s*$";
2163
+ var jsonPathExprs = (column, path) => {
2164
+ switch (columnDialect(column)) {
2165
+ case "pg": {
2166
+ const pathArray = import_drizzle_orm4.sql`array[${import_drizzle_orm4.sql.join(
2167
+ path.map((part) => import_drizzle_orm4.sql`${part}`),
2168
+ import_drizzle_orm4.sql`, `
2169
+ )}]::text[]`;
2170
+ const text = import_drizzle_orm4.sql`(${column} #>> ${pathArray})`;
2171
+ return {
2172
+ text,
2173
+ number: import_drizzle_orm4.sql`(case when ${text} ~ ${NUMERIC_TEXT_PATTERN} then ${text}::numeric end)`,
2174
+ boolean: text,
2175
+ encodeBoolean: (value) => String(value)
2176
+ };
2177
+ }
2178
+ case "mysql": {
2179
+ const extracted = import_drizzle_orm4.sql`json_extract(${column}, ${jsonPathString(path)})`;
2180
+ const text = import_drizzle_orm4.sql`(case when json_type(${extracted}) = 'NULL' then null else json_unquote(${extracted}) end)`;
2181
+ return {
2182
+ text,
2183
+ number: import_drizzle_orm4.sql`(case when ${text} regexp ${NUMERIC_TEXT_PATTERN} then cast(${text} as decimal(65, 30)) end)`,
2184
+ boolean: text,
2185
+ encodeBoolean: (value) => String(value)
2186
+ };
2187
+ }
2188
+ default: {
2189
+ const extracted = import_drizzle_orm4.sql`json_extract(${column}, ${jsonPathString(path)})`;
2190
+ return {
2191
+ text: import_drizzle_orm4.sql`cast(${extracted} as text)`,
2192
+ number: import_drizzle_orm4.sql`(case when typeof(${extracted}) in ('integer', 'real') then ${extracted} end)`,
2193
+ // SQLite has no boolean type: a JSON `true` comes back as the integer 1.
2194
+ boolean: extracted,
2195
+ encodeBoolean: (value) => value ? 1 : 0
2196
+ };
2197
+ }
2198
+ }
2199
+ };
2200
+ var JSON_PATH_COMPARISONS = {
2201
+ eq: "=",
2202
+ ne: "<>",
2203
+ lt: "<",
2204
+ lte: "<=",
2205
+ gt: ">",
2206
+ gte: ">="
2207
+ };
2208
+ var inferJsonPathCast = (value) => typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "text";
2209
+ var jsonPathCondition = (column, columnName, filter) => {
2210
+ const { path, as: castOverride, ...operators } = filter;
2211
+ const locator = `${columnName}.path`;
2212
+ if (!Array.isArray(path) || !path.length) {
2213
+ throw new import_graphql5.GraphQLError(`WHERE ${locator}: 'path' must name at least one key`);
2214
+ }
2215
+ const exprs = jsonPathExprs(column, path);
2216
+ const variants = [];
2217
+ for (const [operatorName, operatorValue] of Object.entries(operators)) {
2218
+ if (operatorValue === null || operatorValue === void 0) {
2219
+ continue;
2220
+ }
2221
+ if (operatorName === "isNull" || operatorName === "isNotNull") {
2222
+ if (operatorValue === false) {
2223
+ continue;
2224
+ }
2225
+ variants.push(operatorName === "isNull" ? import_drizzle_orm4.sql`${exprs.text} is null` : import_drizzle_orm4.sql`${exprs.text} is not null`);
2226
+ continue;
2227
+ }
2228
+ if (operatorName in safeLikeOps) {
2229
+ const { buildPattern, insensitive } = safeLikeOps[operatorName];
2230
+ if (typeof operatorValue !== "string") {
2231
+ throw new import_graphql5.GraphQLError(`WHERE ${locator}: operator '${operatorName}' takes a string`);
2232
+ }
2233
+ variants.push(safeLikeCondition(exprs.text, buildPattern(operatorValue), insensitive));
2234
+ continue;
2235
+ }
2236
+ const comparison = JSON_PATH_COMPARISONS[operatorName];
2237
+ if (!comparison) {
2238
+ throw new import_graphql5.GraphQLError(`WHERE ${locator}: Unknown operator: ${operatorName}`);
2239
+ }
2240
+ const cast = castOverride ?? inferJsonPathCast(operatorValue);
2241
+ if (cast === "number") {
2242
+ const numeric = Number(operatorValue);
2243
+ if (Number.isNaN(numeric)) {
2244
+ throw new import_graphql5.GraphQLError(
2245
+ `WHERE ${locator}: operator '${operatorName}' compares as a number, so its value must be one`
2246
+ );
2247
+ }
2248
+ variants.push(import_drizzle_orm4.sql`${exprs.number} ${import_drizzle_orm4.sql.raw(comparison)} ${numeric}`);
2249
+ } else if (cast === "boolean") {
2250
+ const truthy = operatorValue === true || operatorValue === "true";
2251
+ variants.push(import_drizzle_orm4.sql`${exprs.boolean} ${import_drizzle_orm4.sql.raw(comparison)} ${exprs.encodeBoolean(truthy)}`);
2252
+ } else {
2253
+ variants.push(import_drizzle_orm4.sql`${exprs.text} ${import_drizzle_orm4.sql.raw(comparison)} ${String(operatorValue)}`);
2254
+ }
2255
+ }
2256
+ return variants.length ? variants.length > 1 ? (0, import_drizzle_orm4.and)(...variants) : variants[0] : void 0;
2257
+ };
2057
2258
  var extractFiltersColumn = (column, columnName, operators) => {
2058
2259
  const { OR, AND, NOT, ...restOperators } = operators;
2059
2260
  const entries = Object.entries(restOperators);
@@ -2075,6 +2276,13 @@ var extractFiltersColumn = (column, columnName, operators) => {
2075
2276
  variants.push(singleValueOps[operatorName](column, singleValue));
2076
2277
  } else if (operatorName in stringValueOps) {
2077
2278
  variants.push(stringValueOps[operatorName](column, operatorValue));
2279
+ } else if (operatorName === "path" && isJsonColumn2(column)) {
2280
+ for (const pathFilter of operatorValue) {
2281
+ const extracted = jsonPathCondition(column, columnName, pathFilter);
2282
+ if (extracted) {
2283
+ variants.push(extracted);
2284
+ }
2285
+ }
2078
2286
  } else if (operatorName === "contains" && isJsonColumn2(column)) {
2079
2287
  variants.push(jsonContains(column, columnName, operatorValue));
2080
2288
  } else if (operatorName in safeLikeOps) {
@@ -2082,7 +2290,8 @@ var extractFiltersColumn = (column, columnName, operators) => {
2082
2290
  variants.push(safeLikeCondition(column, buildPattern(operatorValue), insensitive));
2083
2291
  } else if (operatorName in arrayValueOps) {
2084
2292
  if (!operatorValue.length) {
2085
- throw new import_graphql5.GraphQLError(`WHERE ${columnName}: Unable to use operator ${operatorName} with an empty array!`);
2293
+ variants.push(operatorName === "inArray" ? sqlFalse() : sqlTrue());
2294
+ continue;
2086
2295
  }
2087
2296
  const arrayValue = operatorValue.map((val) => remapFromGraphQLCore(val, column, columnName));
2088
2297
  variants.push(arrayValueOps[operatorName](column, arrayValue));
@@ -2090,7 +2299,8 @@ var extractFiltersColumn = (column, columnName, operators) => {
2090
2299
  variants.push((0, import_drizzle_orm4.arrayContains)(column, [operatorValue]));
2091
2300
  } else if (operatorName in arrayMembershipOps) {
2092
2301
  if (!operatorValue.length) {
2093
- throw new import_graphql5.GraphQLError(`WHERE ${columnName}: Unable to use operator ${operatorName} with an empty array!`);
2302
+ variants.push(operatorName === "hasSome" ? sqlFalse() : sqlTrue());
2303
+ continue;
2094
2304
  }
2095
2305
  variants.push(arrayMembershipOps[operatorName](column, operatorValue));
2096
2306
  } else if (operatorName === "isEmpty") {
@@ -2353,7 +2563,7 @@ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, ori
2353
2563
  } : void 0;
2354
2564
  const hasPagination = offset != null || limit != null;
2355
2565
  const pkNames = targetPkNames ?? [];
2356
- thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName)) : hasPagination && pkNames.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0;
2566
+ thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName), relWhere) : hasPagination && pkNames.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0;
2357
2567
  thisRecord.offset = offset;
2358
2568
  thisRecord.limit = limit;
2359
2569
  const relWith = relationField ? extractRelationsParamsInner(
@@ -2433,6 +2643,15 @@ var primaryKeyOrderExprs = (table, pkNames) => {
2433
2643
  var CURSOR_FIELD_NAME = "cursor";
2434
2644
  var ROW_CURSOR_PROP = "__drizzle_graphql_cursor";
2435
2645
  var orderByHasRelationEntry = (orderBy) => !!orderBy && Object.values(orderBy).some((config) => config && typeof config === "object" && config.direction === void 0);
2646
+ var orderByCursorObstacle = (orderBy) => {
2647
+ if (orderByHasRelationEntry(orderBy)) {
2648
+ return "'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor.";
2649
+ }
2650
+ if (orderBy && Object.values(orderBy).some((config) => config && typeof config === "object" && config.matchFilterOrder)) {
2651
+ return "'after' cannot be combined with 'matchFilterOrder' \u2014 a row's position in the request's own filter list is not a value of the row, so it cannot be encoded into a cursor.";
2652
+ }
2653
+ return void 0;
2654
+ };
2436
2655
  var cursorOrderingEntries = (orderBy, pkNames) => {
2437
2656
  const entries = orderBy ? orderByEntries(orderBy) : [];
2438
2657
  const seen = new Set(entries.map(([column]) => column));
@@ -2564,7 +2783,7 @@ var attachRowCursors = (rows, entries) => {
2564
2783
  };
2565
2784
  var rowCursorResolver = (source) => source?.[ROW_CURSOR_PROP] ?? null;
2566
2785
  var getUniqueColumnSets = (table, getTableConfig4) => {
2567
- const cols = (0, import_drizzle_orm4.getColumns)(table);
2786
+ const cols = visibleColumns(table);
2568
2787
  const propNameByColumnName = new Map(Object.entries(cols).map(([propName, col]) => [col.name, propName]));
2569
2788
  const toPropNames = (columnNames) => {
2570
2789
  const propNames = [];
@@ -2604,12 +2823,13 @@ var getUniqueColumnSets = (table, getTableConfig4) => {
2604
2823
  var DISTINCT_RN = "__drizzle_graphql_distinct_rn";
2605
2824
  var columnEnumCache = /* @__PURE__ */ new WeakMap();
2606
2825
  var generateColumnEnum = (table, enumName, description, predicate = () => true) => {
2826
+ const cacheKey = `${enumName}\0${excludedColumnsKey(table)}`;
2607
2827
  let tableCache = columnEnumCache.get(table);
2608
- const cached = tableCache?.get(enumName);
2828
+ const cached = tableCache?.get(cacheKey);
2609
2829
  if (cached) {
2610
2830
  return cached;
2611
2831
  }
2612
- const columnNames = Object.entries((0, import_drizzle_orm4.getColumns)(table)).filter(([columnName, column]) => predicate(column, columnName)).map(([columnName]) => columnName);
2832
+ const columnNames = Object.entries(visibleColumns(table)).filter(([columnName, column]) => predicate(column, columnName)).map(([columnName]) => columnName);
2613
2833
  if (!columnNames.length) {
2614
2834
  return void 0;
2615
2835
  }
@@ -2622,7 +2842,7 @@ var generateColumnEnum = (table, enumName, description, predicate = () => true)
2622
2842
  tableCache = /* @__PURE__ */ new Map();
2623
2843
  columnEnumCache.set(table, tableCache);
2624
2844
  }
2625
- tableCache.set(enumName, enumType);
2845
+ tableCache.set(cacheKey, enumType);
2626
2846
  return enumType;
2627
2847
  };
2628
2848
  var generateDistinctEnum = (table, typeName) => generateColumnEnum(table, `${typeName}DistinctColumn`, `Columns of ${typeName} that a query can be made distinct on`);
@@ -3028,11 +3248,10 @@ var runRelationalSelect = async (opts) => {
3028
3248
  if (after != null && distinct) {
3029
3249
  throw new import_graphql5.GraphQLError("'after' cannot be combined with 'distinct'.");
3030
3250
  }
3031
- if (orderByHasRelationEntry(orderBy)) {
3251
+ const cursorObstacle = orderByCursorObstacle(orderBy);
3252
+ if (cursorObstacle) {
3032
3253
  if (after != null) {
3033
- throw new import_graphql5.GraphQLError(
3034
- "'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor."
3035
- );
3254
+ throw new import_graphql5.GraphQLError(cursorObstacle);
3036
3255
  }
3037
3256
  } else if (!pkNames?.length) {
3038
3257
  if (after != null) {
@@ -3072,13 +3291,13 @@ var runRelationalSelect = async (opts) => {
3072
3291
  // drizzle-orm v1 RQB calls orderBy/where with the aliased table proxy — use it
3073
3292
  // directly so column refs match the CTE alias.
3074
3293
  orderBy: distinctKeys ? (aliasedTable2) => [
3075
- ...orderBy ? extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName)) : [],
3294
+ ...orderBy ? extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName), where) : [],
3076
3295
  ...primaryKeyOrderExprs(aliasedTable2, pkNames)
3077
3296
  ] : cursorEntries ? (
3078
3297
  // Cursor pagination needs a total order: the request's orderBy plus the PK tiebreak,
3079
3298
  // exactly the ordering the cursor encodes and the keyset predicate compares against.
3080
3299
  (aliasedTable2) => cursorOrderExprs(aliasedTable2, cursorEntries)
3081
- ) : orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName)) : needsDefaultOrder && pkNames?.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0,
3300
+ ) : orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName), where) : needsDefaultOrder && pkNames?.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0,
3082
3301
  where: distinctKeys ? { RAW: (aliasedTable2) => primaryKeyRestriction(aliasedTable2, pkNames, distinctKeys) } : where || cursorValues ? {
3083
3302
  RAW: (aliasedTable2) => (0, import_drizzle_orm4.and)(
3084
3303
  where ? extractFilters(aliasedTable2, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0,
@@ -3210,7 +3429,7 @@ var classifyAggregateColumns = (table, tableName) => {
3210
3429
  const numeric = {};
3211
3430
  const orderable = {};
3212
3431
  const all = {};
3213
- for (const [columnName, column] of Object.entries((0, import_drizzle_orm5.getColumns)(table))) {
3432
+ for (const [columnName, column] of Object.entries(visibleColumns(table))) {
3214
3433
  all[columnName] = column;
3215
3434
  const converted = drizzleColumnToGraphQLType(column, columnName, tableName, true, false, false);
3216
3435
  const gqlType = converted.type;
@@ -3454,7 +3673,7 @@ var HAVING_OPS = { eq: import_drizzle_orm5.eq, ne: import_drizzle_orm5.ne, gt: i
3454
3673
  var groupableColumns = (table, tableName) => {
3455
3674
  const { orderable } = classifyAggregateColumns(table, tableName);
3456
3675
  const groupable = { ...orderable };
3457
- for (const [columnName, column] of Object.entries((0, import_drizzle_orm5.getColumns)(table))) {
3676
+ for (const [columnName, column] of Object.entries(visibleColumns(table))) {
3458
3677
  if (groupable[columnName]) {
3459
3678
  continue;
3460
3679
  }
@@ -3922,7 +4141,8 @@ var generateSchemaData = (db, schema, relations, options) => {
3922
4141
  const { relationsDepthLimit, prefixes, suffixes, typeNameMapper, shouldEagerLoad, features, complexity, limits } = options;
3923
4142
  const rawSchema = schema;
3924
4143
  const schemaEntries = Object.entries(rawSchema);
3925
- const tableEntries = schemaEntries.filter(([_key, value]) => (0, import_drizzle_orm6.is)(value, import_mysql_core2.MySqlTable));
4144
+ const excludedTables = new Set(options.exclude?.tables ?? []);
4145
+ const tableEntries = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm6.is)(value, import_mysql_core2.MySqlTable) && !excludedTables.has(key));
3926
4146
  const tables = Object.fromEntries(tableEntries);
3927
4147
  if (!tableEntries.length) {
3928
4148
  throw new Error(
@@ -3936,7 +4156,11 @@ var generateSchemaData = (db, schema, relations, options) => {
3936
4156
  }
3937
4157
  registerScalarOverrides(tables, options);
3938
4158
  registerEnumConfig(options);
4159
+ registerColumnExclusions(tables, options.exclude);
3939
4160
  const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
4161
+ for (const excluded of excludedTables) {
4162
+ delete namedRelations[excluded];
4163
+ }
3940
4164
  attachTargetPrimaryKeys(namedRelations, tables, mysqlPrimaryKeyPropNames);
3941
4165
  const eagerRelations = pruneNonEagerRelations(namedRelations, shouldEagerLoad);
3942
4166
  const filterCtx = { tables, relationMap: namedRelations };
@@ -4404,7 +4628,7 @@ var createNestedWriteTypes = (params) => {
4404
4628
  }
4405
4629
  const omitted = plan.fkSide === "child" ? plan.foreignColPropName : void 0;
4406
4630
  const fields = Object.fromEntries(
4407
- Object.entries((0, import_drizzle_orm7.getColumns)(plan.targetTable)).filter(([columnName]) => columnName !== omitted).map(([columnName, column]) => [
4631
+ Object.entries(visibleColumns(plan.targetTable)).filter(([columnName]) => columnName !== omitted).map(([columnName, column]) => [
4408
4632
  columnName,
4409
4633
  drizzleColumnToGraphQLType(column, columnName, plan.targetTableName, false, true, true)
4410
4634
  ])
@@ -4730,11 +4954,10 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
4730
4954
  if (after != null && distinct?.length) {
4731
4955
  throw new import_graphql9.GraphQLError("'after' cannot be combined with 'distinct'.");
4732
4956
  }
4733
- if (orderByHasRelationEntry(orderBy)) {
4957
+ const cursorObstacle = orderByCursorObstacle(orderBy);
4958
+ if (cursorObstacle) {
4734
4959
  if (after != null) {
4735
- throw new import_graphql9.GraphQLError(
4736
- "'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor."
4737
- );
4960
+ throw new import_graphql9.GraphQLError(cursorObstacle);
4738
4961
  }
4739
4962
  } else if (!pkNames.length) {
4740
4963
  if (after != null) {
@@ -4782,7 +5005,7 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
4782
5005
  q = q.orderBy(...cursorOrderExprs(table, cursorEntries));
4783
5006
  } else if (orderBy) {
4784
5007
  q = q.orderBy(
4785
- ...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName)),
5008
+ ...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName), where),
4786
5009
  ...distinctKeys ? primaryKeyOrderExprs(table, pkNames) : []
4787
5010
  );
4788
5011
  } else if ((distinctKeys || offset != null || limit != null) && pkNames.length) {
@@ -4848,7 +5071,7 @@ var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filt
4848
5071
  q = q.where(extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)));
4849
5072
  }
4850
5073
  if (orderBy) {
4851
- q = q.orderBy(...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName)));
5074
+ q = q.orderBy(...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName), where));
4852
5075
  } else if (pkNames.length) {
4853
5076
  q = q.orderBy(...primaryKeyOrderExprs(table, pkNames));
4854
5077
  }
@@ -5282,7 +5505,8 @@ function generateSchemaData2(db, schema, relations, options) {
5282
5505
  limits
5283
5506
  } = options;
5284
5507
  const schemaEntries = Object.entries(schema);
5285
- const tableEntries = schemaEntries.filter(([_key, value]) => (0, import_drizzle_orm8.is)(value, import_pg_core2.PgTable));
5508
+ const excludedTables = new Set(options.exclude?.tables ?? []);
5509
+ const tableEntries = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm8.is)(value, import_pg_core2.PgTable) && !excludedTables.has(key));
5286
5510
  const tables = Object.fromEntries(tableEntries);
5287
5511
  if (!tableEntries.length) {
5288
5512
  throw new Error(
@@ -5291,7 +5515,11 @@ function generateSchemaData2(db, schema, relations, options) {
5291
5515
  }
5292
5516
  registerScalarOverrides(tables, options);
5293
5517
  registerEnumConfig(options);
5518
+ registerColumnExclusions(tables, options.exclude);
5294
5519
  const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
5520
+ for (const excluded of excludedTables) {
5521
+ delete namedRelations[excluded];
5522
+ }
5295
5523
  attachTargetPrimaryKeys(namedRelations, tables, pgPrimaryKeyPropNames);
5296
5524
  const eagerRelations = pruneNonEagerRelations(namedRelations, shouldEagerLoad);
5297
5525
  const filterCtx = { tables, relationMap: namedRelations };
@@ -6294,7 +6522,8 @@ var generateSchemaData3 = (db, schema, relations, options) => {
6294
6522
  } = options;
6295
6523
  const rawSchema = schema;
6296
6524
  const schemaEntries = Object.entries(rawSchema);
6297
- const tableEntries = schemaEntries.filter(([_key, value]) => (0, import_drizzle_orm9.is)(value, import_sqlite_core2.SQLiteTable));
6525
+ const excludedTables = new Set(options.exclude?.tables ?? []);
6526
+ const tableEntries = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm9.is)(value, import_sqlite_core2.SQLiteTable) && !excludedTables.has(key));
6298
6527
  const tables = Object.fromEntries(tableEntries);
6299
6528
  if (!tableEntries.length) {
6300
6529
  throw new Error(
@@ -6303,7 +6532,11 @@ var generateSchemaData3 = (db, schema, relations, options) => {
6303
6532
  }
6304
6533
  registerScalarOverrides(tables, options);
6305
6534
  registerEnumConfig(options);
6535
+ registerColumnExclusions(tables, options.exclude);
6306
6536
  const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
6537
+ for (const excluded of excludedTables) {
6538
+ delete namedRelations[excluded];
6539
+ }
6307
6540
  attachTargetPrimaryKeys(namedRelations, tables, sqlitePrimaryKeyPropNames);
6308
6541
  const eagerRelations = pruneNonEagerRelations(namedRelations, shouldEagerLoad);
6309
6542
  const filterCtx = { tables, relationMap: namedRelations };
@@ -6850,6 +7083,49 @@ var buildSchema = (db, config) => {
6850
7083
  limitPolicyCache.set(tableName, resolved);
6851
7084
  return resolved;
6852
7085
  } : void 0;
7086
+ const exclude = config?.exclude;
7087
+ if (exclude) {
7088
+ const tableNames = new Set(
7089
+ Object.entries(schema).filter(([, value]) => (0, import_drizzle_orm10.is)(value, import_drizzle_orm10.Table)).map(([key]) => key)
7090
+ );
7091
+ const excludedTables = new Set(exclude.tables ?? []);
7092
+ for (const tableName of excludedTables) {
7093
+ if (!tableNames.has(tableName)) {
7094
+ throw new Error(
7095
+ `Drizzle-GraphQL Error: config.exclude.tables names '${tableName}', which is not a table in the Drizzle schema.`
7096
+ );
7097
+ }
7098
+ }
7099
+ if (excludedTables.size >= tableNames.size) {
7100
+ throw new Error(
7101
+ "Drizzle-GraphQL Error: config.exclude.tables excludes every table in the schema, leaving nothing to generate."
7102
+ );
7103
+ }
7104
+ for (const [tableName, columnNames] of Object.entries(exclude.columns ?? {})) {
7105
+ if (!tableNames.has(tableName)) {
7106
+ throw new Error(
7107
+ `Drizzle-GraphQL Error: config.exclude.columns names table '${tableName}', which is not a table in the Drizzle schema.`
7108
+ );
7109
+ }
7110
+ if (excludedTables.has(tableName)) {
7111
+ continue;
7112
+ }
7113
+ const columns = (0, import_drizzle_orm10.getColumns)(schema[tableName]);
7114
+ for (const columnName of columnNames) {
7115
+ const column = columns[columnName];
7116
+ if (!column) {
7117
+ throw new Error(
7118
+ `Drizzle-GraphQL Error: config.exclude.columns names '${tableName}.${columnName}', which is not a column of that table.`
7119
+ );
7120
+ }
7121
+ if (column.notNull && !column.hasDefault && !column.defaultFn) {
7122
+ console.warn(
7123
+ `Drizzle-GraphQL Warning: excluded column '${tableName}.${columnName}' is NOT NULL with no default, so generated inserts for '${tableName}' can never succeed.`
7124
+ );
7125
+ }
7126
+ }
7127
+ }
7128
+ }
6853
7129
  const eagerOpt = config?.eagerLoadRelations;
6854
7130
  const shouldEagerLoad = eagerOpt === void 0 || eagerOpt === true ? () => true : eagerOpt === false ? () => false : eagerOpt;
6855
7131
  if (!typeNameMapper && suffixes.list === suffixes.single) {
@@ -6883,6 +7159,7 @@ var buildSchema = (db, config) => {
6883
7159
  enumNameMapper: config?.enumNameMapper,
6884
7160
  transactions,
6885
7161
  limits,
7162
+ exclude,
6886
7163
  docs: {
6887
7164
  describeColumn: config?.describeColumn,
6888
7165
  describeTable: config?.describeTable,