fix(drizzle-cli): use serial as PK when useNumberId is enabled (#3228)

This commit is contained in:
Abbas
2025-06-30 18:36:23 -07:00
committed by GitHub
parent 7c4719ed77
commit 12e15cce41
3 changed files with 104 additions and 3 deletions
+16 -3
View File
@@ -3,6 +3,7 @@ import {
type BetterAuthDbSchema,
type FieldAttribute,
} from "better-auth/db";
import type { BetterAuthOptions } from "better-auth/types";
import { existsSync } from "fs";
import type { SchemaGenerator } from "./types";
@@ -27,7 +28,7 @@ export const generateDrizzleSchema: SchemaGenerator = async ({
}
const fileExist = existsSync(filePath);
let code: string = generateImport({ databaseType, tables });
let code: string = generateImport({ databaseType, tables, options });
for (const tableKey in tables) {
const table = tables[tableKey]!;
@@ -117,7 +118,11 @@ export const generateDrizzleSchema: SchemaGenerator = async ({
let id: string = "";
if (options.advanced?.database?.useNumberId) {
id = `int("id").autoincrement.primaryKey()`;
if (databaseType === "pg") {
id = `serial("id").primaryKey()`;
} else {
id = `int("id").autoincrement.primaryKey()`;
}
} else {
if (databaseType === "mysql") {
id = `varchar('id', { length: 36 }).primaryKey()`;
@@ -173,13 +178,20 @@ export const generateDrizzleSchema: SchemaGenerator = async ({
function generateImport({
databaseType,
tables,
}: { databaseType: "sqlite" | "mysql" | "pg"; tables: BetterAuthDbSchema }) {
options,
}: {
databaseType: "sqlite" | "mysql" | "pg";
tables: BetterAuthDbSchema;
options: BetterAuthOptions;
}) {
let imports: string[] = [];
const hasBigint = Object.values(tables).some((table) =>
Object.values(table.fields).some((field) => field.bigint),
);
const useNumberId = options.advanced?.database?.useNumberId;
imports.push(`${databaseType}Table`);
imports.push(
databaseType === "mysql"
@@ -191,6 +203,7 @@ function generateImport({
imports.push(hasBigint ? (databaseType !== "sqlite" ? "bigint" : "") : "");
imports.push(databaseType !== "sqlite" ? "timestamp, boolean" : "");
imports.push(databaseType === "mysql" ? "int" : "integer");
imports.push(useNumberId ? (databaseType === "pg" ? "serial" : "") : "");
return `import { ${imports
.map((x) => x.trim())
@@ -0,0 +1,57 @@
import { pgTable, text, timestamp, boolean, integer, serial } from "drizzle-orm/pg-core";
export const user = pgTable("user", {
id: serial("id").primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
emailVerified: boolean('email_verified').$defaultFn(() => false).notNull(),
image: text('image'),
createdAt: timestamp('created_at').$defaultFn(() => /* @__PURE__ */ new Date()).notNull(),
updatedAt: timestamp('updated_at').$defaultFn(() => /* @__PURE__ */ new Date()).notNull(),
twoFactorEnabled: boolean('two_factor_enabled'),
username: text('username').unique(),
displayUsername: text('display_username')
});
export const session = pgTable("session", {
id: serial("id").primaryKey(),
expiresAt: timestamp('expires_at').notNull(),
token: text('token').notNull().unique(),
createdAt: timestamp('created_at').notNull(),
updatedAt: timestamp('updated_at').notNull(),
ipAddress: text('ip_address'),
userAgent: text('user_agent'),
userId: serial('user_id').primaryKey().notNull().references(()=> user.id, { onDelete: 'cascade' })
});
export const account = pgTable("account", {
id: serial("id").primaryKey(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
userId: serial('user_id').primaryKey().notNull().references(()=> user.id, { onDelete: 'cascade' }),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
idToken: text('id_token'),
accessTokenExpiresAt: timestamp('access_token_expires_at'),
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
scope: text('scope'),
password: text('password'),
createdAt: timestamp('created_at').notNull(),
updatedAt: timestamp('updated_at').notNull()
});
export const verification = pgTable("verification", {
id: serial("id").primaryKey(),
identifier: text('identifier').notNull(),
value: text('value').notNull(),
expiresAt: timestamp('expires_at').notNull(),
createdAt: timestamp('created_at').$defaultFn(() => /* @__PURE__ */ new Date()),
updatedAt: timestamp('updated_at').$defaultFn(() => /* @__PURE__ */ new Date())
});
export const twoFactor = pgTable("two_factor", {
id: serial("id").primaryKey(),
secret: text('secret').notNull(),
backupCodes: text('backup_codes').notNull(),
userId: serial('user_id').primaryKey().notNull().references(()=> user.id, { onDelete: 'cascade' })
});
+31
View File
@@ -132,6 +132,37 @@ describe("generate", async () => {
expect(schema.code).toMatchFileSnapshot("./__snapshots__/auth-schema.txt");
});
it("should generate drizzle schema with number id", async () => {
const schema = await generateDrizzleSchema({
file: "test.drizzle",
adapter: drizzleAdapter(
{},
{
provider: "pg",
schema: {},
},
)({} as BetterAuthOptions),
options: {
database: drizzleAdapter(
{},
{
provider: "pg",
schema: {},
},
),
plugins: [twoFactor(), username()],
advanced: {
database: {
useNumberId: true,
},
},
},
});
expect(schema.code).toMatchFileSnapshot(
"./__snapshots__/auth-schema-number-id.txt",
);
});
it("should generate kysely schema", async () => {
const schema = await generateMigrations({
file: "test.sql",