@vantreeseba/drizzle-graphql 7.2.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/README.md +120 -2
- package/dist/README.md +120 -2
- package/dist/index.cjs +214 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +214 -24
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -188,6 +188,12 @@ type OrderByArgs<TTable extends Table> = {
|
|
|
188
188
|
* emulated with an extra `IS NULL` sort key on MySQL.
|
|
189
189
|
*/
|
|
190
190
|
nulls?: 'first' | 'last';
|
|
191
|
+
/**
|
|
192
|
+
* Sort by the column's position in the `inArray` list the same request's `where` gives
|
|
193
|
+
* it, rather than by the column's own value. Requires that `inArray` filter; cannot be
|
|
194
|
+
* combined with `after` or `distinct`.
|
|
195
|
+
*/
|
|
196
|
+
matchFilterOrder?: boolean;
|
|
191
197
|
};
|
|
192
198
|
};
|
|
193
199
|
|
|
@@ -262,10 +268,13 @@ type LimitPolicyFor = (tableName: string) => ResolvedLimitPolicy | undefined;
|
|
|
262
268
|
* across relation boundaries. Each entry may also carry `nulls: first | last`
|
|
263
269
|
* (see {@link orderExpressions} for how MySQL emulates it).
|
|
264
270
|
*
|
|
271
|
+
* An entry may instead set `matchFilterOrder`, which sorts by the column's position in the
|
|
272
|
+
* `inArray` list the same request's `where` gives it — `whereArgs` is that `where`.
|
|
273
|
+
*
|
|
265
274
|
* `ctx` supplies the tables and relation map that relation ordering needs; callers whose
|
|
266
275
|
* inputs cannot contain relation keys may omit it.
|
|
267
276
|
*/
|
|
268
|
-
declare const extractOrderBy: <TTable extends Table, TArgs extends OrderByArgs<any> = OrderByArgs<TTable>>(table: TTable, orderArgs: TArgs, ctx?: RelationFilterContext) => SQL[];
|
|
277
|
+
declare const extractOrderBy: <TTable extends Table, TArgs extends OrderByArgs<any> = OrderByArgs<TTable>>(table: TTable, orderArgs: TArgs, ctx?: RelationFilterContext, whereArgs?: Record<string, any>) => SQL[];
|
|
269
278
|
/**
|
|
270
279
|
* Everything `extractFilters` needs to turn a relation key in a `where` argument into a
|
|
271
280
|
* correlated subquery. Omitted by callers that don't generate relation filters, in which case
|
package/dist/index.d.ts
CHANGED
|
@@ -188,6 +188,12 @@ type OrderByArgs<TTable extends Table> = {
|
|
|
188
188
|
* emulated with an extra `IS NULL` sort key on MySQL.
|
|
189
189
|
*/
|
|
190
190
|
nulls?: 'first' | 'last';
|
|
191
|
+
/**
|
|
192
|
+
* Sort by the column's position in the `inArray` list the same request's `where` gives
|
|
193
|
+
* it, rather than by the column's own value. Requires that `inArray` filter; cannot be
|
|
194
|
+
* combined with `after` or `distinct`.
|
|
195
|
+
*/
|
|
196
|
+
matchFilterOrder?: boolean;
|
|
191
197
|
};
|
|
192
198
|
};
|
|
193
199
|
|
|
@@ -262,10 +268,13 @@ type LimitPolicyFor = (tableName: string) => ResolvedLimitPolicy | undefined;
|
|
|
262
268
|
* across relation boundaries. Each entry may also carry `nulls: first | last`
|
|
263
269
|
* (see {@link orderExpressions} for how MySQL emulates it).
|
|
264
270
|
*
|
|
271
|
+
* An entry may instead set `matchFilterOrder`, which sorts by the column's position in the
|
|
272
|
+
* `inArray` list the same request's `where` gives it — `whereArgs` is that `where`.
|
|
273
|
+
*
|
|
265
274
|
* `ctx` supplies the tables and relation map that relation ordering needs; callers whose
|
|
266
275
|
* inputs cannot contain relation keys may omit it.
|
|
267
276
|
*/
|
|
268
|
-
declare const extractOrderBy: <TTable extends Table, TArgs extends OrderByArgs<any> = OrderByArgs<TTable>>(table: TTable, orderArgs: TArgs, ctx?: RelationFilterContext) => SQL[];
|
|
277
|
+
declare const extractOrderBy: <TTable extends Table, TArgs extends OrderByArgs<any> = OrderByArgs<TTable>>(table: TTable, orderArgs: TArgs, ctx?: RelationFilterContext, whereArgs?: Record<string, any>) => SQL[];
|
|
269
278
|
/**
|
|
270
279
|
* Everything `extractFilters` needs to turn a relation key in a `where` argument into a
|
|
271
280
|
* correlated subquery. Omitted by callers that don't generate relation filters, in which case
|
package/dist/index.js
CHANGED
|
@@ -1012,10 +1012,10 @@ var runMutation = async (db, context, info, txCtx, body) => {
|
|
|
1012
1012
|
}
|
|
1013
1013
|
return runOnSharedTx(state, body);
|
|
1014
1014
|
};
|
|
1015
|
-
var batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, orderCtx) => {
|
|
1015
|
+
var batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, orderCtx, whereArgs) => {
|
|
1016
1016
|
const cols = getColumns2(targetTable);
|
|
1017
1017
|
const orderExprs = [
|
|
1018
|
-
...orderByArg ? extractOrderBy(targetTable, orderByArg, orderCtx) : [],
|
|
1018
|
+
...orderByArg ? extractOrderBy(targetTable, orderByArg, orderCtx, whereArgs) : [],
|
|
1019
1019
|
...primaryKeyOrderExprs(targetTable, pkNames)
|
|
1020
1020
|
];
|
|
1021
1021
|
const orderClause = orderExprs.length ? sql2` order by ${sql2.join(orderExprs, sql2`, `)}` : sql2``;
|
|
@@ -1126,11 +1126,12 @@ var createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limits
|
|
|
1126
1126
|
limit ?? null,
|
|
1127
1127
|
offset ?? null,
|
|
1128
1128
|
targetPkNames,
|
|
1129
|
-
relationFilterCtx(filterCtx, targetTableName)
|
|
1129
|
+
relationFilterCtx(filterCtx, targetTableName),
|
|
1130
|
+
whereArg
|
|
1130
1131
|
);
|
|
1131
1132
|
} else {
|
|
1132
1133
|
let q = executor.select().from(targetTable).where(whereCondition);
|
|
1133
|
-
const orderExprs = cursorEntries ? cursorOrderExprs(targetTable, cursorEntries) : orderByArg ? extractOrderBy(targetTable, orderByArg, relationFilterCtx(filterCtx, targetTableName)) : [];
|
|
1134
|
+
const orderExprs = cursorEntries ? cursorOrderExprs(targetTable, cursorEntries) : orderByArg ? extractOrderBy(targetTable, orderByArg, relationFilterCtx(filterCtx, targetTableName), whereArg) : [];
|
|
1134
1135
|
if (orderExprs.length) {
|
|
1135
1136
|
q = q.orderBy(...orderExprs);
|
|
1136
1137
|
}
|
|
@@ -1341,6 +1342,10 @@ var innerOrder = new GraphQLInputObjectType3({
|
|
|
1341
1342
|
nulls: {
|
|
1342
1343
|
type: orderNulls,
|
|
1343
1344
|
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)"
|
|
1345
|
+
},
|
|
1346
|
+
matchFilterOrder: {
|
|
1347
|
+
type: GraphQLBoolean2,
|
|
1348
|
+
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`."
|
|
1344
1349
|
}
|
|
1345
1350
|
}
|
|
1346
1351
|
});
|
|
@@ -1406,10 +1411,59 @@ var jsonFilterFields = (column, colType) => {
|
|
|
1406
1411
|
description: "Value structurally contains this JSON (Postgres `@>` / MySQL JSON_CONTAINS)"
|
|
1407
1412
|
}
|
|
1408
1413
|
} : {},
|
|
1414
|
+
path: {
|
|
1415
|
+
type: new GraphQLList3(new GraphQLNonNull3(jsonPathFilter)),
|
|
1416
|
+
description: "Compares the value at one path inside the document. Several entries are ANDed; a single object may be passed without the list brackets."
|
|
1417
|
+
},
|
|
1409
1418
|
isNull: { type: GraphQLBoolean2 },
|
|
1410
1419
|
isNotNull: { type: GraphQLBoolean2 }
|
|
1411
1420
|
};
|
|
1412
1421
|
};
|
|
1422
|
+
var jsonPathCast = new GraphQLEnumType2({
|
|
1423
|
+
name: "JSONPathCast",
|
|
1424
|
+
description: "How to read the value at a JSON path before comparing it",
|
|
1425
|
+
values: {
|
|
1426
|
+
TEXT: { value: "text", description: "Compare as text (lexicographic ordering)" },
|
|
1427
|
+
NUMBER: { value: "number", description: "Compare as a number; a non-numeric value never matches" },
|
|
1428
|
+
BOOLEAN: { value: "boolean", description: "Compare as a boolean" }
|
|
1429
|
+
}
|
|
1430
|
+
});
|
|
1431
|
+
var jsonPathFilter = new GraphQLInputObjectType3({
|
|
1432
|
+
name: "JSONPathFilter",
|
|
1433
|
+
fields: {
|
|
1434
|
+
path: {
|
|
1435
|
+
type: new GraphQLNonNull3(new GraphQLList3(new GraphQLNonNull3(GraphQLString2))),
|
|
1436
|
+
description: 'Keys to walk from the document root, e.g. `["profile", "level"]`. An all-digits key indexes an array.'
|
|
1437
|
+
},
|
|
1438
|
+
as: { type: jsonPathCast, description: "Overrides how the value is read before comparing" },
|
|
1439
|
+
eq: { type: GraphQLJSON, description: "Equal to" },
|
|
1440
|
+
ne: { type: GraphQLJSON, description: "Not equal to" },
|
|
1441
|
+
lt: { type: GraphQLJSON, description: "Less than" },
|
|
1442
|
+
lte: { type: GraphQLJSON, description: "Less than or equal to" },
|
|
1443
|
+
gt: { type: GraphQLJSON, description: "Greater than" },
|
|
1444
|
+
gte: { type: GraphQLJSON, description: "Greater than or equal to" },
|
|
1445
|
+
startsWith: {
|
|
1446
|
+
type: GraphQLString2,
|
|
1447
|
+
description: "Extracted value starts with this string. `%`, `_` and `\\` are matched literally."
|
|
1448
|
+
},
|
|
1449
|
+
endsWith: {
|
|
1450
|
+
type: GraphQLString2,
|
|
1451
|
+
description: "Extracted value ends with this string. `%`, `_` and `\\` are matched literally."
|
|
1452
|
+
},
|
|
1453
|
+
contains: {
|
|
1454
|
+
type: GraphQLString2,
|
|
1455
|
+
description: "Extracted value contains this string. `%`, `_` and `\\` are matched literally."
|
|
1456
|
+
},
|
|
1457
|
+
iStartsWith: { type: GraphQLString2, description: "Case-insensitive `startsWith`." },
|
|
1458
|
+
iEndsWith: { type: GraphQLString2, description: "Case-insensitive `endsWith`." },
|
|
1459
|
+
iContains: { type: GraphQLString2, description: "Case-insensitive `contains`." },
|
|
1460
|
+
isNull: {
|
|
1461
|
+
type: GraphQLBoolean2,
|
|
1462
|
+
description: "When true, matches rows where the path is missing or holds JSON null"
|
|
1463
|
+
},
|
|
1464
|
+
isNotNull: { type: GraphQLBoolean2, description: "When true, matches rows where the path holds a value" }
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1413
1467
|
var IN_ARRAY_DESCRIPTION = "Matches any one of these values (SQL `IN`)";
|
|
1414
1468
|
var NOT_IN_ARRAY_DESCRIPTION = "Matches none of these values (SQL `NOT IN`)";
|
|
1415
1469
|
var arrayFilterFields = (colType, colArr) => {
|
|
@@ -2003,6 +2057,9 @@ var orderByEntries = (orderArgs) => Object.entries(orderArgs).sort((a, b) => (b[
|
|
|
2003
2057
|
if (typeof config === "object" && config.direction === void 0) {
|
|
2004
2058
|
throw new GraphQLError4(`ORDER BY ${column}: ordering through a relation is not supported in this query`);
|
|
2005
2059
|
}
|
|
2060
|
+
if (config.matchFilterOrder) {
|
|
2061
|
+
throw new GraphQLError4(`ORDER BY ${column}: 'matchFilterOrder' is not supported in this query`);
|
|
2062
|
+
}
|
|
2006
2063
|
return [column, config.direction, config.nulls ?? void 0];
|
|
2007
2064
|
});
|
|
2008
2065
|
var orderExpressions = (expr, direction, nulls, dialectColumn) => {
|
|
@@ -2037,7 +2094,22 @@ var extendRelationOrderChain = (parentTable, relationName, relEntry, ctx, chain)
|
|
|
2037
2094
|
table: aliasedTarget
|
|
2038
2095
|
};
|
|
2039
2096
|
};
|
|
2040
|
-
var
|
|
2097
|
+
var filterOrderExpression = (column, columnName, whereArgs) => {
|
|
2098
|
+
const values = whereArgs?.[columnName]?.inArray;
|
|
2099
|
+
if (!Array.isArray(values)) {
|
|
2100
|
+
throw new GraphQLError4(
|
|
2101
|
+
`ORDER BY ${columnName}: 'matchFilterOrder' needs an 'inArray' filter on the same column in this query's 'where'`
|
|
2102
|
+
);
|
|
2103
|
+
}
|
|
2104
|
+
if (!values.length) {
|
|
2105
|
+
return sql2`0`;
|
|
2106
|
+
}
|
|
2107
|
+
const branches = values.map(
|
|
2108
|
+
(value, index) => sql2`when ${column} = ${remapFromGraphQLCore(value, column, columnName)} then ${sql2.raw(String(index))}`
|
|
2109
|
+
);
|
|
2110
|
+
return sql2`case ${sql2.join(branches, sql2` `)} else ${sql2.raw(String(values.length))} end`;
|
|
2111
|
+
};
|
|
2112
|
+
var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out, whereArgs) => {
|
|
2041
2113
|
const columns = getColumns2(table);
|
|
2042
2114
|
const relations = ctx?.relationMap[tableKey];
|
|
2043
2115
|
for (const [key, config] of Object.entries(orderArgs)) {
|
|
@@ -2046,8 +2118,11 @@ var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out) => {
|
|
|
2046
2118
|
}
|
|
2047
2119
|
const column = columns[key];
|
|
2048
2120
|
if (column) {
|
|
2121
|
+
if (config.matchFilterOrder && chain) {
|
|
2122
|
+
throw new GraphQLError4(`ORDER BY ${key}: 'matchFilterOrder' is not supported through a relation`);
|
|
2123
|
+
}
|
|
2049
2124
|
out.push({
|
|
2050
|
-
expression: chain ? sql2`(select ${column} from ${sql2.join(chain.fromParts, sql2`, `)} where ${and(...chain.conditions)})` : column,
|
|
2125
|
+
expression: config.matchFilterOrder ? filterOrderExpression(column, key, whereArgs) : chain ? sql2`(select ${column} from ${sql2.join(chain.fromParts, sql2`, `)} where ${and(...chain.conditions)})` : column,
|
|
2051
2126
|
column,
|
|
2052
2127
|
direction: config.direction,
|
|
2053
2128
|
nulls: config.nulls ?? void 0,
|
|
@@ -2060,12 +2135,12 @@ var collectOrderEntries = (table, tableKey, orderArgs, ctx, chain, out) => {
|
|
|
2060
2135
|
throw new GraphQLError4(`ORDER BY ${key}: Unknown column or relation`);
|
|
2061
2136
|
}
|
|
2062
2137
|
const nextChain = extendRelationOrderChain(chain?.table ?? table, key, relEntry, ctx, chain);
|
|
2063
|
-
collectOrderEntries(nextChain.table, relEntry.targetTableName, config, ctx, nextChain, out);
|
|
2138
|
+
collectOrderEntries(nextChain.table, relEntry.targetTableName, config, ctx, nextChain, out, void 0);
|
|
2064
2139
|
}
|
|
2065
2140
|
};
|
|
2066
|
-
var extractOrderBy = (table, orderArgs, ctx) => {
|
|
2141
|
+
var extractOrderBy = (table, orderArgs, ctx, whereArgs) => {
|
|
2067
2142
|
const entries = [];
|
|
2068
|
-
collectOrderEntries(table, ctx?.tableKey ?? "", orderArgs, ctx, void 0, entries);
|
|
2143
|
+
collectOrderEntries(table, ctx?.tableKey ?? "", orderArgs, ctx, void 0, entries, whereArgs);
|
|
2069
2144
|
return entries.sort((a, b) => b.priority - a.priority).flatMap((entry) => orderExpressions(entry.expression, entry.direction, entry.nulls, entry.column));
|
|
2070
2145
|
};
|
|
2071
2146
|
var LIKE_ESCAPE_CHAR = "\\";
|
|
@@ -2097,6 +2172,105 @@ var jsonContains = (column, columnName, value) => {
|
|
|
2097
2172
|
throw new GraphQLError4(`WHERE ${columnName}: Operator 'contains' is not supported for this dialect!`);
|
|
2098
2173
|
}
|
|
2099
2174
|
};
|
|
2175
|
+
var sqlFalse = () => sql2`1 = 0`;
|
|
2176
|
+
var sqlTrue = () => sql2`1 = 1`;
|
|
2177
|
+
var jsonPathString = (path) => `$${path.map((part) => /^\d+$/.test(part) ? `[${part}]` : `."${part.replace(/(["\\])/g, "\\$1")}"`).join("")}`;
|
|
2178
|
+
var NUMERIC_TEXT_PATTERN = "^\\s*-?(\\d+\\.?\\d*|\\.\\d+)([eE][-+]?\\d+)?\\s*$";
|
|
2179
|
+
var jsonPathExprs = (column, path) => {
|
|
2180
|
+
switch (columnDialect(column)) {
|
|
2181
|
+
case "pg": {
|
|
2182
|
+
const pathArray = sql2`array[${sql2.join(
|
|
2183
|
+
path.map((part) => sql2`${part}`),
|
|
2184
|
+
sql2`, `
|
|
2185
|
+
)}]::text[]`;
|
|
2186
|
+
const text = sql2`(${column} #>> ${pathArray})`;
|
|
2187
|
+
return {
|
|
2188
|
+
text,
|
|
2189
|
+
number: sql2`(case when ${text} ~ ${NUMERIC_TEXT_PATTERN} then ${text}::numeric end)`,
|
|
2190
|
+
boolean: text,
|
|
2191
|
+
encodeBoolean: (value) => String(value)
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
case "mysql": {
|
|
2195
|
+
const extracted = sql2`json_extract(${column}, ${jsonPathString(path)})`;
|
|
2196
|
+
const text = sql2`(case when json_type(${extracted}) = 'NULL' then null else json_unquote(${extracted}) end)`;
|
|
2197
|
+
return {
|
|
2198
|
+
text,
|
|
2199
|
+
number: sql2`(case when ${text} regexp ${NUMERIC_TEXT_PATTERN} then cast(${text} as decimal(65, 30)) end)`,
|
|
2200
|
+
boolean: text,
|
|
2201
|
+
encodeBoolean: (value) => String(value)
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
default: {
|
|
2205
|
+
const extracted = sql2`json_extract(${column}, ${jsonPathString(path)})`;
|
|
2206
|
+
return {
|
|
2207
|
+
text: sql2`cast(${extracted} as text)`,
|
|
2208
|
+
number: sql2`(case when typeof(${extracted}) in ('integer', 'real') then ${extracted} end)`,
|
|
2209
|
+
// SQLite has no boolean type: a JSON `true` comes back as the integer 1.
|
|
2210
|
+
boolean: extracted,
|
|
2211
|
+
encodeBoolean: (value) => value ? 1 : 0
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
var JSON_PATH_COMPARISONS = {
|
|
2217
|
+
eq: "=",
|
|
2218
|
+
ne: "<>",
|
|
2219
|
+
lt: "<",
|
|
2220
|
+
lte: "<=",
|
|
2221
|
+
gt: ">",
|
|
2222
|
+
gte: ">="
|
|
2223
|
+
};
|
|
2224
|
+
var inferJsonPathCast = (value) => typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "text";
|
|
2225
|
+
var jsonPathCondition = (column, columnName, filter) => {
|
|
2226
|
+
const { path, as: castOverride, ...operators } = filter;
|
|
2227
|
+
const locator = `${columnName}.path`;
|
|
2228
|
+
if (!Array.isArray(path) || !path.length) {
|
|
2229
|
+
throw new GraphQLError4(`WHERE ${locator}: 'path' must name at least one key`);
|
|
2230
|
+
}
|
|
2231
|
+
const exprs = jsonPathExprs(column, path);
|
|
2232
|
+
const variants = [];
|
|
2233
|
+
for (const [operatorName, operatorValue] of Object.entries(operators)) {
|
|
2234
|
+
if (operatorValue === null || operatorValue === void 0) {
|
|
2235
|
+
continue;
|
|
2236
|
+
}
|
|
2237
|
+
if (operatorName === "isNull" || operatorName === "isNotNull") {
|
|
2238
|
+
if (operatorValue === false) {
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
variants.push(operatorName === "isNull" ? sql2`${exprs.text} is null` : sql2`${exprs.text} is not null`);
|
|
2242
|
+
continue;
|
|
2243
|
+
}
|
|
2244
|
+
if (operatorName in safeLikeOps) {
|
|
2245
|
+
const { buildPattern, insensitive } = safeLikeOps[operatorName];
|
|
2246
|
+
if (typeof operatorValue !== "string") {
|
|
2247
|
+
throw new GraphQLError4(`WHERE ${locator}: operator '${operatorName}' takes a string`);
|
|
2248
|
+
}
|
|
2249
|
+
variants.push(safeLikeCondition(exprs.text, buildPattern(operatorValue), insensitive));
|
|
2250
|
+
continue;
|
|
2251
|
+
}
|
|
2252
|
+
const comparison = JSON_PATH_COMPARISONS[operatorName];
|
|
2253
|
+
if (!comparison) {
|
|
2254
|
+
throw new GraphQLError4(`WHERE ${locator}: Unknown operator: ${operatorName}`);
|
|
2255
|
+
}
|
|
2256
|
+
const cast = castOverride ?? inferJsonPathCast(operatorValue);
|
|
2257
|
+
if (cast === "number") {
|
|
2258
|
+
const numeric = Number(operatorValue);
|
|
2259
|
+
if (Number.isNaN(numeric)) {
|
|
2260
|
+
throw new GraphQLError4(
|
|
2261
|
+
`WHERE ${locator}: operator '${operatorName}' compares as a number, so its value must be one`
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2264
|
+
variants.push(sql2`${exprs.number} ${sql2.raw(comparison)} ${numeric}`);
|
|
2265
|
+
} else if (cast === "boolean") {
|
|
2266
|
+
const truthy = operatorValue === true || operatorValue === "true";
|
|
2267
|
+
variants.push(sql2`${exprs.boolean} ${sql2.raw(comparison)} ${exprs.encodeBoolean(truthy)}`);
|
|
2268
|
+
} else {
|
|
2269
|
+
variants.push(sql2`${exprs.text} ${sql2.raw(comparison)} ${String(operatorValue)}`);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
return variants.length ? variants.length > 1 ? and(...variants) : variants[0] : void 0;
|
|
2273
|
+
};
|
|
2100
2274
|
var extractFiltersColumn = (column, columnName, operators) => {
|
|
2101
2275
|
const { OR, AND, NOT, ...restOperators } = operators;
|
|
2102
2276
|
const entries = Object.entries(restOperators);
|
|
@@ -2118,6 +2292,13 @@ var extractFiltersColumn = (column, columnName, operators) => {
|
|
|
2118
2292
|
variants.push(singleValueOps[operatorName](column, singleValue));
|
|
2119
2293
|
} else if (operatorName in stringValueOps) {
|
|
2120
2294
|
variants.push(stringValueOps[operatorName](column, operatorValue));
|
|
2295
|
+
} else if (operatorName === "path" && isJsonColumn2(column)) {
|
|
2296
|
+
for (const pathFilter of operatorValue) {
|
|
2297
|
+
const extracted = jsonPathCondition(column, columnName, pathFilter);
|
|
2298
|
+
if (extracted) {
|
|
2299
|
+
variants.push(extracted);
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2121
2302
|
} else if (operatorName === "contains" && isJsonColumn2(column)) {
|
|
2122
2303
|
variants.push(jsonContains(column, columnName, operatorValue));
|
|
2123
2304
|
} else if (operatorName in safeLikeOps) {
|
|
@@ -2125,7 +2306,8 @@ var extractFiltersColumn = (column, columnName, operators) => {
|
|
|
2125
2306
|
variants.push(safeLikeCondition(column, buildPattern(operatorValue), insensitive));
|
|
2126
2307
|
} else if (operatorName in arrayValueOps) {
|
|
2127
2308
|
if (!operatorValue.length) {
|
|
2128
|
-
|
|
2309
|
+
variants.push(operatorName === "inArray" ? sqlFalse() : sqlTrue());
|
|
2310
|
+
continue;
|
|
2129
2311
|
}
|
|
2130
2312
|
const arrayValue = operatorValue.map((val) => remapFromGraphQLCore(val, column, columnName));
|
|
2131
2313
|
variants.push(arrayValueOps[operatorName](column, arrayValue));
|
|
@@ -2133,7 +2315,8 @@ var extractFiltersColumn = (column, columnName, operators) => {
|
|
|
2133
2315
|
variants.push(arrayContains(column, [operatorValue]));
|
|
2134
2316
|
} else if (operatorName in arrayMembershipOps) {
|
|
2135
2317
|
if (!operatorValue.length) {
|
|
2136
|
-
|
|
2318
|
+
variants.push(operatorName === "hasSome" ? sqlFalse() : sqlTrue());
|
|
2319
|
+
continue;
|
|
2137
2320
|
}
|
|
2138
2321
|
variants.push(arrayMembershipOps[operatorName](column, operatorValue));
|
|
2139
2322
|
} else if (operatorName === "isEmpty") {
|
|
@@ -2396,7 +2579,7 @@ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, ori
|
|
|
2396
2579
|
} : void 0;
|
|
2397
2580
|
const hasPagination = offset != null || limit != null;
|
|
2398
2581
|
const pkNames = targetPkNames ?? [];
|
|
2399
|
-
thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName)) : hasPagination && pkNames.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0;
|
|
2582
|
+
thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName), relWhere) : hasPagination && pkNames.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0;
|
|
2400
2583
|
thisRecord.offset = offset;
|
|
2401
2584
|
thisRecord.limit = limit;
|
|
2402
2585
|
const relWith = relationField ? extractRelationsParamsInner(
|
|
@@ -2476,6 +2659,15 @@ var primaryKeyOrderExprs = (table, pkNames) => {
|
|
|
2476
2659
|
var CURSOR_FIELD_NAME = "cursor";
|
|
2477
2660
|
var ROW_CURSOR_PROP = "__drizzle_graphql_cursor";
|
|
2478
2661
|
var orderByHasRelationEntry = (orderBy) => !!orderBy && Object.values(orderBy).some((config) => config && typeof config === "object" && config.direction === void 0);
|
|
2662
|
+
var orderByCursorObstacle = (orderBy) => {
|
|
2663
|
+
if (orderByHasRelationEntry(orderBy)) {
|
|
2664
|
+
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.";
|
|
2665
|
+
}
|
|
2666
|
+
if (orderBy && Object.values(orderBy).some((config) => config && typeof config === "object" && config.matchFilterOrder)) {
|
|
2667
|
+
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.";
|
|
2668
|
+
}
|
|
2669
|
+
return void 0;
|
|
2670
|
+
};
|
|
2479
2671
|
var cursorOrderingEntries = (orderBy, pkNames) => {
|
|
2480
2672
|
const entries = orderBy ? orderByEntries(orderBy) : [];
|
|
2481
2673
|
const seen = new Set(entries.map(([column]) => column));
|
|
@@ -3072,11 +3264,10 @@ var runRelationalSelect = async (opts) => {
|
|
|
3072
3264
|
if (after != null && distinct) {
|
|
3073
3265
|
throw new GraphQLError4("'after' cannot be combined with 'distinct'.");
|
|
3074
3266
|
}
|
|
3075
|
-
|
|
3267
|
+
const cursorObstacle = orderByCursorObstacle(orderBy);
|
|
3268
|
+
if (cursorObstacle) {
|
|
3076
3269
|
if (after != null) {
|
|
3077
|
-
throw new GraphQLError4(
|
|
3078
|
-
"'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor."
|
|
3079
|
-
);
|
|
3270
|
+
throw new GraphQLError4(cursorObstacle);
|
|
3080
3271
|
}
|
|
3081
3272
|
} else if (!pkNames?.length) {
|
|
3082
3273
|
if (after != null) {
|
|
@@ -3116,13 +3307,13 @@ var runRelationalSelect = async (opts) => {
|
|
|
3116
3307
|
// drizzle-orm v1 RQB calls orderBy/where with the aliased table proxy — use it
|
|
3117
3308
|
// directly so column refs match the CTE alias.
|
|
3118
3309
|
orderBy: distinctKeys ? (aliasedTable2) => [
|
|
3119
|
-
...orderBy ? extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName)) : [],
|
|
3310
|
+
...orderBy ? extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName), where) : [],
|
|
3120
3311
|
...primaryKeyOrderExprs(aliasedTable2, pkNames)
|
|
3121
3312
|
] : cursorEntries ? (
|
|
3122
3313
|
// Cursor pagination needs a total order: the request's orderBy plus the PK tiebreak,
|
|
3123
3314
|
// exactly the ordering the cursor encodes and the keyset predicate compares against.
|
|
3124
3315
|
(aliasedTable2) => cursorOrderExprs(aliasedTable2, cursorEntries)
|
|
3125
|
-
) : orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName)) : needsDefaultOrder && pkNames?.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0,
|
|
3316
|
+
) : orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName), where) : needsDefaultOrder && pkNames?.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0,
|
|
3126
3317
|
where: distinctKeys ? { RAW: (aliasedTable2) => primaryKeyRestriction(aliasedTable2, pkNames, distinctKeys) } : where || cursorValues ? {
|
|
3127
3318
|
RAW: (aliasedTable2) => and(
|
|
3128
3319
|
where ? extractFilters(aliasedTable2, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0,
|
|
@@ -4822,11 +5013,10 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
|
|
|
4822
5013
|
if (after != null && distinct?.length) {
|
|
4823
5014
|
throw new GraphQLError8("'after' cannot be combined with 'distinct'.");
|
|
4824
5015
|
}
|
|
4825
|
-
|
|
5016
|
+
const cursorObstacle = orderByCursorObstacle(orderBy);
|
|
5017
|
+
if (cursorObstacle) {
|
|
4826
5018
|
if (after != null) {
|
|
4827
|
-
throw new GraphQLError8(
|
|
4828
|
-
"'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor."
|
|
4829
|
-
);
|
|
5019
|
+
throw new GraphQLError8(cursorObstacle);
|
|
4830
5020
|
}
|
|
4831
5021
|
} else if (!pkNames.length) {
|
|
4832
5022
|
if (after != null) {
|
|
@@ -4874,7 +5064,7 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
|
|
|
4874
5064
|
q = q.orderBy(...cursorOrderExprs(table, cursorEntries));
|
|
4875
5065
|
} else if (orderBy) {
|
|
4876
5066
|
q = q.orderBy(
|
|
4877
|
-
...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName)),
|
|
5067
|
+
...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName), where),
|
|
4878
5068
|
...distinctKeys ? primaryKeyOrderExprs(table, pkNames) : []
|
|
4879
5069
|
);
|
|
4880
5070
|
} else if ((distinctKeys || offset != null || limit != null) && pkNames.length) {
|
|
@@ -4940,7 +5130,7 @@ var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filt
|
|
|
4940
5130
|
q = q.where(extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)));
|
|
4941
5131
|
}
|
|
4942
5132
|
if (orderBy) {
|
|
4943
|
-
q = q.orderBy(...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName)));
|
|
5133
|
+
q = q.orderBy(...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName), where));
|
|
4944
5134
|
} else if (pkNames.length) {
|
|
4945
5135
|
q = q.orderBy(...primaryKeyOrderExprs(table, pkNames));
|
|
4946
5136
|
}
|