Skip to content

Instantly share code, notes, and snippets.

@Andersgee
Created April 21, 2023 09:22
Show Gist options
  • Save Andersgee/1439dd648eb1ff60855275fef78cb8e5 to your computer and use it in GitHub Desktop.
Save Andersgee/1439dd648eb1ff60855275fef78cb8e5 to your computer and use it in GitHub Desktop.
KyselyAdapter
import type { Kysely } from "kysely";
import type { Adapter } from "next-auth/adapters";
import type { DB } from "kysely-codegen";
/**
* mostly copy pasted from the unmerged kysely adapter PR to next-auth repo
*
* assumes Account, User and Session ids are Int (not String).
*
* converts to/from string only because Adapter expects it that way.
*/
export function KyselyAdapter(db: Kysely<DB>): Adapter {
const adapter = db.getExecutor().adapter;
const supportsReturning = adapter.supportsReturning;
return {
async createUser(user) {
const query = db.insertInto("User").values(user);
const result = supportsReturning
? await query.returningAll().executeTakeFirstOrThrow()
: await query.executeTakeFirstOrThrow().then(async () => {
return await db
.selectFrom("User")
.selectAll()
.where("email", "=", `${user.email}`)
.executeTakeFirstOrThrow();
});
return { ...result, id: String(result.id) };
},
async getUser(id) {
const intId = parseInt(id, 10);
const result =
(await db
.selectFrom("User")
.selectAll()
.where("id", "=", intId)
.executeTakeFirst()) ?? null;
if (!result) return null;
return { ...result, id: String(result.id) };
},
async getUserByEmail(email) {
const result =
(await db
.selectFrom("User")
.selectAll()
.where("email", "=", email)
.executeTakeFirst()) ?? null;
if (!result) return null;
return { ...result, id: String(result.id) };
},
async getUserByAccount({ providerAccountId, provider }) {
const result =
(await db
.selectFrom("User")
.innerJoin("Account", "User.id", "Account.userId")
.selectAll("User")
.where("Account.providerAccountId", "=", providerAccountId)
.where("Account.provider", "=", provider)
.executeTakeFirst()) ?? null;
if (!result) return null;
return { ...result, id: String(result.id) };
},
async updateUser({ id, ...user }) {
if (!id) throw new Error("User not found");
const intId = parseInt(id, 10);
const query = db.updateTable("User").set(user).where("id", "=", intId);
const result = supportsReturning
? await query.returningAll().executeTakeFirstOrThrow()
: await query.executeTakeFirstOrThrow().then(async () => {
return await db
.selectFrom("User")
.selectAll()
.where("id", "=", intId)
.executeTakeFirstOrThrow();
});
return { ...result, id: String(result.id) };
},
async deleteUser(id) {
const intId = parseInt(id, 10);
await db.deleteFrom("User").where("User.id", "=", intId).execute();
},
async linkAccount(account) {
const acc = { ...account, userId: Number(account.userId) };
await db.insertInto("Account").values(acc).executeTakeFirstOrThrow();
},
async unlinkAccount({ providerAccountId, provider }) {
await db
.deleteFrom("Account")
.where("Account.providerAccountId", "=", providerAccountId)
.where("Account.provider", "=", provider)
.executeTakeFirstOrThrow();
},
async createSession(session) {
const sess = { ...session, userId: Number(session.userId) };
const query = db.insertInto("Session").values(sess);
const result = supportsReturning
? await query.returningAll().executeTakeFirstOrThrow()
: await (async () => {
await query.executeTakeFirstOrThrow();
return await db
.selectFrom("Session")
.selectAll()
.where("sessionToken", "=", sess.sessionToken)
.executeTakeFirstOrThrow();
})();
return {
...result,
id: String(result.id),
userId: String(result.userId),
};
},
async getSessionAndUser(sessionTokenString) {
const result = await db
.selectFrom("Session")
.innerJoin("User", "User.id", "Session.userId")
.selectAll("User")
.select([
"Session.id as sessionId",
"Session.userId",
"Session.sessionToken",
"Session.expires",
])
.where("Session.sessionToken", "=", sessionTokenString)
.executeTakeFirst();
if (!result) return null;
const { sessionId, userId, sessionToken, expires, ...user } = result;
return {
user: { ...user, id: String(userId) },
session: {
id: String(sessionId),
userId: String(userId),
sessionToken,
expires,
},
};
},
async updateSession(session) {
const sess = { ...session, userId: Number(session.userId) };
const query = db
.updateTable("Session")
.set(sess)
.where("Session.sessionToken", "=", session.sessionToken);
const result = supportsReturning
? await query.returningAll().executeTakeFirstOrThrow()
: await query.executeTakeFirstOrThrow().then(async () => {
return await db
.selectFrom("Session")
.selectAll()
.where("Session.sessionToken", "=", sess.sessionToken)
.executeTakeFirstOrThrow();
});
return {
...result,
id: String(result.id),
userId: String(result.userId),
};
},
async deleteSession(sessionToken) {
await db
.deleteFrom("Session")
.where("Session.sessionToken", "=", sessionToken)
.executeTakeFirstOrThrow();
},
async createVerificationToken(verificationToken) {
const query = db
.insertInto("VerificationToken")
.values(verificationToken);
const result = supportsReturning
? await query.returningAll().executeTakeFirstOrThrow()
: await query.executeTakeFirstOrThrow().then(async () => {
return await db
.selectFrom("VerificationToken")
.selectAll()
.where("token", "=", verificationToken.token)
.executeTakeFirstOrThrow();
});
return result;
},
async useVerificationToken({ identifier, token }) {
const query = db
.deleteFrom("VerificationToken")
.where("VerificationToken.token", "=", token)
.where("VerificationToken.identifier", "=", identifier);
const result = supportsReturning
? (await query.returningAll().executeTakeFirst()) ?? null
: await db
.selectFrom("VerificationToken")
.selectAll()
.where("token", "=", token)
.executeTakeFirst()
.then(async (res) => {
await query.executeTakeFirst();
return res;
});
if (!result) return null;
return result;
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment