Skip to content

Commit 9d71feb

Browse files
committed
wip
1 parent 04012de commit 9d71feb

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

app/src/db/repositories/base.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { Prisma } from '@prisma/client';
2+
3+
interface AuditFields {
4+
createdAt?: Date;
5+
createdBy?: string;
6+
updatedAt?: Date | null;
7+
updatedBy?: string | null;
8+
}
9+
10+
interface SoftDeleteFields {
11+
deletedAt?: Date | null;
12+
deletedBy?: string | null;
13+
}
14+
15+
interface PrismaDelegate<TModel, TCreateInput, TUpdateInput, TWhereUniqueInput, TFindManyArgs, TFindFirstArgs> {
16+
create(args: { data: TCreateInput }): Promise<TModel>;
17+
update(args: { where: TWhereUniqueInput; data: TUpdateInput }): Promise<TModel>;
18+
delete(args: { where: TWhereUniqueInput }): Promise<TModel>;
19+
findFirst(args: TFindFirstArgs): Promise<TModel | null>;
20+
findMany(args?: TFindManyArgs): Promise<TModel[]>;
21+
}
22+
23+
export abstract class BaseRepository<
24+
TModel,
25+
TCreateInput extends Record<string, unknown>,
26+
TUpdateInput extends Record<string, unknown>,
27+
TWhereUniqueInput,
28+
TWhereInput,
29+
TFindManyArgs extends { where?: TWhereInput },
30+
TFindFirstArgs extends { where?: TWhereInput },
31+
TDelegate extends PrismaDelegate<TModel, TCreateInput, TUpdateInput, TWhereUniqueInput, TFindManyArgs, TFindFirstArgs>
32+
> {
33+
protected constructor(
34+
protected readonly model: TDelegate,
35+
protected readonly userId: string,
36+
protected readonly softDeleteEnabled = false
37+
) {}
38+
39+
// ------------------------
40+
// Audit helpers
41+
// ------------------------
42+
43+
protected withCreateAudit(data: TCreateInput): TCreateInput & AuditFields {
44+
const now = new Date();
45+
46+
return {
47+
...data,
48+
createdAt: now,
49+
createdBy: this.userId
50+
};
51+
}
52+
53+
protected withUpdateAudit(data: TUpdateInput): TUpdateInput & AuditFields {
54+
return {
55+
...data,
56+
updatedAt: new Date(),
57+
updatedBy: this.userId
58+
};
59+
}
60+
61+
protected withSoftDelete(): SoftDeleteFields {
62+
return {
63+
deletedAt: new Date(),
64+
deletedBy: this.userId
65+
};
66+
}
67+
68+
// ------------------------
69+
// Query helpers
70+
// ------------------------
71+
72+
protected applyNotDeletedFilter(
73+
args: TFindManyArgs | TFindFirstArgs | undefined,
74+
includeDeleted = false
75+
): TFindManyArgs | TFindFirstArgs {
76+
if (!this.softDeleteEnabled || includeDeleted) {
77+
return (args ?? {}) as TFindManyArgs | TFindFirstArgs;
78+
}
79+
80+
const base = (args ?? {}) as TFindManyArgs | TFindFirstArgs;
81+
82+
return {
83+
...base,
84+
where: {
85+
...(base.where ?? ({} as TWhereInput)),
86+
deletedAt: null
87+
}
88+
};
89+
}
90+
91+
// ------------------------
92+
// CRUD
93+
// ------------------------
94+
95+
async create(data: TCreateInput): Promise<TModel> {
96+
return this.model.create({
97+
data: this.withCreateAudit(data)
98+
});
99+
}
100+
101+
async update(where: TWhereUniqueInput, data: TUpdateInput): Promise<TModel> {
102+
return this.model.update({
103+
where,
104+
data: this.withUpdateAudit(data)
105+
});
106+
}
107+
108+
async delete(where: TWhereUniqueInput): Promise<TModel> {
109+
if (!this.softDeleteEnabled) {
110+
return this.model.delete({ where });
111+
}
112+
113+
return this.model.update({
114+
where,
115+
data: {
116+
...this.withUpdateAudit({} as TUpdateInput),
117+
...this.withSoftDelete()
118+
}
119+
});
120+
}
121+
122+
async findFirst(args: TFindFirstArgs, options?: { includeDeleted?: boolean }): Promise<TModel | null> {
123+
return this.model.findFirst(this.applyNotDeletedFilter(args, options?.includeDeleted) as TFindFirstArgs);
124+
}
125+
126+
async findMany(args?: TFindManyArgs, options?: { includeDeleted?: boolean }): Promise<TModel[]> {
127+
return this.model.findMany(this.applyNotDeletedFilter(args, options?.includeDeleted) as TFindManyArgs);
128+
}
129+
}

0 commit comments

Comments
 (0)