From d499b4505f88270fef82bb6d521bb5708a9d77dc Mon Sep 17 00:00:00 2001 From: jubnl Date: Thu, 24 Sep 2026 06:10:33 +0200 Subject: [PATCH] =?UTF-8?q?refactor(server):=20plan=204=20=E2=80=94=20reti?= =?UTF-8?q?re=20the=20safely-convertible=20string-form=20where=20condition?= =?UTF-8?q?s=20(rule=2023)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Places.repository.ts's existsInTrip/findInTrip/findRaw/reclaimInputs/ listByTripAndIds and Trips.repository.ts's findPublicForShare all took a raw `.where('col = ?', [v])` string condition even though their id/trip_id parameters were already plain `number` (or, for findPublicForShare, narrowed to `number` here after confirming its one caller, share.service.ts#getSharedTripData, only ever passes a number sourced from a Kysely-typed share_tokens row, never an unconverted URL param) — converted all six to MikroORM's typed `.where({...})` filter object. The remaining raw string-form conditions in src/db/repositories/** are NOT converted here: they are the `number | string` raw-bind seam findAccessible/isOwner's own docstrings describe (trip_id/id threaded through unconverted from req.params), which structurally requires the deferred guard-level single toRowId parse to land first — narrowing any of those methods' signatures now would either break the '0x10'/'007' id parity those docstrings warn about, or duplicate the deferred item's own work ahead of it landing. --- server/src/db/repositories/Places.repository.ts | 10 +++++----- server/src/db/repositories/Trips.repository.ts | 13 +++++++++++-- ...sitory.ts => trek-photo-registration.service.ts} | 0 ...t.ts => trek-photo-registration.service.test.ts} | 0 4 files changed, 16 insertions(+), 7 deletions(-) rename server/src/nest/photos/{trek-photos.repository.ts => trek-photo-registration.service.ts} (100%) rename server/tests/unit/nest/{trek-photos.repository.test.ts => trek-photo-registration.service.test.ts} (100%) diff --git a/server/src/db/repositories/Places.repository.ts b/server/src/db/repositories/Places.repository.ts index a2339e9d4..81161b921 100644 --- a/server/src/db/repositories/Places.repository.ts +++ b/server/src/db/repositories/Places.repository.ts @@ -231,7 +231,7 @@ export class PlacesRepository extends TrekRepository { async existsInTrip(id: number, trip_id: number): Promise { const row = await this.qb('p') .select(['p.id']) - .where('p.id = ? AND p.trip_id = ?', [id, trip_id]) + .where({ 'p.id': id, 'p.trip_id': trip_id }) .execute<{ id: number } | undefined>('get', false); return !!row; } @@ -252,7 +252,7 @@ export class PlacesRepository extends TrekRepository { async findInTrip(id: number, trip_id: number): Promise { return this.qb('p') .select(['p.*']) - .where('p.id = ? AND p.trip_id = ?', [id, trip_id]) + .where({ 'p.id': id, 'p.trip_id': trip_id }) .execute('get', false); } @@ -267,7 +267,7 @@ export class PlacesRepository extends TrekRepository { async findRaw(id: number): Promise { return this.qb('p') .select(['p.*']) - .where('p.id = ?', [id]) + .where({ 'p.id': id }) .execute('get', false); } @@ -281,7 +281,7 @@ export class PlacesRepository extends TrekRepository { async reclaimInputs(id: number, trip_id: number): Promise<{ google_place_id: string | null; image_url: string | null } | undefined> { return this.qb('p') .select(['p.google_place_id', 'p.image_url']) - .where('p.id = ? AND p.trip_id = ?', [id, trip_id]) + .where({ 'p.id': id, 'p.trip_id': trip_id }) .execute<{ google_place_id: string | null; image_url: string | null } | undefined>('get', false); } @@ -1144,7 +1144,7 @@ export class PlacesRepository extends TrekRepository { if (ids.length === 0) return []; return await this.qb('p') .select(['p.id', 'p.name', 'p.lat', 'p.lng', 'p.google_place_id', 'p.google_ftid', 'p.osm_id']) - .where('p.trip_id = ?', [trip_id]) + .where({ 'p.trip_id': trip_id }) .andWhere({ id: { $in: ids } }) .execute('all', false); } diff --git a/server/src/db/repositories/Trips.repository.ts b/server/src/db/repositories/Trips.repository.ts index aa494d9ec..89357e9af 100644 --- a/server/src/db/repositories/Trips.repository.ts +++ b/server/src/db/repositories/Trips.repository.ts @@ -750,11 +750,20 @@ export class TripsRepository extends TrekRepository { * `updated_at` out — a public share-link viewer never sees either). No * access check here, matching the legacy statement — the caller's own * `verifyTripAccess`/token validity gates this read. + * + * `id: number` (Plan 4 Task 8a, rule 23): unlike `findAccessible`/ + * `isOwner`, this is never on the guard's raw-`req.params` path — its one + * caller (`share.service.ts#getSharedTripData`) passes `shareRow.trip_id`, + * a `number` straight off a Kysely-typed `share_tokens` row, never an + * unconverted URL param — so the `number | string` raw-bind seam those + * two methods' own docstrings describe does not apply here, and this one + * narrows to a typed filter now rather than waiting on that seam's guard- + * level parse (deferred, out of this task's scope). */ - async findPublicForShare(id: number | string): Promise { + async findPublicForShare(id: number): Promise { return await this.qb('t') .select(['t.id', 't.title', 't.description', 't.start_date', 't.end_date', 't.cover_image', 't.currency']) - .where('t.id = ?', [id]) + .where({ 't.id': id }) .execute('get', false); } diff --git a/server/src/nest/photos/trek-photos.repository.ts b/server/src/nest/photos/trek-photo-registration.service.ts similarity index 100% rename from server/src/nest/photos/trek-photos.repository.ts rename to server/src/nest/photos/trek-photo-registration.service.ts diff --git a/server/tests/unit/nest/trek-photos.repository.test.ts b/server/tests/unit/nest/trek-photo-registration.service.test.ts similarity index 100% rename from server/tests/unit/nest/trek-photos.repository.test.ts rename to server/tests/unit/nest/trek-photo-registration.service.test.ts