Skip to content

Commit aecc221

Browse files
realmikesolondom91balazsorban44noam-honig
authored
fix(drizzle): update schema type & fix issue with default id (#10750)
Co-authored-by: Nico Domino <[email protected]> Co-authored-by: Balázs Orbán <[email protected]> Co-authored-by: Noam Honig <[email protected]>
1 parent ddd8209 commit aecc221

File tree

17 files changed

+338
-311
lines changed

17 files changed

+338
-311
lines changed

docs/pages/getting-started/adapters/drizzle.mdx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ To use this adapter, you must have setup Drizzle ORM and Drizzle Kit in your pro
3535
2. Install a supported database driver to your project, like `@libsql/client`, `mysql2` or `postgres`.
3636
3. Create a `drizzle.config.ts` [file](https://orm.drizzle.team/kit-docs/conf).
3737
4. Generate the initial migration from your schema file with a command like, `drizzle-kit generate:pg`.
38-
5. Push that migration to your configured database with a command like, `drizzle-kit push:pg`.
38+
5. Apply migrations by using `migrate()` function or push changes directly to your database with a command like, `drizzle-kit push:pg`.
39+
6. If your schemas differ from the default ones, pass them as the second parameter to the adapter.
3940

4041
#### Schemas
4142

@@ -53,7 +54,7 @@ import {
5354
} from "drizzle-orm/pg-core"
5455
import postgres from "postgres"
5556
import { drizzle } from "drizzle-orm/postgres-js"
56-
import type { AdapterAccount } from "next-auth/adapters"
57+
import type { AdapterAccountType } from "@auth/core/adapters"
5758

5859
const connectionString = "postgres://postgres:postgres@localhost:5432/drizzle"
5960
const pool = postgres(connectionString, { max: 1 })
@@ -76,7 +77,7 @@ export const accounts = pgTable(
7677
userId: text("userId")
7778
.notNull()
7879
.references(() => users.id, { onDelete: "cascade" }),
79-
type: text("type").$type<AdapterAccount["type"]>().notNull(),
80+
type: text("type").$type<AdapterAccountType>().notNull(),
8081
provider: text("provider").notNull(),
8182
providerAccountId: text("providerAccountId").notNull(),
8283
refresh_token: text("refresh_token"),
@@ -129,7 +130,7 @@ import {
129130
} from "drizzle-orm/mysql-core"
130131
import mysql from "mysql2/promise"
131132
import { drizzle } from "drizzle-orm/mysql2"
132-
import type { AdapterAccount } from "next-auth/adapters"
133+
import type { AdapterAccountType } from "@auth/core/adapters"
133134

134135
export const connection = await mysql.createConnection({
135136
host: "host",
@@ -160,7 +161,7 @@ export const accounts = mysqlTable(
160161
.notNull()
161162
.references(() => users.id, { onDelete: "cascade" }),
162163
type: varchar("type", { length: 255 })
163-
.$type<AdapterAccount["type"]>()
164+
.$type<AdapterAccountType>()
164165
.notNull(),
165166
provider: varchar("provider", { length: 255 }).notNull(),
166167
providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
@@ -208,7 +209,7 @@ If you want to modify the schema or add additional fields, you can use the follo
208209
import { integer, sqliteTable, text, primaryKey } from "drizzle-orm/sqlite-core"
209210
import { createClient } from "@libsql/client"
210211
import { drizzle } from "drizzle-orm/libsql"
211-
import type { AdapterAccount } from "next-auth/adapters"
212+
import type { AdapterAccountType } from "@auth/core/adapters"
212213

213214
const client = createClient({
214215
url: "DATABASE_URL",
@@ -232,7 +233,7 @@ export const accounts = sqliteTable(
232233
userId: text("userId")
233234
.notNull()
234235
.references(() => users.id, { onDelete: "cascade" }),
235-
type: text("type").$type<AdapterAccount["type"]>().notNull(),
236+
type: text("type").$type<AdapterAccountType>().notNull(),
236237
provider: text("provider").notNull(),
237238
providerAccountId: text("providerAccountId").notNull(),
238239
refresh_token: text("refresh_token"),

packages/adapter-drizzle/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
"@types/uuid": "^8.3.3",
5454
"better-sqlite3": "^9.4.0",
5555
"drizzle-kit": "^0.20.17",
56-
"drizzle-orm": "^0.30.8",
56+
"drizzle-orm": "^0.30.9",
5757
"mysql2": "^3.9.7",
5858
"postgres": "^3.4.3",
5959
"tsx": "^4.7.0"

packages/adapter-drizzle/src/index.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,10 @@ import type { Adapter } from "@auth/core/adapters"
8383
* primaryKey,
8484
* integer
8585
* } from "drizzle-orm/pg-core"
86-
* import type { AdapterAccount } from '@auth/core/adapters'
87-
* import { randomUUID } from "crypto"
86+
* import type { AdapterAccountType } from '@auth/core/adapters'
8887
*
8988
* export const users = pgTable("user", {
90-
* id: text("id").primaryKey().$defaultFn(() => randomUUID()),
89+
* id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
9190
* name: text("name"),
9291
* email: text("email").notNull(),
9392
* emailVerified: timestamp("emailVerified", { mode: "date" }),
@@ -100,7 +99,7 @@ import type { Adapter } from "@auth/core/adapters"
10099
* userId: text("userId")
101100
* .notNull()
102101
* .references(() => users.id, { onDelete: "cascade" }),
103-
* type: text("type").notNull(),
102+
* type: text("type").$type<AdapterAccountType>().notNull(),
104103
* provider: text("provider").notNull(),
105104
* providerAccountId: text("providerAccountId").notNull(),
106105
* refresh_token: text("refresh_token"),
@@ -149,10 +148,10 @@ import type { Adapter } from "@auth/core/adapters"
149148
* primaryKey,
150149
* varchar,
151150
* } from "drizzle-orm/mysql-core"
152-
* import type { AdapterAccount } from "@auth/core/adapters"
151+
* import type { AdapterAccountType } from "@auth/core/adapters"
153152
*
154153
* export const users = mysqlTable("user", {
155-
* id: varchar("id", { length: 255 }).primaryKey().$defaultFn(() => randomUUID()),
154+
* id: varchar("id", { length: 255 }).primaryKey().$defaultFn(() => crypto.randomUUID()),
156155
* name: varchar("name", { length: 255 }),
157156
* email: varchar("email", { length: 255 }).notNull(),
158157
* emailVerified: timestamp("emailVerified", { mode: "date", fsp: 3 }),
@@ -165,7 +164,7 @@ import type { Adapter } from "@auth/core/adapters"
165164
* userId: varchar("userId", { length: 255 })
166165
* .notNull()
167166
* .references(() => users.id, { onDelete: "cascade" }),
168-
* type: varchar("type", { length: 255 }).notNull(),
167+
* type: varchar("type", { length: 255 }).$type<AdapterAccountType>().notNull(),
169168
* provider: varchar("provider", { length: 255 }).notNull(),
170169
* providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
171170
* refresh_token: varchar("refresh_token", { length: 255 }),
@@ -208,10 +207,10 @@ import type { Adapter } from "@auth/core/adapters"
208207
*
209208
* ```ts title="schema.ts"
210209
* import { integer, sqliteTable, text, primaryKey } from "drizzle-orm/sqlite-core"
211-
* import type { AdapterAccount } from "@auth/core/adapters"
210+
* import type { AdapterAccountType } from "@auth/core/adapters"
212211
*
213212
* export const users = sqliteTable("user", {
214-
* id: text("id").primaryKey().$defaultFn(() => randomUUID()),
213+
* id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
215214
* name: text("name"),
216215
* email: text("email").notNull(),
217216
* emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
@@ -224,7 +223,7 @@ import type { Adapter } from "@auth/core/adapters"
224223
* userId: text("userId")
225224
* .notNull()
226225
* .references(() => users.id, { onDelete: "cascade" }),
227-
* type: text("type").notNull(),
226+
* type: text("type").$type<AdapterAccountType>().notNull(),
228227
* provider: text("provider").notNull(),
229228
* providerAccountId: text("providerAccountId").notNull(),
230229
* refresh_token: text("refresh_token"),

packages/adapter-drizzle/src/lib/mysql.ts

Lines changed: 80 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,86 +15,104 @@ import {
1515
import type {
1616
Adapter,
1717
AdapterAccount,
18+
AdapterAccountType,
1819
AdapterSession,
1920
AdapterUser,
2021
VerificationToken,
2122
} from "@auth/core/adapters"
2223

23-
export const mysqlUsersTable = mysqlTable("user", {
24-
id: varchar("id", { length: 255 })
25-
.primaryKey()
26-
.$defaultFn(() => crypto.randomUUID()),
27-
name: varchar("name", { length: 255 }),
28-
email: varchar("email", { length: 255 }).notNull(),
29-
emailVerified: timestamp("emailVerified", { mode: "date", fsp: 3 }),
30-
image: varchar("image", { length: 255 }),
31-
}) satisfies DefaultMySqlUsersTable
24+
export function defineTables(
25+
schema: Partial<DefaultMySqlSchema> = {}
26+
): Required<DefaultMySqlSchema> {
27+
const usersTable =
28+
schema.usersTable ??
29+
(mysqlTable("user", {
30+
id: varchar("id", { length: 255 })
31+
.primaryKey()
32+
.$defaultFn(() => crypto.randomUUID()),
33+
name: varchar("name", { length: 255 }),
34+
email: varchar("email", { length: 255 }).notNull(),
35+
emailVerified: timestamp("emailVerified", { mode: "date", fsp: 3 }),
36+
image: varchar("image", { length: 255 }),
37+
}) satisfies DefaultMySqlUsersTable)
3238

33-
export const mysqlAccountsTable = mysqlTable(
34-
"account",
35-
{
36-
userId: varchar("userId", { length: 255 })
37-
.notNull()
38-
.references(() => mysqlUsersTable.id, { onDelete: "cascade" }),
39-
type: varchar("type", { length: 255 })
40-
.$type<AdapterAccount["type"]>()
41-
.notNull(),
42-
provider: varchar("provider", { length: 255 }).notNull(),
43-
providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
44-
refresh_token: varchar("refresh_token", { length: 255 }),
45-
access_token: varchar("access_token", { length: 255 }),
46-
expires_at: int("expires_at"),
47-
token_type: varchar("token_type", { length: 255 }),
48-
scope: varchar("scope", { length: 255 }),
49-
id_token: varchar("id_token", { length: 2048 }),
50-
session_state: varchar("session_state", { length: 255 }),
51-
},
52-
(account) => ({
53-
compositePk: primaryKey({
54-
columns: [account.provider, account.providerAccountId],
55-
}),
56-
})
57-
) satisfies DefaultMySqlAccountsTable
39+
const accountsTable =
40+
schema.accountsTable ??
41+
(mysqlTable(
42+
"account",
43+
{
44+
userId: varchar("userId", { length: 255 })
45+
.notNull()
46+
.references(() => usersTable.id, { onDelete: "cascade" }),
47+
type: varchar("type", { length: 255 })
48+
.$type<AdapterAccountType>()
49+
.notNull(),
50+
provider: varchar("provider", { length: 255 }).notNull(),
51+
providerAccountId: varchar("providerAccountId", {
52+
length: 255,
53+
}).notNull(),
54+
refresh_token: varchar("refresh_token", { length: 255 }),
55+
access_token: varchar("access_token", { length: 255 }),
56+
expires_at: int("expires_at"),
57+
token_type: varchar("token_type", { length: 255 }),
58+
scope: varchar("scope", { length: 255 }),
59+
id_token: varchar("id_token", { length: 2048 }),
60+
session_state: varchar("session_state", { length: 255 }),
61+
},
62+
(account) => ({
63+
compositePk: primaryKey({
64+
columns: [account.provider, account.providerAccountId],
65+
}),
66+
})
67+
) satisfies DefaultMySqlAccountsTable)
5868

59-
export const mysqlSessionsTable = mysqlTable("session", {
60-
sessionToken: varchar("sessionToken", { length: 255 }).primaryKey(),
61-
userId: varchar("userId", { length: 255 })
62-
.notNull()
63-
.references(() => mysqlUsersTable.id, { onDelete: "cascade" }),
64-
expires: timestamp("expires", { mode: "date" }).notNull(),
65-
}) satisfies DefaultMySqlSessionsTable
69+
const sessionsTable =
70+
schema.sessionsTable ??
71+
(mysqlTable("session", {
72+
sessionToken: varchar("sessionToken", { length: 255 }).primaryKey(),
73+
userId: varchar("userId", { length: 255 })
74+
.notNull()
75+
.references(() => usersTable.id, { onDelete: "cascade" }),
76+
expires: timestamp("expires", { mode: "date" }).notNull(),
77+
}) satisfies DefaultMySqlSessionsTable)
6678

67-
export const mysqlVerificationTokensTable = mysqlTable(
68-
"verificationToken",
69-
{
70-
identifier: varchar("identifier", { length: 255 }).notNull(),
71-
token: varchar("token", { length: 255 }).notNull(),
72-
expires: timestamp("expires", { mode: "date" }).notNull(),
73-
},
74-
(vt) => ({
75-
compositePk: primaryKey({ columns: [vt.identifier, vt.token] }),
76-
})
77-
) satisfies DefaultMySqlVerificationTokenTable
79+
const verificationTokensTable =
80+
schema.verificationTokensTable ??
81+
(mysqlTable(
82+
"verificationToken",
83+
{
84+
identifier: varchar("identifier", { length: 255 }).notNull(),
85+
token: varchar("token", { length: 255 }).notNull(),
86+
expires: timestamp("expires", { mode: "date" }).notNull(),
87+
},
88+
(vt) => ({
89+
compositePk: primaryKey({ columns: [vt.identifier, vt.token] }),
90+
})
91+
) satisfies DefaultMySqlVerificationTokenTable)
92+
93+
return {
94+
usersTable,
95+
accountsTable,
96+
sessionsTable,
97+
verificationTokensTable,
98+
}
99+
}
78100

79101
export function MySqlDrizzleAdapter(
80102
client: MySqlDatabase<QueryResultHKT, PreparedQueryHKTBase, any>,
81-
schema: DefaultMySqlSchema = {
82-
usersTable: mysqlUsersTable,
83-
accountsTable: mysqlAccountsTable,
84-
sessionsTable: mysqlSessionsTable,
85-
verificationTokensTable: mysqlVerificationTokensTable,
86-
}
103+
schema?: DefaultMySqlSchema
87104
): Adapter {
88105
const { usersTable, accountsTable, sessionsTable, verificationTokensTable } =
89-
schema
106+
defineTables(schema)
90107

91108
return {
92109
async createUser(data: AdapterUser) {
110+
const { id, ...insertData } = data
93111
const hasDefaultId = getTableColumns(usersTable)["id"]["hasDefault"]
94112

95113
await client
96114
.insert(usersTable)
97-
.values(hasDefaultId ? data : { ...data, id: crypto.randomUUID() })
115+
.values(hasDefaultId ? insertData : { ...insertData, id })
98116

99117
return client
100118
.select()
@@ -442,6 +460,6 @@ export type DefaultMySqlVerificationTokenTable = MySqlTableWithColumns<{
442460
export type DefaultMySqlSchema = {
443461
usersTable: DefaultMySqlUsersTable
444462
accountsTable: DefaultMySqlAccountsTable
445-
sessionsTable: DefaultMySqlSessionsTable
446-
verificationTokensTable: DefaultMySqlVerificationTokenTable
463+
sessionsTable?: DefaultMySqlSessionsTable
464+
verificationTokensTable?: DefaultMySqlVerificationTokenTable
447465
}

0 commit comments

Comments
 (0)