@vantreeseba/drizzle-graphql 5.2.0 → 5.4.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 +47 -0
- package/dist/README.md +47 -0
- package/dist/index.cjs +493 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +494 -12
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1013,6 +1013,13 @@ var generateTableSelectTypeFieldsCached = (table, tableName) => {
|
|
|
1013
1013
|
drizzleColumnToGraphQLType(columnDescription, columnName, tableName)
|
|
1014
1014
|
])
|
|
1015
1015
|
);
|
|
1016
|
+
if (!remapped[CURSOR_FIELD_NAME]) {
|
|
1017
|
+
remapped[CURSOR_FIELD_NAME] = {
|
|
1018
|
+
type: import_graphql4.GraphQLString,
|
|
1019
|
+
description: "Opaque cursor of this row's position in the query's ordering. Pass it as `after` to resume from here. Only set on rows returned by a list query.",
|
|
1020
|
+
resolve: rowCursorResolver
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1016
1023
|
fieldMap.set(table, remapped);
|
|
1017
1024
|
return remapped;
|
|
1018
1025
|
};
|
|
@@ -1840,6 +1847,117 @@ var primaryKeyOrderExprs = (table, pkNames) => {
|
|
|
1840
1847
|
const cols = (0, import_drizzle_orm3.getColumns)(table);
|
|
1841
1848
|
return pkNames.map((n) => cols[n]).filter(Boolean).map((col) => (0, import_drizzle_orm3.asc)(col));
|
|
1842
1849
|
};
|
|
1850
|
+
var CURSOR_FIELD_NAME = "cursor";
|
|
1851
|
+
var ROW_CURSOR_PROP = "__drizzle_graphql_cursor";
|
|
1852
|
+
var orderByHasRelationEntry = (orderBy) => !!orderBy && Object.values(orderBy).some((config) => config && typeof config === "object" && config.direction === void 0);
|
|
1853
|
+
var cursorOrderingEntries = (orderBy, pkNames) => {
|
|
1854
|
+
const entries = orderBy ? orderByEntries(orderBy) : [];
|
|
1855
|
+
const seen = new Set(entries.map(([column]) => column));
|
|
1856
|
+
for (const pk of pkNames) {
|
|
1857
|
+
if (!seen.has(pk)) {
|
|
1858
|
+
entries.push([pk, "asc"]);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
return entries;
|
|
1862
|
+
};
|
|
1863
|
+
var cursorOrderExprs = (table, entries) => {
|
|
1864
|
+
const cols = (0, import_drizzle_orm3.getColumns)(table);
|
|
1865
|
+
return entries.flatMap(
|
|
1866
|
+
([column, direction, nulls]) => orderExpressions(cols[column], direction, nulls ?? void 0, cols[column])
|
|
1867
|
+
);
|
|
1868
|
+
};
|
|
1869
|
+
var encodeCursorValue = (value) => {
|
|
1870
|
+
if (value instanceof Date) {
|
|
1871
|
+
return { $type: "date", value: value.toISOString() };
|
|
1872
|
+
}
|
|
1873
|
+
if (typeof value === "bigint") {
|
|
1874
|
+
return { $type: "bigint", value: value.toString() };
|
|
1875
|
+
}
|
|
1876
|
+
return value;
|
|
1877
|
+
};
|
|
1878
|
+
var decodeCursorValue = (value) => {
|
|
1879
|
+
if (value && typeof value === "object" && typeof value.$type === "string") {
|
|
1880
|
+
if (value.$type === "date") {
|
|
1881
|
+
return new Date(value.value);
|
|
1882
|
+
}
|
|
1883
|
+
if (value.$type === "bigint") {
|
|
1884
|
+
return BigInt(value.value);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
return value;
|
|
1888
|
+
};
|
|
1889
|
+
var encodeCursor = (entries, row) => {
|
|
1890
|
+
const payload = {
|
|
1891
|
+
o: entries,
|
|
1892
|
+
v: entries.map(([column]) => encodeCursorValue(row[column] ?? null))
|
|
1893
|
+
};
|
|
1894
|
+
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
1895
|
+
};
|
|
1896
|
+
var decodeCursor = (after, entries) => {
|
|
1897
|
+
let payload;
|
|
1898
|
+
try {
|
|
1899
|
+
payload = JSON.parse(Buffer.from(after, "base64url").toString("utf8"));
|
|
1900
|
+
} catch (_e) {
|
|
1901
|
+
throw new import_graphql4.GraphQLError("Invalid cursor: unable to decode it. Pass a cursor returned by a previous page.");
|
|
1902
|
+
}
|
|
1903
|
+
if (!payload || typeof payload !== "object" || !Array.isArray(payload.o) || !Array.isArray(payload.v) || payload.o.length !== payload.v.length) {
|
|
1904
|
+
throw new import_graphql4.GraphQLError("Invalid cursor: malformed payload. Pass a cursor returned by a previous page.");
|
|
1905
|
+
}
|
|
1906
|
+
const matchesOrdering = payload.o.length === entries.length && payload.o.every(
|
|
1907
|
+
(entry, i) => Array.isArray(entry) && entry[0] === entries[i][0] && entry[1] === entries[i][1] && // The nulls override changes where NULLs sort, so it is part of the ordering identity.
|
|
1908
|
+
// JSON round-trips undefined as null — compare the normalized forms.
|
|
1909
|
+
(entry[2] ?? null) === (entries[i][2] ?? null)
|
|
1910
|
+
);
|
|
1911
|
+
if (!matchesOrdering) {
|
|
1912
|
+
throw new import_graphql4.GraphQLError(
|
|
1913
|
+
"Invalid cursor: it was issued for a different ordering. Pass the same orderBy the cursor's page used."
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
return payload.v.map(decodeCursorValue);
|
|
1917
|
+
};
|
|
1918
|
+
var buildCursorCondition = (table, entries, values, nullOrdering) => {
|
|
1919
|
+
const cols = (0, import_drizzle_orm3.getColumns)(table);
|
|
1920
|
+
const disjuncts = [];
|
|
1921
|
+
const equalities = [];
|
|
1922
|
+
entries.forEach(([column, direction, nulls], i) => {
|
|
1923
|
+
const col = cols[column];
|
|
1924
|
+
if (!col) {
|
|
1925
|
+
throw new import_graphql4.GraphQLError(`Invalid cursor: unknown column '${column}'.`);
|
|
1926
|
+
}
|
|
1927
|
+
const value = values[i];
|
|
1928
|
+
const nullsSortLast = nulls != null ? nulls === "last" : direction === "asc" === (nullOrdering === "nulls-largest");
|
|
1929
|
+
let strictlyAfter;
|
|
1930
|
+
if (value === null || value === void 0) {
|
|
1931
|
+
strictlyAfter = nullsSortLast ? void 0 : (0, import_drizzle_orm3.isNotNull)(col);
|
|
1932
|
+
} else {
|
|
1933
|
+
const comparison = direction === "asc" ? (0, import_drizzle_orm3.gt)(col, value) : (0, import_drizzle_orm3.lt)(col, value);
|
|
1934
|
+
strictlyAfter = nullsSortLast ? (0, import_drizzle_orm3.or)(comparison, (0, import_drizzle_orm3.isNull)(col)) : comparison;
|
|
1935
|
+
}
|
|
1936
|
+
if (strictlyAfter) {
|
|
1937
|
+
disjuncts.push(equalities.length ? (0, import_drizzle_orm3.and)(...equalities, strictlyAfter) : strictlyAfter);
|
|
1938
|
+
}
|
|
1939
|
+
equalities.push(value === null || value === void 0 ? (0, import_drizzle_orm3.isNull)(col) : (0, import_drizzle_orm3.eq)(col, value));
|
|
1940
|
+
});
|
|
1941
|
+
if (!disjuncts.length) {
|
|
1942
|
+
return import_drizzle_orm3.sql`1 = 0`;
|
|
1943
|
+
}
|
|
1944
|
+
return disjuncts.length > 1 ? (0, import_drizzle_orm3.or)(...disjuncts) : disjuncts[0];
|
|
1945
|
+
};
|
|
1946
|
+
var isCursorFieldSelected = (tree, table) => {
|
|
1947
|
+
if (!tree) {
|
|
1948
|
+
return false;
|
|
1949
|
+
}
|
|
1950
|
+
if ((0, import_drizzle_orm3.getColumns)(table)[CURSOR_FIELD_NAME]) {
|
|
1951
|
+
return false;
|
|
1952
|
+
}
|
|
1953
|
+
return Object.values(tree).some((field) => field.name === CURSOR_FIELD_NAME);
|
|
1954
|
+
};
|
|
1955
|
+
var attachRowCursors = (rows, entries) => {
|
|
1956
|
+
for (const row of rows) {
|
|
1957
|
+
row[ROW_CURSOR_PROP] = encodeCursor(entries, row);
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1960
|
+
var rowCursorResolver = (source) => source?.[ROW_CURSOR_PROP] ?? null;
|
|
1843
1961
|
var getUniqueColumnSets = (table, getTableConfig4) => {
|
|
1844
1962
|
const cols = (0, import_drizzle_orm3.getColumns)(table);
|
|
1845
1963
|
const propNameByColumnName = new Map(Object.entries(cols).map(([propName, col]) => [col.name, propName]));
|
|
@@ -2126,6 +2244,7 @@ var computeResolverFieldNames = (tableName, typeNameMapper, prefixes, suffixes)
|
|
|
2126
2244
|
const upsertArrayFieldName = `${upsertPrefix}${mapped ? capitalize(mapped.plural) : capitalize(tableName)}`;
|
|
2127
2245
|
const upsertSingleFieldName = mapped ? `${upsertPrefix}${capitalize(mapped.singular)}` : `${upsertPrefix}${capitalize(tableName)}${suffixes.single}`;
|
|
2128
2246
|
const updateFieldName = `${prefixes.update}${mapped ? capitalize(mapped.singular) : capitalize(tableName)}`;
|
|
2247
|
+
const updateManyFieldName = `${prefixes.update}${mapped ? capitalize(mapped.plural) : capitalize(tableName)}Many`;
|
|
2129
2248
|
const deleteFieldName = `${prefixes.delete}${mapped ? capitalize(mapped.singular) : capitalize(tableName)}`;
|
|
2130
2249
|
const writeSingleSuffix = suffixes.single === "" ? "Single" : suffixes.single;
|
|
2131
2250
|
const updateSingleFieldName = `${updateFieldName}${writeSingleSuffix}`;
|
|
@@ -2141,11 +2260,28 @@ var computeResolverFieldNames = (tableName, typeNameMapper, prefixes, suffixes)
|
|
|
2141
2260
|
upsertArrayFieldName,
|
|
2142
2261
|
upsertSingleFieldName,
|
|
2143
2262
|
updateFieldName,
|
|
2263
|
+
updateManyFieldName,
|
|
2144
2264
|
updateSingleFieldName,
|
|
2145
2265
|
deleteFieldName,
|
|
2146
2266
|
deleteSingleFieldName
|
|
2147
2267
|
};
|
|
2148
2268
|
};
|
|
2269
|
+
var generateUpdateManyInput = (params) => {
|
|
2270
|
+
const { typeName, updatePrefix, updateInput, tableFilters } = params;
|
|
2271
|
+
return new import_graphql4.GraphQLInputObjectType({
|
|
2272
|
+
name: `${capitalize(updatePrefix)}${typeName}ManyInput`,
|
|
2273
|
+
description: `One entry of a batch update of ${typeName}: the rows \`where\` matches get this entry's \`set\` applied.`,
|
|
2274
|
+
fields: {
|
|
2275
|
+
where: {
|
|
2276
|
+
type: tableFilters,
|
|
2277
|
+
description: "Rows this entry updates. An omitted filter updates every row."
|
|
2278
|
+
},
|
|
2279
|
+
set: {
|
|
2280
|
+
type: new import_graphql4.GraphQLNonNull(updateInput)
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2284
|
+
};
|
|
2149
2285
|
var extractRequiredFilters = (table, tableName, where, fieldName, relationCtx) => {
|
|
2150
2286
|
const filters = where ? extractFilters(table, tableName, where, relationCtx) : void 0;
|
|
2151
2287
|
if (!filters) {
|
|
@@ -2164,6 +2300,10 @@ var selectArrayArgs = (orderArgs, filterArgs, distinctEnum) => ({
|
|
|
2164
2300
|
limit: { type: import_graphql4.GraphQLInt },
|
|
2165
2301
|
orderBy: { type: orderArgs },
|
|
2166
2302
|
where: { type: filterArgs },
|
|
2303
|
+
after: {
|
|
2304
|
+
type: import_graphql4.GraphQLString,
|
|
2305
|
+
description: "Keyset pagination: only return rows strictly after this cursor (a row's `cursor` field from a previous page, under the same orderBy)."
|
|
2306
|
+
},
|
|
2167
2307
|
...distinctEnum ? { distinct: { type: new import_graphql4.GraphQLList(new import_graphql4.GraphQLNonNull(distinctEnum)) } } : {}
|
|
2168
2308
|
});
|
|
2169
2309
|
var selectSingleArgs = (orderArgs, filterArgs) => ({
|
|
@@ -2186,9 +2326,31 @@ var runRelationalSelect = async (opts) => {
|
|
|
2186
2326
|
where,
|
|
2187
2327
|
single,
|
|
2188
2328
|
filterCtx,
|
|
2189
|
-
pkNames
|
|
2329
|
+
pkNames,
|
|
2330
|
+
after
|
|
2190
2331
|
} = opts;
|
|
2191
2332
|
const distinct = opts.distinct?.length ? opts.distinct : void 0;
|
|
2333
|
+
const cursorSelected = !single && isCursorFieldSelected(parsedInfo.fieldsByTypeName[typeName], table);
|
|
2334
|
+
let cursorEntries;
|
|
2335
|
+
if (!single && (after != null || cursorSelected)) {
|
|
2336
|
+
if (after != null && distinct) {
|
|
2337
|
+
throw new import_graphql4.GraphQLError("'after' cannot be combined with 'distinct'.");
|
|
2338
|
+
}
|
|
2339
|
+
if (orderByHasRelationEntry(orderBy)) {
|
|
2340
|
+
if (after != null) {
|
|
2341
|
+
throw new import_graphql4.GraphQLError(
|
|
2342
|
+
"'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor."
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
} else if (!pkNames?.length) {
|
|
2346
|
+
if (after != null) {
|
|
2347
|
+
throw new import_graphql4.GraphQLError(`Table ${tableName} has no primary key, so cursor pagination cannot be used on it.`);
|
|
2348
|
+
}
|
|
2349
|
+
} else {
|
|
2350
|
+
cursorEntries = cursorOrderingEntries(orderBy, pkNames);
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
const cursorValues = after != null && cursorEntries ? decodeCursor(after, cursorEntries) : void 0;
|
|
2192
2354
|
const needsDefaultOrder = single || offset != null || opts.limit != null;
|
|
2193
2355
|
let distinctKeys;
|
|
2194
2356
|
if (distinct) {
|
|
@@ -2219,9 +2381,21 @@ var runRelationalSelect = async (opts) => {
|
|
|
2219
2381
|
orderBy: distinctKeys ? (aliasedTable2) => [
|
|
2220
2382
|
...orderBy ? extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName)) : [],
|
|
2221
2383
|
...primaryKeyOrderExprs(aliasedTable2, pkNames)
|
|
2222
|
-
] :
|
|
2223
|
-
|
|
2224
|
-
|
|
2384
|
+
] : cursorEntries ? (
|
|
2385
|
+
// Cursor pagination needs a total order: the request's orderBy plus the PK tiebreak,
|
|
2386
|
+
// exactly the ordering the cursor encodes and the keyset predicate compares against.
|
|
2387
|
+
(aliasedTable2) => cursorOrderExprs(aliasedTable2, cursorEntries)
|
|
2388
|
+
) : orderBy ? (aliasedTable2) => extractOrderBy(aliasedTable2, orderBy, relationFilterCtx(filterCtx, tableName)) : needsDefaultOrder && pkNames?.length ? (aliasedTable2) => primaryKeyOrderExprs(aliasedTable2, pkNames) : void 0,
|
|
2389
|
+
where: distinctKeys ? { RAW: (aliasedTable2) => primaryKeyRestriction(aliasedTable2, pkNames, distinctKeys) } : where || cursorValues ? {
|
|
2390
|
+
RAW: (aliasedTable2) => (0, import_drizzle_orm3.and)(
|
|
2391
|
+
where ? extractFilters(aliasedTable2, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0,
|
|
2392
|
+
cursorValues ? buildCursorCondition(
|
|
2393
|
+
aliasedTable2,
|
|
2394
|
+
cursorEntries,
|
|
2395
|
+
cursorValues,
|
|
2396
|
+
opts.nullOrdering ?? "nulls-smallest"
|
|
2397
|
+
) : void 0
|
|
2398
|
+
)
|
|
2225
2399
|
} : void 0,
|
|
2226
2400
|
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, typeNameMapper, filterCtx) : void 0
|
|
2227
2401
|
};
|
|
@@ -2229,8 +2403,16 @@ var runRelationalSelect = async (opts) => {
|
|
|
2229
2403
|
const result2 = await queryBase.findFirst(params);
|
|
2230
2404
|
return result2 ? remapToGraphQLSingleOutput(result2, tableName, table, relationMap) : void 0;
|
|
2231
2405
|
}
|
|
2406
|
+
if (cursorEntries && cursorSelected) {
|
|
2407
|
+
for (const [column] of cursorEntries) {
|
|
2408
|
+
params.columns[column] = true;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2232
2411
|
params.limit = distinctKeys ? void 0 : opts.limit;
|
|
2233
2412
|
const result = await queryBase.findMany(params);
|
|
2413
|
+
if (cursorEntries && cursorSelected) {
|
|
2414
|
+
attachRowCursors(result, cursorEntries);
|
|
2415
|
+
}
|
|
2234
2416
|
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
|
|
2235
2417
|
};
|
|
2236
2418
|
var eagerLoadMutationRelations = async (db, tableName, rows, pkNames, withParams) => {
|
|
@@ -2778,7 +2960,9 @@ var generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filter
|
|
|
2778
2960
|
single: false,
|
|
2779
2961
|
filterCtx,
|
|
2780
2962
|
pkNames,
|
|
2781
|
-
db: executor
|
|
2963
|
+
db: executor,
|
|
2964
|
+
// MySQL sorts NULLs as the smallest values (first in ASC).
|
|
2965
|
+
nullOrdering: "nulls-smallest"
|
|
2782
2966
|
});
|
|
2783
2967
|
} catch (e) {
|
|
2784
2968
|
throw toGraphQLError(e);
|
|
@@ -2947,6 +3131,48 @@ var generateUpdate = (db, tableName, table, setArgs, filterArgs, fieldName, sing
|
|
|
2947
3131
|
args: queryArgs
|
|
2948
3132
|
};
|
|
2949
3133
|
};
|
|
3134
|
+
var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filterCtx) => {
|
|
3135
|
+
const queryArgs = {
|
|
3136
|
+
updates: {
|
|
3137
|
+
type: new import_graphql6.GraphQLNonNull(new import_graphql6.GraphQLList(new import_graphql6.GraphQLNonNull(updateManyInput)))
|
|
3138
|
+
}
|
|
3139
|
+
};
|
|
3140
|
+
return {
|
|
3141
|
+
name: fieldName,
|
|
3142
|
+
resolver: async (_source, args, context, _info) => {
|
|
3143
|
+
try {
|
|
3144
|
+
const { updates } = args;
|
|
3145
|
+
if (!updates.length) {
|
|
3146
|
+
throw new import_graphql6.GraphQLError("No updates were provided!");
|
|
3147
|
+
}
|
|
3148
|
+
const entries = updates.map(({ where, set }) => {
|
|
3149
|
+
const input = remapFromGraphQLSingleInput(set, table);
|
|
3150
|
+
if (!Object.keys(input).length) {
|
|
3151
|
+
throw new import_graphql6.GraphQLError("Unable to update with no values specified!");
|
|
3152
|
+
}
|
|
3153
|
+
return {
|
|
3154
|
+
set: input,
|
|
3155
|
+
filters: where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
|
|
3156
|
+
};
|
|
3157
|
+
});
|
|
3158
|
+
const executor = resolveExecutor(db, context);
|
|
3159
|
+
await executor.transaction(async (tx) => {
|
|
3160
|
+
for (const entry of entries) {
|
|
3161
|
+
let query = tx.update(table).set(entry.set);
|
|
3162
|
+
if (entry.filters) {
|
|
3163
|
+
query = query.where(entry.filters);
|
|
3164
|
+
}
|
|
3165
|
+
await query;
|
|
3166
|
+
}
|
|
3167
|
+
});
|
|
3168
|
+
return { isSuccess: true };
|
|
3169
|
+
} catch (e) {
|
|
3170
|
+
throw toGraphQLError(e);
|
|
3171
|
+
}
|
|
3172
|
+
},
|
|
3173
|
+
args: queryArgs
|
|
3174
|
+
};
|
|
3175
|
+
};
|
|
2950
3176
|
var generateDelete = (db, tableName, table, filterArgs, fieldName, single, requireWhere, filterCtx) => {
|
|
2951
3177
|
const queryArgs = {
|
|
2952
3178
|
where: {
|
|
@@ -3054,6 +3280,7 @@ var generateSchemaData = (db, schema, relations, options) => {
|
|
|
3054
3280
|
upsertArrayFieldName,
|
|
3055
3281
|
upsertSingleFieldName,
|
|
3056
3282
|
updateFieldName,
|
|
3283
|
+
updateManyFieldName,
|
|
3057
3284
|
updateSingleFieldName,
|
|
3058
3285
|
deleteFieldName,
|
|
3059
3286
|
deleteSingleFieldName
|
|
@@ -3116,6 +3343,15 @@ var generateSchemaData = (db, schema, relations, options) => {
|
|
|
3116
3343
|
features.requireWhere,
|
|
3117
3344
|
filterCtx
|
|
3118
3345
|
) : void 0;
|
|
3346
|
+
const updateManyInput = features.update && features.updateMany ? generateUpdateManyInput({ typeName, updatePrefix: prefixes.update, updateInput, tableFilters }) : void 0;
|
|
3347
|
+
const updateManyGenerated = updateManyInput ? generateUpdateMany(
|
|
3348
|
+
db,
|
|
3349
|
+
tableName,
|
|
3350
|
+
schema[tableName],
|
|
3351
|
+
updateManyInput,
|
|
3352
|
+
updateManyFieldName,
|
|
3353
|
+
filterCtx
|
|
3354
|
+
) : void 0;
|
|
3119
3355
|
const deleteGenerated = features.delete ? generateDelete(
|
|
3120
3356
|
db,
|
|
3121
3357
|
tableName,
|
|
@@ -3193,6 +3429,7 @@ var generateSchemaData = (db, schema, relations, options) => {
|
|
|
3193
3429
|
upsertArrGenerated,
|
|
3194
3430
|
upsertSingleGenerated,
|
|
3195
3431
|
updateGenerated,
|
|
3432
|
+
updateManyGenerated,
|
|
3196
3433
|
updateSingleGenerated,
|
|
3197
3434
|
deleteGenerated,
|
|
3198
3435
|
deleteSingleGenerated
|
|
@@ -3210,6 +3447,7 @@ var generateSchemaData = (db, schema, relations, options) => {
|
|
|
3210
3447
|
...features.insert || onConflictInput ? [insertInput] : [],
|
|
3211
3448
|
...onConflictInput ? [onConflictInput] : [],
|
|
3212
3449
|
...features.update ? [updateInput] : [],
|
|
3450
|
+
...updateManyInput ? [updateManyInput] : [],
|
|
3213
3451
|
tableFilters,
|
|
3214
3452
|
tableOrder
|
|
3215
3453
|
];
|
|
@@ -3276,16 +3514,48 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
|
|
|
3276
3514
|
single: false,
|
|
3277
3515
|
filterCtx,
|
|
3278
3516
|
pkNames,
|
|
3279
|
-
db: executor
|
|
3517
|
+
db: executor,
|
|
3518
|
+
// PostgreSQL sorts NULLs as the largest values (last in ASC).
|
|
3519
|
+
nullOrdering: "nulls-largest"
|
|
3280
3520
|
});
|
|
3281
3521
|
}
|
|
3282
|
-
const { offset, limit, orderBy, where, distinct } = args;
|
|
3522
|
+
const { offset, limit, orderBy, where, distinct, after } = args;
|
|
3283
3523
|
const selectedColumnsSql = extractSelectedColumnsFromTreeSQLFormat(
|
|
3284
3524
|
parsedInfo.fieldsByTypeName[typeName],
|
|
3285
3525
|
table,
|
|
3286
3526
|
{ tableName, relationMap, tables }
|
|
3287
3527
|
);
|
|
3288
|
-
const
|
|
3528
|
+
const cursorSelected = isCursorFieldSelected(parsedInfo.fieldsByTypeName[typeName], table);
|
|
3529
|
+
let cursorEntries;
|
|
3530
|
+
if (after != null || cursorSelected) {
|
|
3531
|
+
if (after != null && distinct?.length) {
|
|
3532
|
+
throw new import_graphql7.GraphQLError("'after' cannot be combined with 'distinct'.");
|
|
3533
|
+
}
|
|
3534
|
+
if (orderByHasRelationEntry(orderBy)) {
|
|
3535
|
+
if (after != null) {
|
|
3536
|
+
throw new import_graphql7.GraphQLError(
|
|
3537
|
+
"'after' cannot be combined with an orderBy that orders through a relation \u2014 a related row's value cannot be encoded into a cursor."
|
|
3538
|
+
);
|
|
3539
|
+
}
|
|
3540
|
+
} else if (!pkNames.length) {
|
|
3541
|
+
if (after != null) {
|
|
3542
|
+
throw new import_graphql7.GraphQLError(
|
|
3543
|
+
`Table ${tableName} has no primary key, so cursor pagination cannot be used on it.`
|
|
3544
|
+
);
|
|
3545
|
+
}
|
|
3546
|
+
} else {
|
|
3547
|
+
cursorEntries = cursorOrderingEntries(orderBy, pkNames);
|
|
3548
|
+
if (cursorSelected) {
|
|
3549
|
+
const allColumns = (0, import_drizzle_orm6.getColumns)(table);
|
|
3550
|
+
for (const [column] of cursorEntries) {
|
|
3551
|
+
selectedColumnsSql[column] ??= allColumns[column];
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
const cursorCondition = after != null && cursorEntries ? buildCursorCondition(table, cursorEntries, decodeCursor(after, cursorEntries), "nulls-largest") : void 0;
|
|
3557
|
+
const baseWhereSql = where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0;
|
|
3558
|
+
const whereSql = cursorCondition ? (0, import_drizzle_orm6.and)(baseWhereSql, cursorCondition) : baseWhereSql;
|
|
3289
3559
|
let distinctKeys;
|
|
3290
3560
|
if (distinct?.length) {
|
|
3291
3561
|
distinctKeys = await selectDistinctKeys({
|
|
@@ -3309,7 +3579,9 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
|
|
|
3309
3579
|
} else if (whereSql) {
|
|
3310
3580
|
q = q.where(whereSql);
|
|
3311
3581
|
}
|
|
3312
|
-
if (
|
|
3582
|
+
if (cursorEntries && !distinctKeys) {
|
|
3583
|
+
q = q.orderBy(...cursorOrderExprs(table, cursorEntries));
|
|
3584
|
+
} else if (orderBy) {
|
|
3313
3585
|
q = q.orderBy(
|
|
3314
3586
|
...extractOrderBy(table, orderBy, relationFilterCtx(filterCtx, tableName)),
|
|
3315
3587
|
...distinctKeys ? primaryKeyOrderExprs(table, pkNames) : []
|
|
@@ -3325,7 +3597,11 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
|
|
|
3325
3597
|
q = q.limit(limit);
|
|
3326
3598
|
}
|
|
3327
3599
|
}
|
|
3328
|
-
|
|
3600
|
+
const rows = await q;
|
|
3601
|
+
if (cursorEntries && cursorSelected) {
|
|
3602
|
+
attachRowCursors(rows, cursorEntries);
|
|
3603
|
+
}
|
|
3604
|
+
return remapToGraphQLArrayOutput(rows, tableName, table, relationMap);
|
|
3329
3605
|
} catch (e) {
|
|
3330
3606
|
throw toGraphQLError(e);
|
|
3331
3607
|
}
|
|
@@ -3591,6 +3867,78 @@ var generateUpdate2 = (db, tableName, table, tables, relationMap, setArgs, filte
|
|
|
3591
3867
|
args: queryArgs
|
|
3592
3868
|
};
|
|
3593
3869
|
};
|
|
3870
|
+
var generateUpdateMany2 = (db, tableName, table, tables, relationMap, updateManyInput, fieldName, typeName, typeNameMapper, filterCtx) => {
|
|
3871
|
+
const queryArgs = {
|
|
3872
|
+
updates: {
|
|
3873
|
+
type: new import_graphql7.GraphQLNonNull(new import_graphql7.GraphQLList(new import_graphql7.GraphQLNonNull(updateManyInput)))
|
|
3874
|
+
}
|
|
3875
|
+
};
|
|
3876
|
+
const pkNames = pgPrimaryKeyPropNames(table);
|
|
3877
|
+
return {
|
|
3878
|
+
name: fieldName,
|
|
3879
|
+
resolver: async (_source, args, context, info) => {
|
|
3880
|
+
try {
|
|
3881
|
+
const { updates } = args;
|
|
3882
|
+
if (!updates.length) {
|
|
3883
|
+
throw new import_graphql7.GraphQLError("No updates were provided!");
|
|
3884
|
+
}
|
|
3885
|
+
const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
|
|
3886
|
+
deep: true
|
|
3887
|
+
});
|
|
3888
|
+
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
3889
|
+
relationMap,
|
|
3890
|
+
tables,
|
|
3891
|
+
tableName,
|
|
3892
|
+
typeName,
|
|
3893
|
+
typeNameMapper,
|
|
3894
|
+
table,
|
|
3895
|
+
pkNames,
|
|
3896
|
+
parsedInfo
|
|
3897
|
+
});
|
|
3898
|
+
const entries = updates.map(({ where, set }) => {
|
|
3899
|
+
const input = remapFromGraphQLSingleInput(set, table);
|
|
3900
|
+
if (!Object.keys(input).length) {
|
|
3901
|
+
throw new import_graphql7.GraphQLError("Unable to update with no values specified!");
|
|
3902
|
+
}
|
|
3903
|
+
return {
|
|
3904
|
+
set: input,
|
|
3905
|
+
filters: where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
|
|
3906
|
+
};
|
|
3907
|
+
});
|
|
3908
|
+
const executor = resolveExecutor(db, context);
|
|
3909
|
+
const perEntry = await executor.transaction(async (tx) => {
|
|
3910
|
+
const results = [];
|
|
3911
|
+
for (const entry of entries) {
|
|
3912
|
+
let query = tx.update(table).set(entry.set);
|
|
3913
|
+
if (entry.filters) {
|
|
3914
|
+
query = query.where(entry.filters);
|
|
3915
|
+
}
|
|
3916
|
+
results.push(await query.returning(columns));
|
|
3917
|
+
}
|
|
3918
|
+
return results;
|
|
3919
|
+
});
|
|
3920
|
+
const flatRows = perEntry.flat();
|
|
3921
|
+
const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
|
|
3922
|
+
const output = [];
|
|
3923
|
+
let offset = 0;
|
|
3924
|
+
for (const rows of perEntry) {
|
|
3925
|
+
if (!rows.length) {
|
|
3926
|
+
output.push(null);
|
|
3927
|
+
continue;
|
|
3928
|
+
}
|
|
3929
|
+
for (let i = 0; i < rows.length; i++) {
|
|
3930
|
+
output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
|
|
3931
|
+
}
|
|
3932
|
+
offset += rows.length;
|
|
3933
|
+
}
|
|
3934
|
+
return output;
|
|
3935
|
+
} catch (e) {
|
|
3936
|
+
throw toGraphQLError(e);
|
|
3937
|
+
}
|
|
3938
|
+
},
|
|
3939
|
+
args: queryArgs
|
|
3940
|
+
};
|
|
3941
|
+
};
|
|
3594
3942
|
var generateDelete2 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx) => {
|
|
3595
3943
|
const queryArgs = {
|
|
3596
3944
|
where: {
|
|
@@ -3709,6 +4057,7 @@ function generateSchemaData2(db, schema, relations, options) {
|
|
|
3709
4057
|
upsertArrayFieldName,
|
|
3710
4058
|
upsertSingleFieldName,
|
|
3711
4059
|
updateFieldName,
|
|
4060
|
+
updateManyFieldName,
|
|
3712
4061
|
updateSingleFieldName,
|
|
3713
4062
|
deleteFieldName,
|
|
3714
4063
|
deleteSingleFieldName
|
|
@@ -3830,6 +4179,19 @@ function generateSchemaData2(db, schema, relations, options) {
|
|
|
3830
4179
|
typeNameMapper,
|
|
3831
4180
|
filterCtx
|
|
3832
4181
|
) : void 0;
|
|
4182
|
+
const updateManyInput = features.update && features.updateMany ? generateUpdateManyInput({ typeName, updatePrefix: prefixes.update, updateInput, tableFilters }) : void 0;
|
|
4183
|
+
const updateManyGenerated = updateManyInput ? generateUpdateMany2(
|
|
4184
|
+
db,
|
|
4185
|
+
tableName,
|
|
4186
|
+
schema[tableName],
|
|
4187
|
+
tables,
|
|
4188
|
+
eagerRelations,
|
|
4189
|
+
updateManyInput,
|
|
4190
|
+
updateManyFieldName,
|
|
4191
|
+
typeName,
|
|
4192
|
+
typeNameMapper,
|
|
4193
|
+
filterCtx
|
|
4194
|
+
) : void 0;
|
|
3833
4195
|
const deleteGenerated = features.delete ? generateDelete2(
|
|
3834
4196
|
db,
|
|
3835
4197
|
tableName,
|
|
@@ -3940,6 +4302,14 @@ function generateSchemaData2(db, schema, relations, options) {
|
|
|
3940
4302
|
resolve: updateGenerated.resolver
|
|
3941
4303
|
};
|
|
3942
4304
|
}
|
|
4305
|
+
if (updateManyGenerated) {
|
|
4306
|
+
mutations[updateManyGenerated.name] = {
|
|
4307
|
+
// Nullable items: a no-match entry yields `null` in its slot.
|
|
4308
|
+
type: new import_graphql7.GraphQLNonNull(new import_graphql7.GraphQLList(singleTableItemOutput)),
|
|
4309
|
+
args: updateManyGenerated.args,
|
|
4310
|
+
resolve: updateManyGenerated.resolver
|
|
4311
|
+
};
|
|
4312
|
+
}
|
|
3943
4313
|
if (updateSingleGenerated) {
|
|
3944
4314
|
mutations[updateSingleGenerated.name] = {
|
|
3945
4315
|
type: singleTableItemOutput,
|
|
@@ -3966,6 +4336,7 @@ function generateSchemaData2(db, schema, relations, options) {
|
|
|
3966
4336
|
...features.insert || onConflictInput ? [insertInput] : [],
|
|
3967
4337
|
...onConflictInput ? [onConflictInput] : [],
|
|
3968
4338
|
...features.update ? [updateInput] : [],
|
|
4339
|
+
...updateManyInput ? [updateManyInput] : [],
|
|
3969
4340
|
tableFilters,
|
|
3970
4341
|
tableOrder
|
|
3971
4342
|
];
|
|
@@ -4037,7 +4408,9 @@ var generateSelectArray3 = (db, tableName, tables, relationMap, orderArgs, filte
|
|
|
4037
4408
|
single: false,
|
|
4038
4409
|
filterCtx,
|
|
4039
4410
|
pkNames,
|
|
4040
|
-
db: executor
|
|
4411
|
+
db: executor,
|
|
4412
|
+
// SQLite sorts NULLs as the smallest values (first in ASC).
|
|
4413
|
+
nullOrdering: "nulls-smallest"
|
|
4041
4414
|
});
|
|
4042
4415
|
} catch (e) {
|
|
4043
4416
|
throw toGraphQLError(e);
|
|
@@ -4286,6 +4659,91 @@ var generateUpdate3 = (db, tableName, table, tables, relationMap, setArgs, filte
|
|
|
4286
4659
|
args: queryArgs
|
|
4287
4660
|
};
|
|
4288
4661
|
};
|
|
4662
|
+
var generateUpdateMany3 = (db, tableName, table, tables, relationMap, updateManyInput, fieldName, typeName, typeNameMapper, filterCtx) => {
|
|
4663
|
+
const queryArgs = {
|
|
4664
|
+
updates: {
|
|
4665
|
+
type: new import_graphql8.GraphQLNonNull(new import_graphql8.GraphQLList(new import_graphql8.GraphQLNonNull(updateManyInput)))
|
|
4666
|
+
}
|
|
4667
|
+
};
|
|
4668
|
+
const pkNames = sqlitePrimaryKeyPropNames(table);
|
|
4669
|
+
return {
|
|
4670
|
+
name: fieldName,
|
|
4671
|
+
resolver: async (_source, args, context, info) => {
|
|
4672
|
+
try {
|
|
4673
|
+
const { updates } = args;
|
|
4674
|
+
if (!updates.length) {
|
|
4675
|
+
throw new import_graphql8.GraphQLError("No updates were provided!");
|
|
4676
|
+
}
|
|
4677
|
+
const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
|
|
4678
|
+
deep: true
|
|
4679
|
+
});
|
|
4680
|
+
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
4681
|
+
relationMap,
|
|
4682
|
+
tables,
|
|
4683
|
+
tableName,
|
|
4684
|
+
typeName,
|
|
4685
|
+
typeNameMapper,
|
|
4686
|
+
table,
|
|
4687
|
+
pkNames,
|
|
4688
|
+
parsedInfo
|
|
4689
|
+
});
|
|
4690
|
+
const entries = updates.map(({ where, set }) => {
|
|
4691
|
+
const input = remapFromGraphQLSingleInput(set, table);
|
|
4692
|
+
if (!Object.keys(input).length) {
|
|
4693
|
+
throw new import_graphql8.GraphQLError("Unable to update with no values specified!");
|
|
4694
|
+
}
|
|
4695
|
+
return {
|
|
4696
|
+
set: input,
|
|
4697
|
+
filters: where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
|
|
4698
|
+
};
|
|
4699
|
+
});
|
|
4700
|
+
const runEntry = (tx, entry) => {
|
|
4701
|
+
let query = tx.update(table).set(entry.set);
|
|
4702
|
+
if (entry.filters) {
|
|
4703
|
+
query = query.where(entry.filters);
|
|
4704
|
+
}
|
|
4705
|
+
return query.returning(columns).all();
|
|
4706
|
+
};
|
|
4707
|
+
const executor = resolveExecutor(db, context);
|
|
4708
|
+
const perEntry = await executor.transaction((tx) => {
|
|
4709
|
+
const first = runEntry(tx, entries[0]);
|
|
4710
|
+
if (typeof first?.then === "function") {
|
|
4711
|
+
return (async () => {
|
|
4712
|
+
const results2 = [await first];
|
|
4713
|
+
for (let i = 1; i < entries.length; i++) {
|
|
4714
|
+
results2.push(await runEntry(tx, entries[i]));
|
|
4715
|
+
}
|
|
4716
|
+
return results2;
|
|
4717
|
+
})();
|
|
4718
|
+
}
|
|
4719
|
+
const results = [first];
|
|
4720
|
+
for (let i = 1; i < entries.length; i++) {
|
|
4721
|
+
results.push(runEntry(tx, entries[i]));
|
|
4722
|
+
}
|
|
4723
|
+
return results;
|
|
4724
|
+
});
|
|
4725
|
+
const flatRows = perEntry.flat();
|
|
4726
|
+
const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
|
|
4727
|
+
const output = [];
|
|
4728
|
+
let offset = 0;
|
|
4729
|
+
for (const rows of perEntry) {
|
|
4730
|
+
if (!rows.length) {
|
|
4731
|
+
output.push(null);
|
|
4732
|
+
continue;
|
|
4733
|
+
}
|
|
4734
|
+
for (let i = 0; i < rows.length; i++) {
|
|
4735
|
+
output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
|
|
4736
|
+
}
|
|
4737
|
+
offset += rows.length;
|
|
4738
|
+
}
|
|
4739
|
+
return output;
|
|
4740
|
+
} catch (e) {
|
|
4741
|
+
throw toGraphQLError(e);
|
|
4742
|
+
}
|
|
4743
|
+
},
|
|
4744
|
+
args: queryArgs
|
|
4745
|
+
};
|
|
4746
|
+
};
|
|
4289
4747
|
var generateDelete3 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx) => {
|
|
4290
4748
|
const queryArgs = {
|
|
4291
4749
|
where: {
|
|
@@ -4405,6 +4863,7 @@ var generateSchemaData3 = (db, schema, relations, options) => {
|
|
|
4405
4863
|
upsertArrayFieldName,
|
|
4406
4864
|
upsertSingleFieldName,
|
|
4407
4865
|
updateFieldName,
|
|
4866
|
+
updateManyFieldName,
|
|
4408
4867
|
updateSingleFieldName,
|
|
4409
4868
|
deleteFieldName,
|
|
4410
4869
|
deleteSingleFieldName
|
|
@@ -4526,6 +4985,19 @@ var generateSchemaData3 = (db, schema, relations, options) => {
|
|
|
4526
4985
|
typeNameMapper,
|
|
4527
4986
|
filterCtx
|
|
4528
4987
|
) : void 0;
|
|
4988
|
+
const updateManyInput = features.update && features.updateMany ? generateUpdateManyInput({ typeName, updatePrefix: prefixes.update, updateInput, tableFilters }) : void 0;
|
|
4989
|
+
const updateManyGenerated = updateManyInput ? generateUpdateMany3(
|
|
4990
|
+
db,
|
|
4991
|
+
tableName,
|
|
4992
|
+
schema[tableName],
|
|
4993
|
+
tables,
|
|
4994
|
+
eagerRelations,
|
|
4995
|
+
updateManyInput,
|
|
4996
|
+
updateManyFieldName,
|
|
4997
|
+
typeName,
|
|
4998
|
+
typeNameMapper,
|
|
4999
|
+
filterCtx
|
|
5000
|
+
) : void 0;
|
|
4529
5001
|
const deleteGenerated = features.delete ? generateDelete3(
|
|
4530
5002
|
db,
|
|
4531
5003
|
tableName,
|
|
@@ -4636,6 +5108,14 @@ var generateSchemaData3 = (db, schema, relations, options) => {
|
|
|
4636
5108
|
resolve: updateGenerated.resolver
|
|
4637
5109
|
};
|
|
4638
5110
|
}
|
|
5111
|
+
if (updateManyGenerated) {
|
|
5112
|
+
mutations[updateManyGenerated.name] = {
|
|
5113
|
+
// Nullable items: a no-match entry yields `null` in its slot.
|
|
5114
|
+
type: new import_graphql8.GraphQLNonNull(new import_graphql8.GraphQLList(singleTableItemOutput)),
|
|
5115
|
+
args: updateManyGenerated.args,
|
|
5116
|
+
resolve: updateManyGenerated.resolver
|
|
5117
|
+
};
|
|
5118
|
+
}
|
|
4639
5119
|
if (updateSingleGenerated) {
|
|
4640
5120
|
mutations[updateSingleGenerated.name] = {
|
|
4641
5121
|
type: singleTableItemOutput,
|
|
@@ -4662,6 +5142,7 @@ var generateSchemaData3 = (db, schema, relations, options) => {
|
|
|
4662
5142
|
...features.insert || onConflictInput ? [insertInput] : [],
|
|
4663
5143
|
...onConflictInput ? [onConflictInput] : [],
|
|
4664
5144
|
...features.update ? [updateInput] : [],
|
|
5145
|
+
...updateManyInput ? [updateManyInput] : [],
|
|
4665
5146
|
tableFilters,
|
|
4666
5147
|
tableOrder
|
|
4667
5148
|
];
|
|
@@ -4724,6 +5205,7 @@ var buildSchema = (db, config) => {
|
|
|
4724
5205
|
distinct: config?.features?.distinct ?? true,
|
|
4725
5206
|
insert: config?.features?.insert ?? true,
|
|
4726
5207
|
update: config?.features?.update ?? true,
|
|
5208
|
+
updateMany: config?.features?.updateMany ?? true,
|
|
4727
5209
|
delete: config?.features?.delete ?? true,
|
|
4728
5210
|
upsert: config?.features?.upsert ?? false,
|
|
4729
5211
|
requireWhere: config?.features?.requireWhere ?? false
|