drizzle-graphql
Version:
Automatically generate GraphQL schema or customizable schema config fields from Drizzle ORM schema
1,381 lines (1,372 loc) • 67.3 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc2) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
buildSchema: () => buildSchema
});
module.exports = __toCommonJS(src_exports);
var import_drizzle_orm7 = require("drizzle-orm");
var import_mysql_core3 = require("drizzle-orm/mysql-core");
var import_pg_core3 = require("drizzle-orm/pg-core");
var import_sqlite_core3 = require("drizzle-orm/sqlite-core");
var import_graphql7 = require("graphql");
// src/util/builders/mysql.ts
var import_drizzle_orm4 = require("drizzle-orm");
var import_mysql_core2 = require("drizzle-orm/mysql-core");
var import_graphql4 = require("graphql");
// src/util/builders/common.ts
var import_drizzle_orm3 = require("drizzle-orm");
var import_graphql3 = require("graphql");
// src/util/case-ops/index.ts
var uncapitalize = (input) => input.length ? `${input[0].toLocaleLowerCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
var capitalize = (input) => input.length ? `${input[0].toLocaleUpperCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
// src/util/data-mappers/index.ts
var import_drizzle_orm = require("drizzle-orm");
var import_graphql = require("graphql");
var remapToGraphQLCore = (key, value, tableName, column, relationMap) => {
if (value instanceof Date)
return value.toISOString();
if (value instanceof Buffer)
return Array.from(value);
if (typeof value === "bigint")
return value.toString();
if (Array.isArray(value)) {
const relations = relationMap?.[tableName];
if (relations?.[key]) {
return remapToGraphQLArrayOutput(
value,
relations[key].targetTableName,
relations[key].relation.referencedTable,
relationMap
);
}
if (column.columnType === "PgGeometry" || column.columnType === "PgVector")
return value;
return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
}
if (typeof value === "object") {
const relations = relationMap?.[tableName];
if (relations?.[key]) {
return remapToGraphQLSingleOutput(
value,
relations[key].targetTableName,
relations[key].relation.referencedTable,
relationMap
);
}
if (column.columnType === "PgGeometryObject")
return value;
return JSON.stringify(value);
}
return value;
};
var remapToGraphQLSingleOutput = (queryOutput, tableName, table, relationMap) => {
for (const [key, value] of Object.entries(queryOutput)) {
if (value === void 0 || value === null) {
delete queryOutput[key];
} else {
queryOutput[key] = remapToGraphQLCore(key, value, tableName, table[key], relationMap);
}
}
return queryOutput;
};
var remapToGraphQLArrayOutput = (queryOutput, tableName, table, relationMap) => {
for (const entry of queryOutput) {
remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
}
return queryOutput;
};
var remapFromGraphQLCore = (value, column, columnName) => {
switch (column.dataType) {
case "date": {
const formatted = new Date(value);
if (Number.isNaN(formatted.getTime()))
throw new import_graphql.GraphQLError(`Field '${columnName}' is not a valid date!`);
return formatted;
}
case "buffer": {
if (!Array.isArray(value)) {
throw new import_graphql.GraphQLError(`Field '${columnName}' is not an array!`);
}
return Buffer.from(value);
}
case "json": {
if (column.columnType === "PgGeometryObject")
return value;
try {
return JSON.parse(value);
} catch (e) {
throw new import_graphql.GraphQLError(
`Invalid JSON in field '${columnName}':
${e instanceof Error ? e.message : "Unknown error"}`
);
}
}
case "array": {
if (!Array.isArray(value)) {
throw new import_graphql.GraphQLError(`Field '${columnName}' is not an array!`);
}
if (column.columnType === "PgGeometry" && value.length !== 2) {
throw new import_graphql.GraphQLError(
`Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`
);
}
return value;
}
case "bigint": {
try {
return BigInt(value);
} catch (error) {
throw new import_graphql.GraphQLError(`Field '${columnName}' is not a BigInt!`);
}
}
default: {
return value;
}
}
};
var remapFromGraphQLSingleInput = (queryInput, table) => {
for (const [key, value] of Object.entries(queryInput)) {
if (value === void 0) {
delete queryInput[key];
} else {
const column = (0, import_drizzle_orm.getTableColumns)(table)[key];
if (!column)
throw new import_graphql.GraphQLError(`Unknown column: ${key}`);
if (value === null && column.notNull) {
delete queryInput[key];
continue;
}
queryInput[key] = remapFromGraphQLCore(value, column, key);
}
}
return queryInput;
};
var remapFromGraphQLArrayInput = (queryInput, table) => {
for (const entry of queryInput)
remapFromGraphQLSingleInput(entry, table);
return queryInput;
};
// src/util/type-converter/index.ts
var import_drizzle_orm2 = require("drizzle-orm");
var import_mysql_core = require("drizzle-orm/mysql-core");
var import_pg_core = require("drizzle-orm/pg-core");
var import_sqlite_core = require("drizzle-orm/sqlite-core");
var import_graphql2 = require("graphql");
var allowedNameChars = /^[a-zA-Z0-9_]+$/;
var enumMap = /* @__PURE__ */ new WeakMap();
var generateEnumCached = (column, columnName, tableName) => {
if (enumMap.has(column))
return enumMap.get(column);
const gqlEnum = new import_graphql2.GraphQLEnumType({
name: `${capitalize(tableName)}${capitalize(columnName)}Enum`,
values: Object.fromEntries(column.enumValues.map((e, index) => [allowedNameChars.test(e) ? e : `Option${index}`, {
value: e,
description: `Value: ${e}`
}]))
});
enumMap.set(column, gqlEnum);
return gqlEnum;
};
var geoXyType = new import_graphql2.GraphQLObjectType({
name: "PgGeometryObject",
fields: {
x: { type: import_graphql2.GraphQLFloat },
y: { type: import_graphql2.GraphQLFloat }
}
});
var geoXyInputType = new import_graphql2.GraphQLInputObjectType({
name: "PgGeometryObjectInput",
fields: {
x: { type: import_graphql2.GraphQLFloat },
y: { type: import_graphql2.GraphQLFloat }
}
});
var columnToGraphQLCore = (column, columnName, tableName, isInput) => {
switch (column.dataType) {
case "boolean":
return { type: import_graphql2.GraphQLBoolean, description: "Boolean" };
case "json":
return column.columnType === "PgGeometryObject" ? {
type: isInput ? geoXyInputType : geoXyType,
description: "Geometry points XY"
} : { type: import_graphql2.GraphQLString, description: "JSON" };
case "date":
return { type: import_graphql2.GraphQLString, description: "Date" };
case "string":
if (column.enumValues?.length)
return { type: generateEnumCached(column, columnName, tableName) };
return { type: import_graphql2.GraphQLString, description: "String" };
case "bigint":
return { type: import_graphql2.GraphQLString, description: "BigInt" };
case "number":
return (0, import_drizzle_orm2.is)(column, import_pg_core.PgInteger) || (0, import_drizzle_orm2.is)(column, import_pg_core.PgSerial) || (0, import_drizzle_orm2.is)(column, import_mysql_core.MySqlInt) || (0, import_drizzle_orm2.is)(column, import_mysql_core.MySqlSerial) || (0, import_drizzle_orm2.is)(column, import_sqlite_core.SQLiteInteger) ? { type: import_graphql2.GraphQLInt, description: "Integer" } : { type: import_graphql2.GraphQLFloat, description: "Float" };
case "buffer":
return { type: new import_graphql2.GraphQLList(new import_graphql2.GraphQLNonNull(import_graphql2.GraphQLInt)), description: "Buffer" };
case "array": {
if (column.columnType === "PgVector") {
return {
type: new import_graphql2.GraphQLList(new import_graphql2.GraphQLNonNull(import_graphql2.GraphQLFloat)),
description: "Array<Float>"
};
}
if (column.columnType === "PgGeometry") {
return {
type: new import_graphql2.GraphQLList(new import_graphql2.GraphQLNonNull(import_graphql2.GraphQLFloat)),
description: "Tuple<[Float, Float]>"
};
}
const innerType = columnToGraphQLCore(
column.baseColumn,
columnName,
tableName,
isInput
);
return {
type: new import_graphql2.GraphQLList(new import_graphql2.GraphQLNonNull(innerType.type)),
description: `Array<${innerType.description}>`
};
}
case "custom":
default:
throw new Error(`Drizzle-GraphQL Error: Type ${column.dataType} is not implemented!`);
}
};
var drizzleColumnToGraphQLType = (column, columnName, tableName, forceNullable = false, defaultIsNullable = false, isInput = false) => {
const typeDesc = columnToGraphQLCore(column, columnName, tableName, isInput);
const noDesc = ["string", "boolean", "number"];
if (noDesc.find((e) => e === column.dataType))
delete typeDesc.description;
if (forceNullable)
return typeDesc;
if (column.notNull && !(defaultIsNullable && (column.hasDefault || column.defaultFn))) {
return {
type: new import_graphql2.GraphQLNonNull(typeDesc.type),
description: typeDesc.description
};
}
return typeDesc;
};
// src/util/builders/common.ts
var rqbCrashTypes = [
"SQLiteBigInt",
"SQLiteBlobJson",
"SQLiteBlobBuffer"
];
var extractSelectedColumnsFromTree = (tree, table) => {
const tableColumns = (0, import_drizzle_orm3.getTableColumns)(table);
const treeEntries = Object.entries(tree);
const selectedColumns = [];
for (const [fieldName, fieldData] of treeEntries) {
if (!tableColumns[fieldData.name])
continue;
selectedColumns.push([fieldData.name, true]);
}
if (!selectedColumns.length) {
const columnKeys = Object.entries(tableColumns);
const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
selectedColumns.push([columnName, true]);
}
return Object.fromEntries(selectedColumns);
};
var extractSelectedColumnsFromTreeSQLFormat = (tree, table) => {
const tableColumns = (0, import_drizzle_orm3.getTableColumns)(table);
const treeEntries = Object.entries(tree);
const selectedColumns = [];
for (const [fieldName, fieldData] of treeEntries) {
if (!tableColumns[fieldData.name])
continue;
selectedColumns.push([fieldData.name, tableColumns[fieldData.name]]);
}
if (!selectedColumns.length) {
const columnKeys = Object.entries(tableColumns);
const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
selectedColumns.push([columnName, tableColumns[columnName]]);
}
return Object.fromEntries(selectedColumns);
};
var innerOrder = new import_graphql3.GraphQLInputObjectType({
name: "InnerOrder",
fields: {
direction: {
type: new import_graphql3.GraphQLNonNull(
new import_graphql3.GraphQLEnumType({
name: "OrderDirection",
description: "Order by direction",
values: {
asc: {
value: "asc",
description: "Ascending order"
},
desc: {
value: "desc",
description: "Descending order"
}
}
})
)
},
priority: { type: new import_graphql3.GraphQLNonNull(import_graphql3.GraphQLInt), description: "Priority of current field" }
}
});
var generateColumnFilterValues = (column, tableName, columnName) => {
const columnGraphQLType = drizzleColumnToGraphQLType(column, columnName, tableName, true, false, true);
const columnArr = new import_graphql3.GraphQLList(new import_graphql3.GraphQLNonNull(columnGraphQLType.type));
const baseFields = {
eq: { type: columnGraphQLType.type, description: columnGraphQLType.description },
ne: { type: columnGraphQLType.type, description: columnGraphQLType.description },
lt: { type: columnGraphQLType.type, description: columnGraphQLType.description },
lte: { type: columnGraphQLType.type, description: columnGraphQLType.description },
gt: { type: columnGraphQLType.type, description: columnGraphQLType.description },
gte: { type: columnGraphQLType.type, description: columnGraphQLType.description },
like: { type: import_graphql3.GraphQLString },
notLike: { type: import_graphql3.GraphQLString },
ilike: { type: import_graphql3.GraphQLString },
notIlike: { type: import_graphql3.GraphQLString },
inArray: { type: columnArr, description: `Array<${columnGraphQLType.description}>` },
notInArray: { type: columnArr, description: `Array<${columnGraphQLType.description}>` },
isNull: { type: import_graphql3.GraphQLBoolean },
isNotNull: { type: import_graphql3.GraphQLBoolean }
};
const type = new import_graphql3.GraphQLInputObjectType({
name: `${capitalize(tableName)}${capitalize(columnName)}Filters`,
fields: {
...baseFields,
OR: {
type: new import_graphql3.GraphQLList(
new import_graphql3.GraphQLNonNull(
new import_graphql3.GraphQLInputObjectType({
name: `${capitalize(tableName)}${capitalize(columnName)}filtersOr`,
fields: {
...baseFields
}
})
)
)
}
}
});
return type;
};
var orderMap = /* @__PURE__ */ new WeakMap();
var generateTableOrderCached = (table) => {
if (orderMap.has(table))
return orderMap.get(table);
const columns = (0, import_drizzle_orm3.getTableColumns)(table);
const columnEntries = Object.entries(columns);
const remapped = Object.fromEntries(
columnEntries.map(([columnName, columnDescription]) => [columnName, { type: innerOrder }])
);
orderMap.set(table, remapped);
return remapped;
};
var filterMap = /* @__PURE__ */ new WeakMap();
var generateTableFilterValuesCached = (table, tableName) => {
if (filterMap.has(table))
return filterMap.get(table);
const columns = (0, import_drizzle_orm3.getTableColumns)(table);
const columnEntries = Object.entries(columns);
const remapped = Object.fromEntries(
columnEntries.map(([columnName, columnDescription]) => [
columnName,
{
type: generateColumnFilterValues(columnDescription, tableName, columnName)
}
])
);
filterMap.set(table, remapped);
return remapped;
};
var fieldMap = /* @__PURE__ */ new WeakMap();
var generateTableSelectTypeFieldsCached = (table, tableName) => {
if (fieldMap.has(table))
return fieldMap.get(table);
const columns = (0, import_drizzle_orm3.getTableColumns)(table);
const columnEntries = Object.entries(columns);
const remapped = Object.fromEntries(
columnEntries.map(([columnName, columnDescription]) => [
columnName,
drizzleColumnToGraphQLType(columnDescription, columnName, tableName)
])
);
fieldMap.set(table, remapped);
return remapped;
};
var orderTypeMap = /* @__PURE__ */ new WeakMap();
var generateTableOrderTypeCached = (table, tableName) => {
if (orderTypeMap.has(table))
return orderTypeMap.get(table);
const orderColumns = generateTableOrderCached(table);
const order = new import_graphql3.GraphQLInputObjectType({
name: `${capitalize(tableName)}OrderBy`,
fields: orderColumns
});
orderTypeMap.set(table, order);
return order;
};
var filterTypeMap = /* @__PURE__ */ new WeakMap();
var generateTableFilterTypeCached = (table, tableName) => {
if (filterTypeMap.has(table))
return filterTypeMap.get(table);
const filterColumns = generateTableFilterValuesCached(table, tableName);
const filters = new import_graphql3.GraphQLInputObjectType({
name: `${capitalize(tableName)}Filters`,
fields: {
...filterColumns,
OR: {
type: new import_graphql3.GraphQLList(
new import_graphql3.GraphQLNonNull(
new import_graphql3.GraphQLInputObjectType({
name: `${capitalize(tableName)}FiltersOr`,
fields: filterColumns
})
)
)
}
}
});
filterTypeMap.set(table, filters);
return filters;
};
var generateSelectFields = (tables, tableName, relationMap, typeName, withOrder, relationsDepthLimit, currentDepth = 0, usedTables = /* @__PURE__ */ new Set()) => {
const relations = relationMap[tableName];
const relationEntries = relations ? Object.entries(relations) : [];
const table = tables[tableName];
const order = withOrder ? generateTableOrderTypeCached(table, tableName) : void 0;
const filters = generateTableFilterTypeCached(table, tableName);
const tableFields = generateTableSelectTypeFieldsCached(table, tableName);
if (usedTables.has(tableName) || typeof relationsDepthLimit === "number" && currentDepth >= relationsDepthLimit || !relationEntries.length) {
return {
order,
filters,
tableFields,
relationFields: {}
};
}
const rawRelationFields = [];
const updatedUsedTables = new Set(usedTables).add(tableName);
const newDepth = currentDepth + 1;
for (const [relationName, { targetTableName, relation }] of relationEntries) {
const relTypeName = `${typeName}${capitalize(relationName)}Relation`;
const isOne = (0, import_drizzle_orm3.is)(relation, import_drizzle_orm3.One);
const relData = generateSelectFields(
tables,
targetTableName,
relationMap,
relTypeName,
!isOne,
relationsDepthLimit,
newDepth,
updatedUsedTables
);
const relType = new import_graphql3.GraphQLObjectType({
name: relTypeName,
fields: { ...relData.tableFields, ...relData.relationFields }
});
if (isOne) {
rawRelationFields.push([
relationName,
{
type: relType,
args: {
where: { type: relData.filters }
}
}
]);
continue;
}
rawRelationFields.push([
relationName,
{
type: new import_graphql3.GraphQLNonNull(new import_graphql3.GraphQLList(new import_graphql3.GraphQLNonNull(relType))),
args: {
where: { type: relData.filters },
orderBy: { type: relData.order },
offset: { type: import_graphql3.GraphQLInt },
limit: { type: import_graphql3.GraphQLInt }
}
}
]);
}
const relationFields = Object.fromEntries(rawRelationFields);
return { order, filters, tableFields, relationFields };
};
var generateTableTypes = (tableName, tables, relationMap, withReturning, relationsDepthLimit) => {
const stylizedName = capitalize(tableName);
const { tableFields, relationFields, filters, order } = generateSelectFields(
tables,
tableName,
relationMap,
stylizedName,
true,
relationsDepthLimit
);
const table = tables[tableName];
const columns = (0, import_drizzle_orm3.getTableColumns)(table);
const columnEntries = Object.entries(columns);
const insertFields = Object.fromEntries(
columnEntries.map(([columnName, columnDescription]) => [
columnName,
drizzleColumnToGraphQLType(columnDescription, columnName, tableName, false, true, true)
])
);
const updateFields = Object.fromEntries(
columnEntries.map(([columnName, columnDescription]) => [
columnName,
drizzleColumnToGraphQLType(columnDescription, columnName, tableName, true, false, true)
])
);
const insertInput = new import_graphql3.GraphQLInputObjectType({
name: `${stylizedName}InsertInput`,
fields: insertFields
});
const selectSingleOutput = new import_graphql3.GraphQLObjectType({
name: `${stylizedName}SelectItem`,
fields: { ...tableFields, ...relationFields }
});
const selectArrOutput = new import_graphql3.GraphQLNonNull(new import_graphql3.GraphQLList(new import_graphql3.GraphQLNonNull(selectSingleOutput)));
const singleTableItemOutput = withReturning ? new import_graphql3.GraphQLObjectType({
name: `${stylizedName}Item`,
fields: tableFields
}) : void 0;
const arrTableItemOutput = withReturning ? new import_graphql3.GraphQLNonNull(new import_graphql3.GraphQLList(new import_graphql3.GraphQLNonNull(singleTableItemOutput))) : void 0;
const updateInput = new import_graphql3.GraphQLInputObjectType({
name: `${stylizedName}UpdateInput`,
fields: updateFields
});
const inputs = {
insertInput,
updateInput,
tableOrder: order,
tableFilters: filters
};
const outputs = withReturning ? {
selectSingleOutput,
selectArrOutput,
singleTableItemOutput,
arrTableItemOutput
} : {
selectSingleOutput,
selectArrOutput
};
return {
inputs,
outputs
};
};
var extractOrderBy = (table, orderArgs) => {
const res = [];
for (const [column, config] of Object.entries(orderArgs).sort(
(a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0)
)) {
if (!config)
continue;
const { direction } = config;
res.push(direction === "asc" ? (0, import_drizzle_orm3.asc)((0, import_drizzle_orm3.getTableColumns)(table)[column]) : (0, import_drizzle_orm3.desc)((0, import_drizzle_orm3.getTableColumns)(table)[column]));
}
return res;
};
var extractFiltersColumn = (column, columnName, operators) => {
if (!operators.OR?.length)
delete operators.OR;
const entries = Object.entries(operators);
if (operators.OR) {
if (entries.length > 1) {
throw new import_graphql3.GraphQLError(`WHERE ${columnName}: Cannot specify both fields and 'OR' in column operators!`);
}
const variants2 = [];
for (const variant of operators.OR) {
const extracted = extractFiltersColumn(column, columnName, variant);
if (extracted)
variants2.push(extracted);
}
return variants2.length ? variants2.length > 1 ? (0, import_drizzle_orm3.or)(...variants2) : variants2[0] : void 0;
}
const variants = [];
for (const [operatorName, operatorValue] of entries) {
if (operatorValue === null || operatorValue === false)
continue;
let operator;
switch (operatorName) {
case "eq":
operator = operator ?? import_drizzle_orm3.eq;
case "ne":
operator = operator ?? import_drizzle_orm3.ne;
case "gt":
operator = operator ?? import_drizzle_orm3.gt;
case "gte":
operator = operator ?? import_drizzle_orm3.gte;
case "lt":
operator = operator ?? import_drizzle_orm3.lt;
case "lte":
operator = operator ?? import_drizzle_orm3.lte;
const singleValue = remapFromGraphQLCore(operatorValue, column, columnName);
variants.push(operator(column, singleValue));
break;
case "like":
operator = operator ?? import_drizzle_orm3.like;
case "notLike":
operator = operator ?? import_drizzle_orm3.notLike;
case "ilike":
operator = operator ?? import_drizzle_orm3.ilike;
case "notIlike":
operator = operator ?? import_drizzle_orm3.notIlike;
variants.push(operator(column, operatorValue));
break;
case "inArray":
operator = operator ?? import_drizzle_orm3.inArray;
case "notInArray":
operator = operator ?? import_drizzle_orm3.notInArray;
if (!operatorValue.length) {
throw new import_graphql3.GraphQLError(
`WHERE ${columnName}: Unable to use operator ${operatorName} with an empty array!`
);
}
const arrayValue = operatorValue.map((val) => remapFromGraphQLCore(val, column, columnName));
variants.push(operator(column, arrayValue));
break;
case "isNull":
operator = operator ?? import_drizzle_orm3.isNull;
case "isNotNull":
operator = operator ?? import_drizzle_orm3.isNotNull;
variants.push(operator(column));
}
}
return variants.length ? variants.length > 1 ? (0, import_drizzle_orm3.and)(...variants) : variants[0] : void 0;
};
var extractFilters = (table, tableName, filters) => {
if (!filters.OR?.length)
delete filters.OR;
const entries = Object.entries(filters);
if (!entries.length)
return;
if (filters.OR) {
if (entries.length > 1) {
throw new import_graphql3.GraphQLError(`WHERE ${tableName}: Cannot specify both fields and 'OR' in table filters!`);
}
const variants2 = [];
for (const variant of filters.OR) {
const extracted = extractFilters(table, tableName, variant);
if (extracted)
variants2.push(extracted);
}
return variants2.length ? variants2.length > 1 ? (0, import_drizzle_orm3.or)(...variants2) : variants2[0] : void 0;
}
const variants = [];
for (const [columnName, operators] of entries) {
if (operators === null)
continue;
const column = (0, import_drizzle_orm3.getTableColumns)(table)[columnName];
variants.push(extractFiltersColumn(column, columnName, operators));
}
return variants.length ? variants.length > 1 ? (0, import_drizzle_orm3.and)(...variants) : variants[0] : void 0;
};
var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, originField, isInitial = false) => {
const relations = relationMap[tableName];
if (!relations)
return void 0;
const baseField = Object.entries(originField.fieldsByTypeName).find(([key, value]) => key === typeName)?.[1];
if (!baseField)
return void 0;
const args = {};
for (const [relName, { targetTableName, relation }] of Object.entries(relations)) {
const relTypeName = `${isInitial ? capitalize(tableName) : typeName}${capitalize(relName)}Relation`;
const relFieldSelection = Object.values(baseField).find(
(field) => field.name === relName
)?.fieldsByTypeName[relTypeName];
if (!relFieldSelection)
continue;
const columns = extractSelectedColumnsFromTree(relFieldSelection, tables[targetTableName]);
const thisRecord = {};
thisRecord.columns = columns;
const relationField = Object.values(baseField).find((e) => e.name === relName);
const relationArgs = relationField?.args;
const orderBy = relationArgs?.orderBy ? extractOrderBy(tables[targetTableName], relationArgs.orderBy) : void 0;
const where = relationArgs?.where ? extractFilters(tables[targetTableName], relName, relationArgs?.where) : void 0;
const offset = relationArgs?.offset ?? void 0;
const limit = relationArgs?.limit ?? void 0;
thisRecord.orderBy = orderBy;
thisRecord.where = where;
thisRecord.offset = offset;
thisRecord.limit = limit;
const relWith = relationField ? extractRelationsParamsInner(relationMap, tables, targetTableName, relTypeName, relationField) : void 0;
thisRecord.with = relWith;
args[relName] = thisRecord;
}
return args;
};
var extractRelationsParams = (relationMap, tables, tableName, info, typeName) => {
if (!info)
return void 0;
return extractRelationsParamsInner(relationMap, tables, tableName, typeName, info, true);
};
// src/util/builders/mysql.ts
var import_graphql_parse_resolve_info = require("graphql-parse-resolve-info");
var generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filterArgs) => {
const queryName = `${uncapitalize(tableName)}`;
const queryBase = db.query[tableName];
if (!queryBase) {
throw new Error(
`Drizzle-GraphQL Error: Table ${tableName} not found in drizzle instance. Did you forget to pass schema to drizzle constructor?`
);
}
const queryArgs = {
offset: {
type: import_graphql4.GraphQLInt
},
limit: {
type: import_graphql4.GraphQLInt
},
orderBy: {
type: orderArgs
},
where: {
type: filterArgs
}
};
const typeName = `${capitalize(tableName)}SelectItem`;
const table = tables[tableName];
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { offset, limit, orderBy, where } = args;
const parsedInfo = (0, import_graphql_parse_resolve_info.parseResolveInfo)(info, {
deep: true
});
const query = queryBase.findMany({
columns: extractSelectedColumnsFromTree(
parsedInfo.fieldsByTypeName[typeName],
table
),
offset,
limit,
orderBy: orderBy ? extractOrderBy(table, orderBy) : void 0,
where: where ? extractFilters(table, tableName, where) : void 0,
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName) : void 0
});
const result = await query;
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql4.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateSelectSingle = (db, tableName, tables, relationMap, orderArgs, filterArgs) => {
const queryName = `${uncapitalize(tableName)}Single`;
const queryBase = db.query[tableName];
if (!queryBase) {
throw new Error(
`Drizzle-GraphQL Error: Table ${tableName} not found in drizzle instance. Did you forget to pass schema to drizzle constructor?`
);
}
const queryArgs = {
offset: {
type: import_graphql4.GraphQLInt
},
orderBy: {
type: orderArgs
},
where: {
type: filterArgs
}
};
const typeName = `${capitalize(tableName)}SelectItem`;
const table = tables[tableName];
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { offset, orderBy, where } = args;
const parsedInfo = (0, import_graphql_parse_resolve_info.parseResolveInfo)(info, {
deep: true
});
const query = queryBase.findFirst({
columns: extractSelectedColumnsFromTree(
parsedInfo.fieldsByTypeName[typeName],
table
),
offset,
orderBy: orderBy ? extractOrderBy(table, orderBy) : void 0,
where: where ? extractFilters(table, tableName, where) : void 0,
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName) : void 0
});
const result = await query;
if (!result)
return void 0;
return remapToGraphQLSingleOutput(result, tableName, table, relationMap);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql4.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateInsertArray = (db, tableName, table, baseType) => {
const queryName = `insertInto${capitalize(tableName)}`;
const queryArgs = {
values: {
type: new import_graphql4.GraphQLNonNull(new import_graphql4.GraphQLList(new import_graphql4.GraphQLNonNull(baseType)))
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const input = remapFromGraphQLArrayInput(args.values, table);
if (!input.length)
throw new import_graphql4.GraphQLError("No values were provided!");
await db.insert(table).values(input);
return { isSuccess: true };
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql4.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateInsertSingle = (db, tableName, table, baseType) => {
const queryName = `insertInto${capitalize(tableName)}Single`;
const queryArgs = {
values: {
type: new import_graphql4.GraphQLNonNull(baseType)
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const input = remapFromGraphQLSingleInput(args.values, table);
await db.insert(table).values(input);
return { isSuccess: true };
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql4.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateUpdate = (db, tableName, table, setArgs, filterArgs) => {
const queryName = `update${capitalize(tableName)}`;
const queryArgs = {
set: {
type: new import_graphql4.GraphQLNonNull(setArgs)
},
where: {
type: filterArgs
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { where, set } = args;
const input = remapFromGraphQLSingleInput(set, table);
if (!Object.keys(input).length)
throw new import_graphql4.GraphQLError("Unable to update with no values specified!");
let query = db.update(table).set(input);
if (where) {
const filters = extractFilters(table, tableName, where);
query = query.where(filters);
}
await query;
return { isSuccess: true };
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql4.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateDelete = (db, tableName, table, filterArgs) => {
const queryName = `deleteFrom${tableName}`;
const queryArgs = {
where: {
type: filterArgs
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { where } = args;
let query = db.delete(table);
if (where) {
const filters = extractFilters(table, tableName, where);
query = query.where(filters);
}
await query;
return { isSuccess: true };
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql4.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateSchemaData = (db, schema, relationsDepthLimit) => {
const rawSchema = schema;
const schemaEntries = Object.entries(rawSchema);
const tableEntries = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm4.is)(value, import_mysql_core2.MySqlTable));
const tables = Object.fromEntries(tableEntries);
if (!tableEntries.length) {
throw new Error(
"Drizzle-GraphQL Error: No tables detected in Drizzle-ORM's database instance. Did you forget to pass schema to drizzle constructor?"
);
}
const rawRelations = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm4.is)(value, import_drizzle_orm4.Relations)).map(([key, value]) => [
tableEntries.find(
([tableName, tableValue]) => tableValue === value.table
)[0],
value
]).map(([tableName, relValue]) => [
tableName,
relValue.config((0, import_drizzle_orm4.createTableRelationsHelpers)(tables[tableName]))
]);
const namedRelations = Object.fromEntries(
rawRelations.map(([relName, config]) => {
const namedConfig = Object.fromEntries(
Object.entries(config).map(([innerRelName, innerRelValue]) => [innerRelName, {
relation: innerRelValue,
targetTableName: tableEntries.find(
([tableName, tableValue]) => tableValue === innerRelValue.referencedTable
)[0]
}])
);
return [
relName,
namedConfig
];
})
);
const queries = {};
const mutations = {};
const gqlSchemaTypes = Object.fromEntries(
Object.entries(tables).map(([tableName, table]) => [
tableName,
generateTableTypes(tableName, tables, namedRelations, false, relationsDepthLimit)
])
);
const mutationReturnType = new import_graphql4.GraphQLObjectType({
name: `MutationReturn`,
fields: {
isSuccess: {
type: new import_graphql4.GraphQLNonNull(import_graphql4.GraphQLBoolean)
}
}
});
const inputs = {};
const outputs = {
MutationReturn: mutationReturnType
};
for (const [tableName, tableTypes] of Object.entries(gqlSchemaTypes)) {
const { insertInput, updateInput, tableFilters, tableOrder } = tableTypes.inputs;
const { selectSingleOutput, selectArrOutput } = tableTypes.outputs;
const selectArrGenerated = generateSelectArray(
db,
tableName,
tables,
namedRelations,
tableOrder,
tableFilters
);
const selectSingleGenerated = generateSelectSingle(
db,
tableName,
tables,
namedRelations,
tableOrder,
tableFilters
);
const insertArrGenerated = generateInsertArray(db, tableName, schema[tableName], insertInput);
const insertSingleGenerated = generateInsertSingle(db, tableName, schema[tableName], insertInput);
const updateGenerated = generateUpdate(
db,
tableName,
schema[tableName],
updateInput,
tableFilters
);
const deleteGenerated = generateDelete(db, tableName, schema[tableName], tableFilters);
queries[selectArrGenerated.name] = {
type: selectArrOutput,
args: selectArrGenerated.args,
resolve: selectArrGenerated.resolver
};
queries[selectSingleGenerated.name] = {
type: selectSingleOutput,
args: selectSingleGenerated.args,
resolve: selectSingleGenerated.resolver
};
mutations[insertArrGenerated.name] = {
type: mutationReturnType,
args: insertArrGenerated.args,
resolve: insertArrGenerated.resolver
};
mutations[insertSingleGenerated.name] = {
type: mutationReturnType,
args: insertSingleGenerated.args,
resolve: insertSingleGenerated.resolver
};
mutations[updateGenerated.name] = {
type: mutationReturnType,
args: updateGenerated.args,
resolve: updateGenerated.resolver
};
mutations[deleteGenerated.name] = {
type: mutationReturnType,
args: deleteGenerated.args,
resolve: deleteGenerated.resolver
};
[insertInput, updateInput, tableFilters, tableOrder].forEach((e) => inputs[e.name] = e);
outputs[selectSingleOutput.name] = selectSingleOutput;
}
return { queries, mutations, inputs, types: outputs };
};
// src/util/builders/pg.ts
var import_drizzle_orm5 = require("drizzle-orm");
var import_pg_core2 = require("drizzle-orm/pg-core");
var import_graphql5 = require("graphql");
var import_graphql_parse_resolve_info2 = require("graphql-parse-resolve-info");
var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filterArgs) => {
const queryName = `${uncapitalize(tableName)}`;
const queryBase = db.query[tableName];
if (!queryBase) {
throw new Error(
`Drizzle-GraphQL Error: Table ${tableName} not found in drizzle instance. Did you forget to pass schema to drizzle constructor?`
);
}
const queryArgs = {
offset: {
type: import_graphql5.GraphQLInt
},
limit: {
type: import_graphql5.GraphQLInt
},
orderBy: {
type: orderArgs
},
where: {
type: filterArgs
}
};
const typeName = `${capitalize(tableName)}SelectItem`;
const table = tables[tableName];
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { offset, limit, orderBy, where } = args;
const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, {
deep: true
});
const query = queryBase.findMany({
columns: extractSelectedColumnsFromTree(
parsedInfo.fieldsByTypeName[typeName],
table
),
/*extractSelectedColumnsFromNode(tableSelection, info.fragments, table) */
offset,
limit,
orderBy: orderBy ? extractOrderBy(table, orderBy) : void 0,
where: where ? extractFilters(table, tableName, where) : void 0,
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName) : void 0
});
const result = await query;
return remapToGraphQLArrayOutput(result, tableName, table, relationMap);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql5.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filterArgs) => {
const queryName = `${uncapitalize(tableName)}Single`;
const queryBase = db.query[tableName];
if (!queryBase) {
throw new Error(
`Drizzle-GraphQL Error: Table ${tableName} not found in drizzle instance. Did you forget to pass schema to drizzle constructor?`
);
}
const queryArgs = {
offset: {
type: import_graphql5.GraphQLInt
},
orderBy: {
type: orderArgs
},
where: {
type: filterArgs
}
};
const typeName = `${capitalize(tableName)}SelectItem`;
const table = tables[tableName];
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { offset, orderBy, where } = args;
const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, {
deep: true
});
const query = queryBase.findFirst({
columns: extractSelectedColumnsFromTree(
parsedInfo.fieldsByTypeName[typeName],
table
),
offset,
orderBy: orderBy ? extractOrderBy(table, orderBy) : void 0,
where: where ? extractFilters(table, tableName, where) : void 0,
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName) : void 0
});
const result = await query;
if (!result)
return void 0;
return remapToGraphQLSingleOutput(result, tableName, table, relationMap);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql5.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateInsertArray2 = (db, tableName, table, baseType) => {
const queryName = `insertInto${capitalize(tableName)}`;
const typeName = `${capitalize(tableName)}Item`;
const queryArgs = {
values: {
type: new import_graphql5.GraphQLNonNull(new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(baseType)))
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const input = remapFromGraphQLArrayInput(args.values, table);
if (!input.length)
throw new import_graphql5.GraphQLError("No values were provided!");
const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, {
deep: true
});
const columns = extractSelectedColumnsFromTreeSQLFormat(
parsedInfo.fieldsByTypeName[typeName],
table
);
const result = await db.insert(table).values(input).returning(columns).onConflictDoNothing();
return remapToGraphQLArrayOutput(result, tableName, table);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql5.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateInsertSingle2 = (db, tableName, table, baseType) => {
const queryName = `insertInto${capitalize(tableName)}Single`;
const typeName = `${capitalize(tableName)}Item`;
const queryArgs = {
values: {
type: new import_graphql5.GraphQLNonNull(baseType)
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const input = remapFromGraphQLSingleInput(args.values, table);
const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, {
deep: true
});
const columns = extractSelectedColumnsFromTreeSQLFormat(
parsedInfo.fieldsByTypeName[typeName],
table
);
const result = await db.insert(table).values(input).returning(columns).onConflictDoNothing();
if (!result[0])
return void 0;
return remapToGraphQLSingleOutput(result[0], tableName, table);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql5.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateUpdate2 = (db, tableName, table, setArgs, filterArgs) => {
const queryName = `update${capitalize(tableName)}`;
const typeName = `${capitalize(tableName)}Item`;
const queryArgs = {
set: {
type: new import_graphql5.GraphQLNonNull(setArgs)
},
where: {
type: filterArgs
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { where, set } = args;
const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, {
deep: true
});
const columns = extractSelectedColumnsFromTreeSQLFormat(
parsedInfo.fieldsByTypeName[typeName],
table
);
const input = remapFromGraphQLSingleInput(set, table);
if (!Object.keys(input).length)
throw new import_graphql5.GraphQLError("Unable to update with no values specified!");
let query = db.update(table).set(input);
if (where) {
const filters = extractFilters(table, tableName, where);
query = query.where(filters);
}
query = query.returning(columns);
const result = await query;
return remapToGraphQLArrayOutput(result, tableName, table);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql5.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateDelete2 = (db, tableName, table, filterArgs) => {
const queryName = `deleteFrom${capitalize(tableName)}`;
const typeName = `${capitalize(tableName)}Item`;
const queryArgs = {
where: {
type: filterArgs
}
};
return {
name: queryName,
resolver: async (source, args, context, info) => {
try {
const { where } = args;
const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, {
deep: true
});
const columns = extractSelectedColumnsFromTreeSQLFormat(
parsedInfo.fieldsByTypeName[typeName],
table
);
let query = db.delete(table);
if (where) {
const filters = extractFilters(table, tableName, where);
query = query.where(filters);
}
query = query.returning(columns);
const result = await query;
return remapToGraphQLArrayOutput(result, tableName, table);
} catch (e) {
if (typeof e === "object" && typeof e.message === "string") {
throw new import_graphql5.GraphQLError(e.message);
}
throw e;
}
},
args: queryArgs
};
};
var generateSchemaData2 = (db, schema, relationsDepthLimit) => {
const rawSchema = schema;
const schemaEntries = Object.entries(rawSchema);
const tableEntries = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm5.is)(value, import_pg_core2.PgTable));
const tables = Object.fromEntries(tableEntries);
if (!tableEntries.length) {
throw new Error(
"Drizzle-GraphQL Error: No tables detected in Drizzle-ORM's database instance. Did you forget to pass schema to drizzle constructor?"
);
}
const rawRelations = schemaEntries.filter(([key, value]) => (0, import_drizzle_orm5.is)(value, import_drizzle_orm5.Relations)).map(([key, value]) => [
tableEntries.find(
([tableName, tableValue]) => tableValue === value.table
)[0],
value
]).map(([tableName, relValue]) => [
tableName,
relValue.config((0, import_drizzle_orm5.createTableRelationsHelpers)(tables[tableName]))
]);
const namedRelations = Object.fromEntries(
rawRelations.map(([relName, config]) => {
const namedConfig = Object.fromEntries(
Object.entries(config).map(([innerRelName, innerRelValue]) => [innerRelName, {
relation: innerRelValue,
targetTableName: tableEntries.find(
([tableName, tableValue]) => tableValue === innerRelValue.referencedTable
)[0]
}])
);
return [
relName,
namedConfig
];
})
);
const queries = {};
const mutations = {};
const gqlSchemaTypes = Object.fromEntries(
Object.entries(tables).map(([tableName, table]) => [
tableName,
generateTableTypes(tableName, tables, namedRelations, true, relationsDepthLimit)
])
);
const inputs = {};
const outputs = {};
for (const [tableName, tableTypes] of Obje