oguimbal / pg-mem

An in memory postgres DB instance for your unit tests
MIT License
1.96k stars 95 forks source link

Rollback doesn't works #285

Open GrassHopper42 opened 1 year ago

GrassHopper42 commented 1 year ago

Describe the bug

I think if multiple insert queries is in transaction and transaction fail, all of it should't be in DB, but successful queries committed in DB. It looks like rollback doesn't work.

To Reproduce

  private lectureInsertQuery = `INSERT INTO lectures
      (name, description, category, price, teacher_id, status, created_at, updated_at)
    VALUES
      ($1, $2, $3, $4, $5, $6, $7, $8)
    RETURNING *`;

  public async saveBulk(lectures: Lecture[]): Promise<Lecture[]> {
    const client = await this.pool.connect();
    let results: Lecture[];

    const insertLecture = async (lecture: Lecture) => {
      const { rows } = await client.query(
        this.lectureInsertQuery,
        lecture.toDB(),
      );
      return Lecture.fromDB(rows[0]);
    };

    try {
      await client.query('BEGIN');
      const insertResults = await lectures.reduce<Promise<Lecture[]>>(
        async (prev, lecture) => {
          let prevResult = await prev;
          const savedLecture = await insertLecture(lecture);
          return Promise.resolve([...prevResult, savedLecture]);
        },
        Promise.resolve([]),
      );
      await client.query('COMMIT');
      results = insertResults;
    } catch (e) {
      await client.query('ROLLBACK');
      throw e;
    } finally {
      client.release();
    }

    return results;
  }

  // test
     it('should rollback with duplicated lecture name', async () => {
        // given
        expect(await repository.findAll()).toHaveLength(3);

        const lecture1 = createLecture({
          name: 'test1',
          description: 'this lecture should rollback after save', // this successfully saved
        });
        const lecture2 = createLecture({
          name: 'test1',
          description: 'this lecture name is duplicate',
        });
        const lecture3 = createLecture({
          name: 'test3',
          description: 'this lecture should not be saved',
        });

        // when
        const actual = async () => {
          await repository.saveBulk([lecture1, lecture2, lecture3]);
        };

        // then
        await expect(actual).rejects.toThrow();
        await expect(repository.findAll()).resolves.toHaveLength(3); // it return 4
      });

pg-mem version

2.6.4

callumjg commented 1 year ago

EDIT: Issue is resolved by updating to 2.6.12

I have come across this issue as well using the pg node adapter. A single insert works fine, but multiple inserts does not.

try {
  await client.query("BEGIN");
  for await (const line of lines) {
    (() => await client.query("SELECT 1 --etc"))();
  }
  await client.query("COMMIT");
} catch (err) {
  await client.query("ROLLBACK");
  throw err;
}