From ca0138dc4592d2d8b534f85410e3ec4c721e5dee Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 8 Oct 2026 20:22:16 +0200 Subject: [PATCH] test(server): make the row factories return what they promise findRow and the default category lookup asked findOne with an empty where, which MikroORM refuses. insertRows returned a single id because insertMany on plain data reports only the last insert id; it now inserts row by row and returns every id. insertRow and updateRows reject instead of throwing before the caller holds a promise. --- server/tests/helpers/factories/places.ts | 2 +- server/tests/helpers/factories/rows.ts | 29 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/server/tests/helpers/factories/places.ts b/server/tests/helpers/factories/places.ts index a70b05427..652c50958 100644 --- a/server/tests/helpers/factories/places.ts +++ b/server/tests/helpers/factories/places.ts @@ -32,7 +32,7 @@ export function makeTag(orm: FactoryOrm, userId: number, overrides: EntityData { return inContext(orm, async (em) => { - const first = await em.findOne(Categories, {}, { orderBy: { id: 'asc' }, disableIdentityMap: true }); + const [first] = await em.find(Categories, {}, { orderBy: { id: 'asc' }, limit: 1, disableIdentityMap: true }); return first?.id ?? null; }); } diff --git a/server/tests/helpers/factories/rows.ts b/server/tests/helpers/factories/rows.ts index 7c2e34b04..8acb9002a 100644 --- a/server/tests/helpers/factories/rows.ts +++ b/server/tests/helpers/factories/rows.ts @@ -34,22 +34,31 @@ export function insertRow( entity: EntityClass, data: RequiredEntityData, ): Promise> { - return inContext(orm, (em) => { + // async, so a refused column rejects the returned promise rather than + // throwing before the caller has one to await. + return inContext(orm, async (em) => { assertWritable(em, entity, data); return em.insert(entity, data); }); } -/** Inserts several rows in one statement and returns their primary keys in order. */ +/** + * Inserts several rows and returns their primary keys in order. One INSERT per + * row: `em.insertMany` on plain data hands back only the last insert id (it + * returns `[insertId]` unless the driver reports `insertedIds`, which the SQL + * drivers never do), so a caller zipping ids with its rows would get one id. + */ export function insertRows( orm: FactoryOrm, entity: EntityClass, data: RequiredEntityData[], ): Promise[]> { if (data.length === 0) return Promise.resolve([]); - return inContext(orm, (em) => { + return inContext(orm, async (em) => { for (const row of data) assertWritable(em, entity, row); - return em.insertMany(entity, data); + const ids: Primary[] = []; + for (const row of data) ids.push(await em.insert(entity, row)); + return ids; }); } @@ -69,14 +78,20 @@ export async function createRow( return row; } -/** The first row matching `where`, or null. */ +/** + * The first row matching `where`, or null. An empty `where` asks for any row, + * which MikroORM's findOne refuses, so that one reads the first row instead. + */ export function findRow( orm: FactoryOrm, entity: EntityClass, where: FilterQuery, ): Promise | null> { return inContext(orm, async (em) => { - const found = await em.findOne(entity, where, { disableIdentityMap: true }); + const anyRow = typeof where === 'object' && where !== null && Object.keys(where).length === 0; + const found = anyRow + ? (await em.find(entity, where, { limit: 1, disableIdentityMap: true }))[0] + : await em.findOne(entity, where, { disableIdentityMap: true }); return found ? toRow(found) : null; }); } @@ -110,7 +125,7 @@ export function updateRows( where: FilterQuery, data: EntityData, ): Promise { - return inContext(orm, (em) => { + return inContext(orm, async (em) => { assertWritable(em, entity, data); return em.nativeUpdate(entity, where, data); });