Skip to content
17 changes: 0 additions & 17 deletions apps/server/src/core/lib/cache.ts

This file was deleted.

37 changes: 14 additions & 23 deletions apps/server/src/modules/account/repositories/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { db, eq, sql } from "@fixr/db/connection";
import { clients, companies, employees, users } from "@fixr/db/schema";
import { accountSchema } from "@fixr/schemas/account";
import { redis } from "../../../config/redis";
import { accountCacheKey, CACHE_TTL } from "../../../core/lib/cache";
import { Cached } from "../../../shared/infra/cache";

/** @description Account data access layer */
export class AccountRepository {
Expand All @@ -12,14 +11,8 @@ export class AccountRepository {
* @param id - The user ID
* @returns The parsed account data
*/
@Cached({ ttl: 3600, key: "account" })
static async queryAccountById(id: string) {
const cacheKey = accountCacheKey(id);
const cached = await redis.get(cacheKey);

if (cached) {
return accountSchema.parse(JSON.parse(cached));
}

const [account] = await db
.select({
id: users.id,
Expand All @@ -29,19 +22,19 @@ export class AccountRepository {
cpf: sql`COALESCE(${employees.cpf}, ${clients.cpf})`,
phone: sql`COALESCE(${employees.phone}, ${clients.phone})`,
profileType: sql`CASE
WHEN ${employees.id} IS NOT NULL THEN 'employee'
WHEN ${clients.id} IS NOT NULL THEN 'client'
ELSE 'unknown'
END`,
WHEN ${employees.id} IS NOT NULL THEN 'employee'
WHEN ${clients.id} IS NOT NULL THEN 'client'
ELSE 'unknown'
END`,
company: sql`CASE
WHEN ${employees.id} IS NOT NULL THEN JSON_OBJECT(
'id', ${companies.id},
'name', ${companies.name},
'subdomain', ${companies.subdomain},
'role', ${employees.role}
)
ELSE NULL
END`,
WHEN ${employees.id} IS NOT NULL THEN JSON_OBJECT(
'id', ${companies.id},
'name', ${companies.name},
'subdomain', ${companies.subdomain},
'role', ${employees.role}
)
ELSE NULL
END`,
createdAt: users.createdAt,
})
.from(users)
Expand All @@ -51,8 +44,6 @@ export class AccountRepository {
.where(eq(users.id, id))
.limit(1);

await redis.set(cacheKey, JSON.stringify(account), "EX", CACHE_TTL);

return accountSchema.parse(account);
}
}
45 changes: 7 additions & 38 deletions apps/server/src/modules/auth/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ import {

import type { TokenPayload } from "google-auth-library";
import type { z } from "zod";
import { redis } from "../../../config/redis";
import {
CACHE_TTL,
jwtPayloadCacheKey,
userCacheKey,
} from "../../../core/lib/cache";
import { Cached, InvalidateCache } from "../../../shared/infra/cache";

/** @description User data access layer */
export class AuthRepository {
Expand All @@ -23,14 +18,8 @@ export class AuthRepository {
* @param id - The user ID
* @returns The parsed user data
*/
@Cached({ ttl: 3600, key: "user" })
static async queryUserById(id: string) {
const cacheKey = userCacheKey(id);
const cached = await redis.get(cacheKey);

if (cached) {
return userSchema.parse(JSON.parse(cached));
}

const [user] = await db
.select({
id: users.id,
Expand All @@ -52,8 +41,6 @@ export class AuthRepository {
.where(eq(users.id, id))
.limit(1);

await redis.set(cacheKey, JSON.stringify(user), "EX", CACHE_TTL);

return userSchema.parse(user);
}

Expand All @@ -63,6 +50,7 @@ export class AuthRepository {
* @param email - The user email
* @returns The parsed user data or null if not found
*/
@Cached({ ttl: 3600, key: "user:email" })
static async queryUserByEmail(
email: string
): Promise<z.infer<typeof userSchema> | null> {
Expand Down Expand Up @@ -100,14 +88,8 @@ export class AuthRepository {
* @param userId - The user ID
* @returns The parsed JWT payload
*/
@Cached({ ttl: 3600, key: "jwt" })
static async queryJWTPayloadByUserId(userId: string) {
const cacheKey = jwtPayloadCacheKey(userId);
const cached = await redis.get(cacheKey);

if (cached) {
return jwtPayload.parse(JSON.parse(cached));
}

const [payload] = await db
.select({
id: users.id,
Expand Down Expand Up @@ -138,8 +120,6 @@ export class AuthRepository {
.leftJoin(companies, eq(employees.companyId, companies.id))
.where(eq(users.id, userId));

await redis.set(cacheKey, JSON.stringify(payload), "EX", CACHE_TTL);

return jwtPayload.parse(payload);
}

Expand All @@ -166,15 +146,13 @@ export class AuthRepository {
*
* @param userId - The user ID
*/
@InvalidateCache({ patterns: ["user:*", "jwt:*", "account:*"] })
static async setUserVerified(userId: string) {
const verifyUser = db
.update(users)
.set({ verified: true })
.where(eq(users.id, userId));

const cacheKey = userCacheKey(userId);
await redis.del(cacheKey);

return await verifyUser;
}

Expand All @@ -183,12 +161,10 @@ export class AuthRepository {
*
* @param userId - The user ID
*/
@InvalidateCache({ patterns: ["user:*", "jwt:*", "account:*"] })
static async deleteUser(userId: string) {
const delUser = db.delete(users).where(eq(users.id, userId));

const cacheKey = userCacheKey(userId);
await redis.del(cacheKey);

return await delUser;
}

Expand All @@ -198,21 +174,14 @@ export class AuthRepository {
* @param userId - The user ID
* @param data - Google token payload data
*/
@InvalidateCache({ patterns: ["user:*", "jwt:*", "account:*"] })
static async updateUserWithGoogleData({
userId,
data,
}: {
userId: string;
data: Partial<TokenPayload>;
}) {
const invalidate = {
user: userCacheKey(userId),
jwt: jwtPayloadCacheKey(userId),
};

// Use Promise.all for parallel cache invalidation instead of sequential loop
await Promise.all(Object.values(invalidate).map((key) => redis.del(key)));

return await db
.update(users)
.set({ googleId: data.sub, avatarUrl: data.picture })
Expand Down
3 changes: 3 additions & 0 deletions apps/server/src/modules/categories/repositories/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { asc, db, eq, like } from "@fixr/db/connection";
import { modelCategories } from "@fixr/db/schema";
import { Cached } from "../../../shared/infra/cache";

/** @description Data access layer for device categories */
export class CategoriesRepository {
Expand All @@ -8,6 +9,7 @@ export class CategoriesRepository {
*
* @param query - Optional name filter
*/
@Cached({ ttl: 3600, key: "categories:all" })
static async queryAllCategories(query?: string) {
const base = db.select().from(modelCategories).$dynamic();
if (query) {
Expand All @@ -22,6 +24,7 @@ export class CategoriesRepository {
* @param slug - The category slug
* @returns The category record or null
*/
@Cached({ ttl: 3600, key: "categories:slug" })
static async queryCategoryBySlug(slug: string) {
const [category] = await db
.select()
Expand Down
34 changes: 4 additions & 30 deletions apps/server/src/modules/companies/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import {
} from "@fixr/db/schema";
import type { createCompanySchema } from "@fixr/schemas/companies";
import type { z } from "zod";
import { redis } from "../../../config/redis";
import { CACHE_TTL, companyCacheKey } from "../../../core/lib/cache";
import { hashPassword } from "../../../core/lib/hash-password";
import { Cached, InvalidateCache } from "../../../shared/infra/cache";

/** @description Companies data access layer */
export class CompaniesRepository {
Expand All @@ -19,31 +18,18 @@ export class CompaniesRepository {
* @param id - The company ID
* @returns The parsed company data
*/
@Cached({ ttl: 3600, key: "company" })
static async queryCompanyById(id: string) {
const cacheKey = companyCacheKey(id);
const cached = await redis.get(cacheKey);

if (cached) {
const parsed = JSON.parse(cached);
if (!parsed) {
return undefined;
}
return companySelectSchema.parse(parsed);
}

const [company] = await db
.select()
.from(companies)
.where(eq(companies.id, id))
.limit(1);

if (!company) {
await redis.set(cacheKey, JSON.stringify(null), "EX", CACHE_TTL);
return undefined;
}

await redis.set(cacheKey, JSON.stringify(company), "EX", CACHE_TTL);

return companySelectSchema.parse(company);
}

Expand All @@ -53,31 +39,18 @@ export class CompaniesRepository {
* @param subdomain - The company subdomain
* @returns The parsed company data
*/
@Cached({ ttl: 3600, key: "company:subdomain" })
static async queryCompanyBySubdomain(subdomain: string) {
const cacheKey = companyCacheKey(subdomain);
const cached = await redis.get(cacheKey);

if (cached) {
const parsed = JSON.parse(cached);
if (!parsed) {
return undefined;
}
return companySelectSchema.parse(parsed);
}

const [company] = await db
.select()
.from(companies)
.where(eq(companies.subdomain, subdomain))
.limit(1);

if (!company) {
await redis.set(cacheKey, JSON.stringify(null), "EX", CACHE_TTL);
return undefined;
}

await redis.set(cacheKey, JSON.stringify(company), "EX", CACHE_TTL);

return companySelectSchema.parse(company);
}

Expand Down Expand Up @@ -108,6 +81,7 @@ export class CompaniesRepository {
/**
* @description Create a company, user, and employee (admin) in sequence
*/
@InvalidateCache({ patterns: ["company:*"] })
static async createOrgWithAdmin(data: z.infer<typeof createCompanySchema>) {
const [orgId] = await db
.insert(companies)
Expand Down
7 changes: 2 additions & 5 deletions apps/server/src/modules/credentials/repositories/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { db, eq } from "@fixr/db/connection";
import { users } from "@fixr/db/schema";
import { redis } from "../../../config/redis";
import { userCacheKey } from "../../../core/lib/cache";
import { InvalidateCache } from "../../../shared/infra/cache";

/** @description Credentials data access layer */
export class CredentialsRepository {
Expand All @@ -11,15 +10,13 @@ export class CredentialsRepository {
* @param userId - The user ID
* @param passwordHash - The new bcrypt hash
*/
@InvalidateCache({ patterns: ["user:*", "jwt:*", "account:*"] })
static async updateUserPassword(userId: string, passwordHash: string) {
const updatePass = db
.update(users)
.set({ passwordHash })
.where(eq(users.id, userId));

const cacheKey = userCacheKey(userId);
await redis.del(cacheKey);

return await updatePass;
}
}
3 changes: 3 additions & 0 deletions apps/server/src/modules/employees/repositories/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { employees, users } from "@fixr/db/schema";
import type { createEmployeeSchema } from "@fixr/schemas/employees";
import type { z } from "zod";
import { hashPassword } from "../../../core/lib/hash-password";
import { Cached, InvalidateCache } from "../../../shared/infra/cache";

/** @description Employees data access layer */
export class EmployeesRepository {
Expand All @@ -13,6 +14,7 @@ export class EmployeesRepository {
* @param cpf - The employee CPF
* @returns The employee data or undefined
*/
@Cached({ ttl: 3600, key: "employees:cpf" })
static async getEmployeeByCpf(cpf: string) {
const [data] = await db
.select()
Expand All @@ -27,6 +29,7 @@ export class EmployeesRepository {
* @param data - The employee registration data
* @param companyId - The company ID
*/
@InvalidateCache({ patterns: ["employees:*"] })
static async createEmployeeAndAccount({
data,
companyId,
Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/modules/makers/repositories/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { and, asc, db, desc, eq, like, type SQL } from "@fixr/db/connection";
import { modelMakers } from "@fixr/db/schema";
import { Cached } from "../../../shared/infra/cache";

/** @description Column selection for paginated makers list */
export const makersListSelect = {
Expand Down Expand Up @@ -51,6 +52,7 @@ export class MakersRepository {
* @param slug - The maker slug
* @returns The maker record or null
*/
@Cached({ ttl: 3600, key: "makers:slug" })
static async queryMakerBySlug(slug: string) {
const [maker] = await db
.select()
Expand Down
Loading