Skip to content

Commit

Permalink
Streamline prisma initialization (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
KennethWussmann authored Feb 27, 2024
1 parent 403bbeb commit ca63ddd
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 65 deletions.
4 changes: 2 additions & 2 deletions src/server/api/routers/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
protectedProcedure,
publicProcedure,
} from "~/server/api/trpc";
import { db } from "~/server/db";
import { defaultApplicationContext } from "~/server/lib/applicationContext";

const isDatabaseHealthy = async () => {
try {
await db.$queryRaw`SELECT 1`;
await defaultApplicationContext.prismaClient.$queryRaw`SELECT 1`;
return true;
} catch (e) {
return false;
Expand Down
41 changes: 4 additions & 37 deletions src/server/api/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,14 @@

import { initTRPC, TRPCError } from "@trpc/server";
import { type CreateNextContextOptions } from "@trpc/server/adapters/next";
import { type Session } from "next-auth";
import superjson from "superjson";
import { ZodError } from "zod";
import { ApplicationContext } from "~/server/lib/applicationContext";
import { defaultApplicationContext } from "~/server/lib/applicationContext";

import { getServerAuthSession } from "~/server/auth/auth";
import { db } from "~/server/db";
import { type RateLimitType } from "../lib/rate-limit/rateLimitService";
import { UserRole } from "@prisma/client";

/**
* 1. CONTEXT
*
* This section defines the "contexts" that are available in the backend API.
*
* These allow you to access things when processing a request, like the database, the session, etc.
*/

interface CreateContextOptions {
session: Session | null;
remoteAddress: string;
applicationContext: ApplicationContext;
}

/**
* This helper generates the "internals" for a tRPC context. If you need to use it, you can export
* it from here.
*
* Examples of things you may need it for:
* - testing, so we don't have to mock Next.js' req/res
* - tRPC's `createSSGHelpers`, where we don't have req/res
*
* @see https://create.t3.gg/en/usage/trpc#-serverapitrpcts
*/
const createInnerTRPCContext = (opts: CreateContextOptions) => {
return {
...opts,
db,
};
};

/**
* This is the actual context you will use in your router. It will be used to process every request
* that goes through your tRPC endpoint.
Expand Down Expand Up @@ -77,11 +44,11 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
});
}

return createInnerTRPCContext({
return {
session,
remoteAddress,
applicationContext: new ApplicationContext(),
});
applicationContext: defaultApplicationContext,
};
};

/**
Expand Down
4 changes: 2 additions & 2 deletions src/server/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
type DefaultSession,
type NextAuthOptions,
} from "next-auth";
import { db } from "~/server/db";
import { providers } from "./providers";
import { defaultApplicationContext } from "../lib/applicationContext";

/**
* Module augmentation for `next-auth` types. Allows us to add custom properties to the `session`
Expand Down Expand Up @@ -46,7 +46,7 @@ export const authOptions: NextAuthOptions = {
pages: {
signIn: "/auth/signin",
},
adapter: PrismaAdapter(db),
adapter: PrismaAdapter(defaultApplicationContext.prismaClient),
providers,
};

Expand Down
14 changes: 7 additions & 7 deletions src/server/auth/customCredentialsProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import CredentialsProvider from "next-auth/providers/credentials";
import { db } from "../db";
import { verifyPassword } from "../lib/utils/passwordUtils";
import { defaultApplicationContext } from "../lib/applicationContext";
import { sanitizeEmail } from "../lib/utils/emailUtils";
Expand All @@ -13,7 +12,7 @@ export const CustomCredentialsProvider = () =>
password: { label: "Password", type: "password" },
},
async authorize(credentials, req): Promise<User | null> {
const { rateLimitService } = defaultApplicationContext;
const { rateLimitService, userService } = defaultApplicationContext;

if (!credentials) {
return null;
Expand All @@ -39,11 +38,12 @@ export const CustomCredentialsProvider = () =>
}

try {
const user = await db.user.findFirst({
where: {
email,
},
});
const user = await userService.findUserByEmail(email);

if (!user) {
await rateLimitService.consume("login_failed_by_ip", ip);
return null;
}

const isLoggedIn =
user?.password &&
Expand Down
16 changes: 0 additions & 16 deletions src/server/db.ts

This file was deleted.

7 changes: 6 additions & 1 deletion src/server/lib/applicationContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import { TeamCreationService } from "./team/TeamCreationService";
import { ImportService } from "./import/importService";

export class ApplicationContext {
public readonly prismaClient = new PrismaClient();
public readonly prismaClient = new PrismaClient({
log:
process.env.LOG_LEVEL === "debug"
? ["query", "error", "warn"]
: ["error"],
});
public readonly logger = createLogger({});
private readonly meiliSearch = new MeiliSearch({
host: process.env.MEILI_URL ?? "http://127.0.0.1:7700",
Expand Down
7 changes: 7 additions & 0 deletions src/server/lib/user/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ export class UserService {
});
};

public findUserByEmail = async (email: string) => {
const user = await this.prisma.user.findUnique({
where: { email: sanitizeEmail(email) },
});
return user;
};

public changePassword = async (
userId: string,
input: UserChangePasswordRequest
Expand Down

0 comments on commit ca63ddd

Please sign in to comment.