Files
better-auth/docs/lib/copy-schema/adapter/prisma.ts

119 lines
3.6 KiB
TypeScript

import type { Resolver } from "../types";
import {
capitalize,
filterNonUniqueIndexes,
getIndexName,
getTypeFactory,
} from "../utils";
export type PrismaResolverOptions = {
/**
* @default "postgresql"
*/
provider?:
| "sqlite"
| "cockroachdb"
| "mysql"
| "postgresql"
| "sqlserver"
| "mongodb";
usePlural?: boolean;
};
export const prismaResolver = (options: PrismaResolverOptions): Resolver => {
const provider = options.provider ?? "postgresql";
return {
language: "prisma",
handler: (ctx) => {
const getType = getTypeFactory((field) => {
let string = "String";
let id = ctx.useNumberId && provider !== "mongodb" ? "Int" : "String";
let foreignKeyId =
ctx.useNumberId && provider !== "mongodb" ? "Int" : "String";
if (field.required === false) {
string += "?";
id += "?";
foreignKeyId += "?";
}
id += ` @id${ctx.useNumberId || provider === "mongodb" ? ` @default(${provider === "mongodb" ? "auto()" : "autoincrement()"})` : ""}`;
if (provider === "mongodb") {
if (field.unique) {
string += " @db.VarChar(255)";
} else if (field.references) {
string += " @db.VarChar(36)";
}
id += ` @map("_id") @db.ObjectId`;
foreignKeyId += " @db.ObjectId";
}
// Only PostgreSQL, CockroachDB, and MongoDB support Prisma scalar
// lists. They cannot be nullable (`String[]?` is invalid) and
// default to an empty list, so `@default([])` is emitted to match
// the generated schema. The other providers have no array type, so
// the adapter stores these as a JSON string in a plain `String`.
const supportsScalarList =
provider === "postgresql" ||
provider === "cockroachdb" ||
provider === "mongodb";
return {
string,
boolean: `Boolean${field.required === false ? "?" : ""}`,
number: `${field.bigint ? "BigInt" : "Int"}${field.required === false ? "?" : ""}`,
date: `DateTime${field.required === false ? "?" : ""}`,
json: `Json${field.required === false ? "?" : ""}`,
id,
"string[]": supportsScalarList ? "String[] @default([])" : "String",
"number[]": supportsScalarList
? `${field.bigint ? "BigInt" : "Int"}[] @default([])`
: "String",
foreignKeyId,
};
});
const lines = [
`model ${capitalize(ctx.schema.modelName)}${options.usePlural ? "s" : ""} {`,
];
if (ctx.mode === "alter") {
lines.push("\t// ...existing fields");
}
for (const field of ctx.schema.fields) {
const type = getType(field);
let newLine = `${field.fieldName} ${type}`;
let additionalLine = "";
if (field.type === "date" && provider === "postgresql") {
newLine += " @db.Timestamptz(3)";
}
if (field.unique) {
newLine += " @unique";
}
if (field.references) {
const fieldName = field.fieldName.endsWith("Id")
? field.fieldName.slice(0, -2)
: capitalize(field.fieldName);
let dataType = capitalize(field.references.model);
if (field.required === false) {
dataType += "?";
}
additionalLine = `${fieldName} ${dataType}${options.usePlural ? "s" : ""} @relation(fields: [${field.fieldName}], references: [${field.references.field}])`;
}
if (additionalLine !== "") {
lines.push(`\t${additionalLine}`);
}
lines.push(`\t${newLine}`);
}
for (const field of filterNonUniqueIndexes(ctx.schema)) {
lines.push(
`\t@@index([${field.fieldName}], map: "${getIndexName(ctx.schema.modelName, field)}")`,
);
}
lines.push(
`\t@@map("${ctx.schema.modelName}${options.usePlural ? "s" : ""}")`,
);
lines.push("}");
return lines.join("\n");
},
};
};