Skip to content

Commit 85d8f12

Browse files
authored
Merge pull request #500 from bcgov/feature/db-repos
refactor(api): migrate to controller-service-domain-repository architecture
2 parents 37a0591 + 167d61d commit 85d8f12

300 files changed

Lines changed: 23998 additions & 18159 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.vscode/extensions.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
"eamodio.gitlens",
88
"editorconfig.editorconfig",
99
"esbenp.prettier-vscode",
10-
"gruntfuggly.todo-tree",
1110
"lokalise.i18n-ally",
1211
"redhat.vscode-yaml",
1312
"ryanluker.vscode-coverage-gutters",

app/app.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Prisma } from '@prisma/client';
21
import compression from 'compression';
32
import config from 'config';
43
import cors from 'cors';
@@ -141,37 +140,6 @@ export function errorHandler(
141140
if (err instanceof Problem) {
142141
log.error(err);
143142
err.send(req, res);
144-
} else if (err instanceof Prisma.PrismaClientKnownRequestError) {
145-
switch (err.code) {
146-
case 'P2002':
147-
new Problem(500, {
148-
type: err.code,
149-
title: err.meta?.constraint as string,
150-
detail: err.meta?.modelName as string
151-
}).send(req, res);
152-
break;
153-
case 'P2003':
154-
new Problem(500, {
155-
type: err.code,
156-
title: err.meta?.constraint as string,
157-
detail: err.meta?.modelName as string
158-
}).send(req, res);
159-
break;
160-
case 'P2025':
161-
new Problem(404, {
162-
type: err.code,
163-
title: err.meta?.cause as string,
164-
detail: err.meta?.modelName as string
165-
}).send(req, res);
166-
break;
167-
default:
168-
new Problem(500, {
169-
type: err.code,
170-
title: err.meta?.cause as string,
171-
detail: err.meta?.modelName as string
172-
}).send(req, res);
173-
break;
174-
}
175143
} else {
176144
if (err.stack) log.error(err);
177145
new Problem(500, { detail: err.message ?? err.toString() }).send(req, res);

app/eslint.config.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,29 @@ export default defineConfig([
3737
quotes: ['error', 'single'],
3838
semi: ['error', 'always']
3939
}
40+
},
41+
// Entity repositories must go through inherited query/mutation methods,
42+
// never touch `this.model` directly — that's only for readable.ts/writable.ts
43+
// to implement the base methods themselves.
44+
{
45+
files: ['src/repository/**/*.ts'],
46+
rules: {
47+
'no-restricted-syntax': [
48+
'error',
49+
{
50+
// eslint-disable-next-line quotes
51+
selector: `MemberExpression[object.type='ThisExpression'][property.name='model']`,
52+
message:
53+
'Use inherited query methods (this.findMany, this.create, etc.) instead of this.model directly. ' +
54+
'Only readable.ts/writable.ts may access this.model.'
55+
}
56+
]
57+
}
58+
},
59+
{
60+
files: ['src/repository/readable.ts', 'src/repository/writable.ts'],
61+
rules: {
62+
'no-restricted-syntax': 'off'
63+
}
4064
}
4165
]);

app/peachSync.ts

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { syncPeachRecords } from './src/controllers/peach.ts';
2-
import { sendPermitUpdateNotifications } from './src/controllers/permit.ts';
1+
import { syncPeachRecords } from './src/domains/peach.ts';
2+
import { sendPermitUpdateNotifications } from './src/domains/permit.ts';
33
import { refreshCodeCaches } from './src/db/codes/cache.ts';
4+
import { unitOfWork } from './src/db/unitOfWork.ts';
45
import { getLogger } from './src/utils/log.ts';
56
import { state } from './state.ts';
67

@@ -11,33 +12,42 @@ const log = getLogger(module.filename);
1112
async function syncPeachToPcns() {
1213
if (!state.features.peach) return;
1314

14-
const started = Date.now();
15-
let updatedPermitsWithNotes: UpdatedPermitWithNote[];
15+
await unitOfWork.execute(
16+
async ({ electrificationProject, generalProject, housingProject, permit, permitNote, user }) => {
17+
const started = Date.now();
18+
let updatedPermitsWithNotes: UpdatedPermitWithNote[];
1619

17-
log.info('PEACH sync job started');
18-
try {
19-
updatedPermitsWithNotes = await syncPeachRecords();
20+
log.info('PEACH sync job started');
21+
try {
22+
updatedPermitsWithNotes = await syncPeachRecords({ permit });
2023

21-
log.info('PEACH sync completed', {
22-
durationMs: Date.now() - started,
23-
updatedCount: updatedPermitsWithNotes.length
24-
});
25-
} catch (error) {
26-
log.error('PEACH sync FAILED during data sync', error);
27-
process.exitCode = 1;
28-
return;
29-
}
24+
log.info('PEACH sync completed', {
25+
durationMs: Date.now() - started,
26+
updatedCount: updatedPermitsWithNotes.length
27+
});
28+
} catch (error) {
29+
log.error('PEACH sync FAILED during data sync', error);
30+
process.exitCode = 1;
31+
return;
32+
}
3033

31-
if (updatedPermitsWithNotes.length === 0) return;
34+
if (updatedPermitsWithNotes.length === 0) return;
3235

33-
try {
34-
for (const permitWithNote of updatedPermitsWithNotes) {
35-
const { permit, note } = permitWithNote;
36-
await sendPermitUpdateNotifications(permit, true, note);
36+
try {
37+
for (const permitWithNote of updatedPermitsWithNotes) {
38+
const { permit, note } = permitWithNote;
39+
await sendPermitUpdateNotifications(
40+
{ electrificationProject, generalProject, housingProject, permitNote, user },
41+
permit,
42+
true,
43+
note
44+
);
45+
}
46+
} catch (error) {
47+
log.warn('PEACH sync completed but sending notifications failed', error);
48+
}
3749
}
38-
} catch (error) {
39-
log.warn('PEACH sync completed but sending notifications failed', error);
40-
}
50+
);
4151
}
4252

4353
async function main() {

0 commit comments

Comments
 (0)