Try to use drizzle event though
This commit is contained in:
parent
f14e73ac8f
commit
d88eae7230
14 changed files with 1978 additions and 12 deletions
4
lib/db/db.ts
Normal file
4
lib/db/db.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { drizzle } from "drizzle-orm/vercel-postgres";
|
||||
import { sql } from "@vercel/postgres";
|
||||
|
||||
export const db = drizzle(sql);
|
||||
270
lib/db/index.ts
Normal file
270
lib/db/index.ts
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/**
|
||||
* <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}>
|
||||
* <p style={{fontWeight: "normal"}}>Official <a href="https://github.com/drizzle-team/drizzle-orm">Drizzle ORM</a> adapter for Auth.js / NextAuth.js.</p>
|
||||
* <a href="https://github.com/drizzle-team/drizzle-orm">
|
||||
* <img style={{display: "block"}} src="https://pbs.twimg.com/profile_images/1598308842391179266/CtXrfLnk_400x400.jpg" width="38" />
|
||||
* </a>
|
||||
* </div>
|
||||
*
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install next-auth drizzle-orm @next-auth/drizzle-adapter
|
||||
* npm install drizzle-kit --save-dev
|
||||
* ```
|
||||
*
|
||||
* @module @next-auth/drizzle-adapter
|
||||
*/
|
||||
import type { Adapter } from "@auth/nextjs/adapters";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { v4 as uuid } from "uuid";
|
||||
import type { DbClient, Schema } from "./schema";
|
||||
|
||||
/**
|
||||
* ## Setup
|
||||
*
|
||||
* Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object:
|
||||
*
|
||||
* ```js title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import GoogleProvider from "next-auth/providers/google"
|
||||
* import { DrizzleAdapter } from "@next-auth/drizzle-adapter"
|
||||
* import { db } from "./db-schema"
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: DrizzleAdapter(db),
|
||||
* providers: [
|
||||
* GoogleProvider({
|
||||
* clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
* clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
* }),
|
||||
* ],
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* ## Advanced usage
|
||||
*
|
||||
* ### Create the Drizzle schema from scratch
|
||||
*
|
||||
* You'll need to create a database schema that includes the minimal schema for a `next-auth` adapter.
|
||||
* Be sure to use the Drizzle driver version that you're using for your project.
|
||||
*
|
||||
* > This schema is adapted for use in Drizzle and based upon our main [schema](https://authjs.dev/reference/adapters#models)
|
||||
*
|
||||
*
|
||||
* ```json title="db-schema.ts"
|
||||
*
|
||||
* import { integer, pgTable, text, primaryKey } from 'drizzle-orm/pg-core';
|
||||
* import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
* import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
||||
* import { Pool } from 'pg'
|
||||
* import { ProviderType } from 'next-auth/providers';
|
||||
*
|
||||
* export const users = pgTable('users', {
|
||||
* id: text('id').notNull().primaryKey(),
|
||||
* name: text('name'),
|
||||
* email: text("email").notNull(),
|
||||
* emailVerified: integer("emailVerified"),
|
||||
* image: text("image"),
|
||||
* });
|
||||
*
|
||||
* export const accounts = pgTable("accounts", {
|
||||
* userId: text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
|
||||
* type: text("type").$type<ProviderType>().notNull(),
|
||||
* provider: text("provider").notNull(),
|
||||
* providerAccountId: text("providerAccountId").notNull(),
|
||||
* refresh_token: text("refresh_token"),
|
||||
* access_token: text("access_token"),
|
||||
* expires_at: integer("expires_at"),
|
||||
* token_type: text("token_type"),
|
||||
* scope: text("scope"),
|
||||
* id_token: text("id_token"),
|
||||
* session_state: text("session_state"),
|
||||
* }, (account) => ({
|
||||
* _: primaryKey(account.provider, account.providerAccountId)
|
||||
* }))
|
||||
*
|
||||
* export const sessions = pgTable("sessions", {
|
||||
* userId: text("userId").notNull().references(() => users.id, { onDelete: "cascade" }),
|
||||
* sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
* expires: integer("expires").notNull(),
|
||||
* })
|
||||
*
|
||||
* export const verificationTokens = pgTable("verificationToken", {
|
||||
* identifier: text("identifier").notNull(),
|
||||
* token: text("token").notNull(),
|
||||
* expires: integer("expires").notNull()
|
||||
* }, (vt) => ({
|
||||
* _: primaryKey(vt.identifier, vt.token)
|
||||
* }))
|
||||
*
|
||||
* const pool = new Pool({
|
||||
* connectionString: "YOUR_CONNECTION_STRING"
|
||||
* });
|
||||
*
|
||||
* export const db = drizzle(pool);
|
||||
*
|
||||
* migrate(db, { migrationsFolder: "./drizzle" })
|
||||
*
|
||||
* ```
|
||||
*
|
||||
**/
|
||||
export function DrizzleAdapterPg(
|
||||
client: DbClient,
|
||||
{ users, sessions, verificationTokens, accounts }: Schema
|
||||
): Adapter {
|
||||
return {
|
||||
createUser: async (data) => {
|
||||
return client
|
||||
.insert(users)
|
||||
.values({ ...data, id: uuid() })
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
},
|
||||
getUser: async (data) => {
|
||||
return (
|
||||
client
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.id, data))
|
||||
.then((res) => res[0]) ?? null
|
||||
);
|
||||
},
|
||||
getUserByEmail: async (data) => {
|
||||
return (
|
||||
client
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, data))
|
||||
.then((res) => res[0]) ?? null
|
||||
);
|
||||
},
|
||||
createSession: async (data) => {
|
||||
return client
|
||||
.insert(sessions)
|
||||
.values(data)
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
},
|
||||
getSessionAndUser: async (data) => {
|
||||
return (
|
||||
client
|
||||
.select({
|
||||
session: sessions,
|
||||
user: users,
|
||||
})
|
||||
.from(sessions)
|
||||
.where(eq(sessions.sessionToken, data))
|
||||
.innerJoin(users, eq(users.id, sessions.userId))
|
||||
.then((res) => res[0]) ?? null
|
||||
);
|
||||
},
|
||||
updateUser: async (data) => {
|
||||
if (!data.id) {
|
||||
throw new Error("No user id.");
|
||||
}
|
||||
|
||||
return client
|
||||
.update(users)
|
||||
.set(data)
|
||||
.where(eq(users.id, data.id))
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
},
|
||||
updateSession: async (data) => {
|
||||
return client
|
||||
.update(sessions)
|
||||
.set(data)
|
||||
.where(eq(sessions.sessionToken, data.sessionToken))
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
},
|
||||
linkAccount: async (rawAccount) => {
|
||||
const updatedAccount = await client
|
||||
.insert(accounts)
|
||||
.values(rawAccount)
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
|
||||
// Drizzle will return `null` for fields that are not defined.
|
||||
// However, the return type is expecting `undefined`.
|
||||
const account: ReturnType<Adapter["linkAccount"]> = {
|
||||
...updatedAccount,
|
||||
access_token: updatedAccount.access_token ?? undefined,
|
||||
token_type: updatedAccount.token_type ?? undefined,
|
||||
id_token: updatedAccount.id_token ?? undefined,
|
||||
refresh_token: updatedAccount.refresh_token ?? undefined,
|
||||
scope: updatedAccount.scope ?? undefined,
|
||||
expires_at: updatedAccount.expires_at ?? undefined,
|
||||
session_state: updatedAccount.session_state ?? undefined,
|
||||
};
|
||||
|
||||
return account;
|
||||
},
|
||||
getUserByAccount: async (account) => {
|
||||
const user =
|
||||
(await client
|
||||
.select()
|
||||
.from(users)
|
||||
.innerJoin(
|
||||
accounts,
|
||||
and(
|
||||
eq(accounts.providerAccountId, account.providerAccountId),
|
||||
eq(accounts.provider, account.provider)
|
||||
)
|
||||
)
|
||||
.then((res) => res[0])) ?? null;
|
||||
|
||||
return user.users;
|
||||
},
|
||||
deleteSession: async (sessionToken) => {
|
||||
await client
|
||||
.delete(sessions)
|
||||
.where(eq(sessions.sessionToken, sessionToken));
|
||||
},
|
||||
createVerificationToken: async (token) => {
|
||||
return client
|
||||
.insert(verificationTokens)
|
||||
.values(token)
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
},
|
||||
useVerificationToken: async (token) => {
|
||||
try {
|
||||
return (
|
||||
client
|
||||
.delete(verificationTokens)
|
||||
.where(
|
||||
and(
|
||||
eq(verificationTokens.identifier, token.identifier),
|
||||
eq(verificationTokens.token, token.token)
|
||||
)
|
||||
)
|
||||
.returning()
|
||||
.then((res) => res[0]) ?? null
|
||||
);
|
||||
} catch (err) {
|
||||
throw new Error("No verification token found.");
|
||||
}
|
||||
},
|
||||
deleteUser: async (id) => {
|
||||
await client
|
||||
.delete(users)
|
||||
.where(eq(users.id, id))
|
||||
.returning()
|
||||
.then((res) => res[0]);
|
||||
},
|
||||
unlinkAccount: async (account) => {
|
||||
await client
|
||||
.delete(accounts)
|
||||
.where(
|
||||
and(
|
||||
eq(accounts.providerAccountId, account.providerAccountId),
|
||||
eq(accounts.provider, account.provider)
|
||||
)
|
||||
);
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
}
|
||||
18
lib/db/migrate.ts
Normal file
18
lib/db/migrate.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { migrate } from "drizzle-orm/vercel-postgres/migrator";
|
||||
import { db } from "./schema";
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
migrate(db, {
|
||||
migrationsFolder: "lib/db/migrations",
|
||||
})
|
||||
.then(() => {
|
||||
console.log("Migration was succesfull!");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Migration failed:", err);
|
||||
})
|
||||
.finally(() => {
|
||||
console.info("Migration finished");
|
||||
});
|
||||
49
lib/db/migrations/0000_flawless_moondragon.sql
Normal file
49
lib/db/migrations/0000_flawless_moondragon.sql
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
CREATE TABLE IF NOT EXISTS "accounts" (
|
||||
"userId" text NOT NULL,
|
||||
"type" text NOT NULL,
|
||||
"provider" text NOT NULL,
|
||||
"providerAccountId" text NOT NULL,
|
||||
"refresh_token" text,
|
||||
"access_token" text,
|
||||
"expires_at" integer,
|
||||
"token_type" text,
|
||||
"scope" text,
|
||||
"id_token" text,
|
||||
"session_state" text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "accounts" ADD CONSTRAINT "accounts_provider_providerAccountId" PRIMARY KEY("provider","providerAccountId");
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "sessions" (
|
||||
"sessionToken" text PRIMARY KEY NOT NULL,
|
||||
"userId" text NOT NULL,
|
||||
"expires" timestamp NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"name" text,
|
||||
"email" text NOT NULL,
|
||||
"emailVerified" timestamp,
|
||||
"image" text
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "verificationToken" (
|
||||
"identifier" text NOT NULL,
|
||||
"token" text NOT NULL,
|
||||
"expires" timestamp NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "verificationToken" ADD CONSTRAINT "verificationToken_identifier_token" PRIMARY KEY("identifier","token");
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "accounts" ADD CONSTRAINT "accounts_userId_users_id_fk" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_userId_users_id_fk" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
7
lib/db/migrations/0001_colorful_spectrum.sql
Normal file
7
lib/db/migrations/0001_colorful_spectrum.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
ALTER TABLE "accounts" DROP CONSTRAINT "accounts_provider_providerAccountId";
|
||||
ALTER TABLE "verificationToken" DROP CONSTRAINT "verificationToken_identifier_token";
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Account_provider_providerAccountId_key" ON "accounts" ("provider","providerAccountId");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Session_sessionToken_key" ON "sessions" ("sessionToken");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_email_key" ON "users" ("email");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "VerificationToken_identifier_token_key" ON "verificationToken" ("identifier","token");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "VerificationToken_token_key" ON "verificationToken" ("token");
|
||||
227
lib/db/migrations/meta/0000_snapshot.json
Normal file
227
lib/db/migrations/meta/0000_snapshot.json
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
{
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"id": "ea430ef9-8e30-4cb6-9985-d03f43656cf8",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"accounts": {
|
||||
"name": "accounts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"userId": {
|
||||
"name": "userId",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"providerAccountId": {
|
||||
"name": "providerAccountId",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"refresh_token": {
|
||||
"name": "refresh_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"access_token": {
|
||||
"name": "access_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"token_type": {
|
||||
"name": "token_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"scope": {
|
||||
"name": "scope",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"id_token": {
|
||||
"name": "id_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"session_state": {
|
||||
"name": "session_state",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"accounts_userId_users_id_fk": {
|
||||
"name": "accounts_userId_users_id_fk",
|
||||
"tableFrom": "accounts",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {
|
||||
"accounts_provider_providerAccountId": {
|
||||
"name": "accounts_provider_providerAccountId",
|
||||
"columns": [
|
||||
"provider",
|
||||
"providerAccountId"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"name": "sessions",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"sessionToken": {
|
||||
"name": "sessionToken",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"userId": {
|
||||
"name": "userId",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires": {
|
||||
"name": "expires",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"sessions_userId_users_id_fk": {
|
||||
"name": "sessions_userId_users_id_fk",
|
||||
"tableFrom": "sessions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"emailVerified": {
|
||||
"name": "emailVerified",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"image": {
|
||||
"name": "image",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"verificationToken": {
|
||||
"name": "verificationToken",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"identifier": {
|
||||
"name": "identifier",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"token": {
|
||||
"name": "token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires": {
|
||||
"name": "expires",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {
|
||||
"verificationToken_identifier_token": {
|
||||
"name": "verificationToken_identifier_token",
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
252
lib/db/migrations/meta/0001_snapshot.json
Normal file
252
lib/db/migrations/meta/0001_snapshot.json
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
{
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"id": "34122d24-88e0-430e-862c-2168b0f866cb",
|
||||
"prevId": "ea430ef9-8e30-4cb6-9985-d03f43656cf8",
|
||||
"tables": {
|
||||
"accounts": {
|
||||
"name": "accounts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"userId": {
|
||||
"name": "userId",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"providerAccountId": {
|
||||
"name": "providerAccountId",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"refresh_token": {
|
||||
"name": "refresh_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"access_token": {
|
||||
"name": "access_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"token_type": {
|
||||
"name": "token_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"scope": {
|
||||
"name": "scope",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"id_token": {
|
||||
"name": "id_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"session_state": {
|
||||
"name": "session_state",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"Account_provider_providerAccountId_key": {
|
||||
"name": "Account_provider_providerAccountId_key",
|
||||
"columns": [
|
||||
"provider",
|
||||
"providerAccountId"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"accounts_userId_users_id_fk": {
|
||||
"name": "accounts_userId_users_id_fk",
|
||||
"tableFrom": "accounts",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"sessions": {
|
||||
"name": "sessions",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"sessionToken": {
|
||||
"name": "sessionToken",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"userId": {
|
||||
"name": "userId",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires": {
|
||||
"name": "expires",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"Session_sessionToken_key": {
|
||||
"name": "Session_sessionToken_key",
|
||||
"columns": [
|
||||
"sessionToken"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"sessions_userId_users_id_fk": {
|
||||
"name": "sessions_userId_users_id_fk",
|
||||
"tableFrom": "sessions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"emailVerified": {
|
||||
"name": "emailVerified",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"image": {
|
||||
"name": "image",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"User_email_key": {
|
||||
"name": "User_email_key",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {}
|
||||
},
|
||||
"verificationToken": {
|
||||
"name": "verificationToken",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"identifier": {
|
||||
"name": "identifier",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"token": {
|
||||
"name": "token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"expires": {
|
||||
"name": "expires",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"VerificationToken_identifier_token_key": {
|
||||
"name": "VerificationToken_identifier_token_key",
|
||||
"columns": [
|
||||
"identifier",
|
||||
"token"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"VerificationToken_token_key": {
|
||||
"name": "VerificationToken_token_key",
|
||||
"columns": [
|
||||
"token"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {}
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
}
|
||||
}
|
||||
20
lib/db/migrations/meta/_journal.json
Normal file
20
lib/db/migrations/meta/_journal.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1684771069602,
|
||||
"tag": "0000_flawless_moondragon",
|
||||
"breakpoints": false
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "5",
|
||||
"when": 1684771628481,
|
||||
"tag": "0001_colorful_spectrum",
|
||||
"breakpoints": false
|
||||
}
|
||||
]
|
||||
}
|
||||
353
lib/db/schema.ts
Normal file
353
lib/db/schema.ts
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
import {
|
||||
integer,
|
||||
timestamp,
|
||||
pgTable,
|
||||
text,
|
||||
primaryKey,
|
||||
uniqueIndex,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { drizzle } from "drizzle-orm/vercel-postgres";
|
||||
import { sql } from "@vercel/postgres";
|
||||
import { ProviderType } from "@auth/nextjs/providers";
|
||||
|
||||
export const users = pgTable(
|
||||
"users",
|
||||
{
|
||||
id: text("id").notNull().primaryKey(),
|
||||
name: text("name"),
|
||||
email: text("email").notNull(),
|
||||
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
||||
image: text("image"),
|
||||
},
|
||||
(user) => ({
|
||||
emailKey: uniqueIndex("User_email_key").on(user.email),
|
||||
})
|
||||
);
|
||||
|
||||
export const accounts = pgTable(
|
||||
"accounts",
|
||||
{
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
type: text("type").$type<ProviderType>().notNull(),
|
||||
provider: text("provider").notNull(),
|
||||
providerAccountId: text("providerAccountId").notNull(),
|
||||
refresh_token: text("refresh_token"),
|
||||
access_token: text("access_token"),
|
||||
expires_at: integer("expires_at"),
|
||||
token_type: text("token_type"),
|
||||
scope: text("scope"),
|
||||
id_token: text("id_token"),
|
||||
session_state: text("session_state"),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
providerProviderAccountIdKey: uniqueIndex(
|
||||
"Account_provider_providerAccountId_key"
|
||||
).on(table.provider, table.providerAccountId),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export const sessions = pgTable(
|
||||
"sessions",
|
||||
{
|
||||
sessionToken: text("sessionToken").notNull().primaryKey(),
|
||||
userId: text("userId")
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: "cascade" }),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
},
|
||||
(table) => {
|
||||
return {
|
||||
sessionTokenKey: uniqueIndex("Session_sessionToken_key").on(
|
||||
table.sessionToken
|
||||
),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export const verificationTokens = pgTable(
|
||||
"verificationToken",
|
||||
{
|
||||
identifier: text("identifier").notNull(),
|
||||
token: text("token").notNull(),
|
||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
identifierTokenKey: uniqueIndex(
|
||||
"VerificationToken_identifier_token_key"
|
||||
).on(table.identifier, table.token),
|
||||
tokenKey: uniqueIndex("VerificationToken_token_key").on(table.token),
|
||||
})
|
||||
);
|
||||
|
||||
// Connect to Vercel Postgres
|
||||
export const db = drizzle(sql);
|
||||
|
||||
export type DbClient = typeof db;
|
||||
|
||||
export type Schema = {
|
||||
users: typeof users;
|
||||
accounts: typeof accounts;
|
||||
sessions: typeof sessions;
|
||||
verificationTokens: typeof verificationTokens;
|
||||
};
|
||||
// import { sql, eq, and } from "drizzle-orm";
|
||||
// import {
|
||||
// PgDatabase,
|
||||
// QueryResultHKT,
|
||||
// integer,
|
||||
// pgTable,
|
||||
// text,
|
||||
// timestamp,
|
||||
// uniqueIndex,
|
||||
// uuid,
|
||||
// } from "drizzle-orm/pg-core";
|
||||
// import { drizzle } from "drizzle-orm/vercel-postgres";
|
||||
// import { sql as c } from "@vercel/postgres";
|
||||
// import { Adapter, AdapterUser } from "@auth/nextjs/adapters";
|
||||
|
||||
// export const db = drizzle(c);
|
||||
|
||||
// export const users = pgTable(
|
||||
// "users",
|
||||
// {
|
||||
// id: uuid("id")
|
||||
// .notNull()
|
||||
// .primaryKey()
|
||||
// .default(sql`gen_random_uuid()`),
|
||||
// name: text("name"),
|
||||
// email: text("email"),
|
||||
// emailVerified: timestamp("emailVerified", { precision: 3 }),
|
||||
// image: text("image"),
|
||||
// },
|
||||
// (table) => {
|
||||
// return {
|
||||
// emailKey: uniqueIndex("User_email_key").on(table.email),
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
|
||||
// export const verificationTokens = pgTable(
|
||||
// "verification_tokens",
|
||||
// {
|
||||
// identifier: text("identifier").notNull(),
|
||||
// token: text("token").notNull(),
|
||||
// expires: timestamp("expires", { precision: 3 }).notNull(),
|
||||
// },
|
||||
// (table) => {
|
||||
// return {
|
||||
// identifierTokenKey: uniqueIndex(
|
||||
// "VerificationToken_identifier_token_key"
|
||||
// ).on(table.identifier, table.token),
|
||||
// tokenKey: uniqueIndex("VerificationToken_token_key").on(table.token),
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
|
||||
// export const sessions = pgTable(
|
||||
// "sessions",
|
||||
// {
|
||||
// id: uuid("id")
|
||||
// .notNull()
|
||||
// .primaryKey()
|
||||
// .default(sql`gen_random_uuid()`),
|
||||
// sessionToken: text("sessionToken").notNull(),
|
||||
// userId: uuid("userId")
|
||||
// .notNull()
|
||||
// .references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" }),
|
||||
// expires: timestamp("expires", { precision: 3 }).notNull(),
|
||||
// },
|
||||
// (table) => {
|
||||
// return {
|
||||
// sessionTokenKey: uniqueIndex("Session_sessionToken_key").on(
|
||||
// table.sessionToken
|
||||
// ),
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
|
||||
// export const accounts = pgTable(
|
||||
// "accounts",
|
||||
// {
|
||||
// id: uuid("id")
|
||||
// .notNull()
|
||||
// .primaryKey()
|
||||
// .default(sql`gen_random_uuid()`),
|
||||
// userId: uuid("userId")
|
||||
// .notNull()
|
||||
// .references(() => users.id, { onDelete: "cascade", onUpdate: "cascade" }),
|
||||
// type: text("type").notNull(),
|
||||
// provider: text("provider").notNull(),
|
||||
// providerAccountId: text("providerAccountId").notNull(),
|
||||
// refresh_token: text("refresh_token"),
|
||||
// access_token: text("access_token"),
|
||||
// expires_at: integer("expires_at"),
|
||||
// token_type: text("token_type"),
|
||||
// scope: text("scope"),
|
||||
// id_token: text("id_token"),
|
||||
// session_state: text("session_state"),
|
||||
// },
|
||||
// (table) => {
|
||||
// return {
|
||||
// providerProviderAccountIdKey: uniqueIndex(
|
||||
// "Account_provider_providerAccountId_key"
|
||||
// ).on(table.provider, table.providerAccountId),
|
||||
// };
|
||||
// }
|
||||
// );
|
||||
|
||||
// type Users = typeof users;
|
||||
// type Sessions = typeof sessions;
|
||||
// type Accounts = typeof accounts;
|
||||
// type VerificationTokens = typeof verificationTokens;
|
||||
|
||||
// export function DrizzleAdapter<
|
||||
// T extends PgDatabase<U>,
|
||||
// U extends QueryResultHKT
|
||||
// >({
|
||||
// db,
|
||||
// schema,
|
||||
// }: {
|
||||
// db: T;
|
||||
// schema: {
|
||||
// users: Users;
|
||||
// sessions: Sessions;
|
||||
// accounts: Accounts;
|
||||
// verificationTokens: VerificationTokens;
|
||||
// };
|
||||
// }): Adapter {
|
||||
// return {
|
||||
// async createUser(user) {
|
||||
// const [newUser] = await db.insert(schema.users).values(user).returning();
|
||||
|
||||
// return newUser as AdapterUser;
|
||||
// },
|
||||
// async getUser(id) {
|
||||
// const [user] = await db
|
||||
// .select()
|
||||
// .from(schema.users)
|
||||
// .where(eq(schema.users.id, id));
|
||||
|
||||
// return (user as AdapterUser) || null;
|
||||
// },
|
||||
// async getUserByEmail(email) {
|
||||
// const [user] = await db
|
||||
// .select()
|
||||
// .from(schema.users)
|
||||
// .where(eq(schema.users.email, email));
|
||||
|
||||
// return (user as AdapterUser) || null;
|
||||
// },
|
||||
// async getUserByAccount({ providerAccountId, provider }) {
|
||||
// const results = await db
|
||||
// .select()
|
||||
// .from(schema.users)
|
||||
// .leftJoin(schema.accounts, eq(schema.accounts.userId, schema.users.id))
|
||||
// .where(
|
||||
// and(
|
||||
// eq(schema.accounts.provider, provider),
|
||||
// eq(schema.accounts.providerAccountId, providerAccountId)
|
||||
// )
|
||||
// );
|
||||
|
||||
// if (results.length) {
|
||||
// return results[0].users as AdapterUser;
|
||||
// }
|
||||
|
||||
// return null;
|
||||
// },
|
||||
// async updateUser(user) {
|
||||
// const userId = user.id;
|
||||
|
||||
// if (!userId) {
|
||||
// throw new Error("Cannot update user without id");
|
||||
// }
|
||||
|
||||
// const [updatedUser] = await db
|
||||
// .update(schema.users)
|
||||
// .set(user)
|
||||
// .where(eq(schema.users.id, userId))
|
||||
// .returning();
|
||||
|
||||
// return updatedUser as AdapterUser;
|
||||
// },
|
||||
// async deleteUser(userId) {
|
||||
// await db.delete(schema.users).where(eq(schema.users.id, userId));
|
||||
// },
|
||||
// async linkAccount(account) {
|
||||
// await db.insert(schema.accounts).values(account);
|
||||
// },
|
||||
// async unlinkAccount({ providerAccountId, provider }) {
|
||||
// await db
|
||||
// .delete(schema.accounts)
|
||||
// .where(
|
||||
// and(
|
||||
// eq(schema.accounts.provider, provider),
|
||||
// eq(schema.accounts.providerAccountId, providerAccountId)
|
||||
// )
|
||||
// );
|
||||
// },
|
||||
// async createSession(session) {
|
||||
// const [newSession] = await db
|
||||
// .insert(schema.sessions)
|
||||
// .values(session)
|
||||
// .returning();
|
||||
|
||||
// return newSession;
|
||||
// },
|
||||
// async getSessionAndUser(sessionToken) {
|
||||
// const results = await db
|
||||
// .select()
|
||||
// .from(schema.sessions)
|
||||
// .leftJoin(schema.users, eq(schema.users.id, schema.sessions.userId))
|
||||
// .where(eq(schema.sessions.sessionToken, sessionToken));
|
||||
|
||||
// if (results.length) {
|
||||
// return {
|
||||
// user: results[0].users! as AdapterUser,
|
||||
// session: results[0].sessions,
|
||||
// };
|
||||
// }
|
||||
|
||||
// return null;
|
||||
// },
|
||||
// async updateSession(session) {
|
||||
// const [updatedSession] = await db
|
||||
// .update(schema.sessions)
|
||||
// .set(session)
|
||||
// .where(eq(schema.sessions.sessionToken, session.sessionToken))
|
||||
// .returning();
|
||||
|
||||
// return updatedSession;
|
||||
// },
|
||||
// async deleteSession(sessionToken) {
|
||||
// await db
|
||||
// .delete(schema.sessions)
|
||||
// .where(eq(schema.sessions.sessionToken, sessionToken));
|
||||
// },
|
||||
// async createVerificationToken(token) {
|
||||
// const [newVerificationToken] = await db
|
||||
// .insert(schema.verificationTokens)
|
||||
// .values(token)
|
||||
// .returning();
|
||||
|
||||
// return newVerificationToken;
|
||||
// },
|
||||
// async useVerificationToken({ identifier, token }) {
|
||||
// const [deletedVerificationToken] = await db
|
||||
// .delete(schema.verificationTokens)
|
||||
// .where(
|
||||
// and(
|
||||
// eq(schema.verificationTokens.identifier, identifier),
|
||||
// eq(schema.verificationTokens.token, token)
|
||||
// )
|
||||
// )
|
||||
// .returning();
|
||||
|
||||
// return deletedVerificationToken || null;
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
Loading…
Add table
Add a link
Reference in a new issue