Skip to content

Commit

Permalink
fix(core): update version values in batch updates
Browse files Browse the repository at this point in the history
Closes #1703
  • Loading branch information
B4nan committed Apr 19, 2021
1 parent f779c26 commit 8476400
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 2 deletions.
14 changes: 14 additions & 0 deletions packages/knex/src/AbstractSqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,20 @@ export abstract class AbstractSqlDriver<C extends AbstractSqlConnection = Abstra
});
});

if (meta.versionProperty) {
const versionProperty = meta.properties[meta.versionProperty];
const quotedFieldName = this.platform.quoteIdentifier(versionProperty.fieldNames[0]);
sql += `${quotedFieldName} = `;

if (versionProperty.type.toLowerCase() === 'date') {
sql += this.platform.getCurrentTimestampSQL(versionProperty.length);
} else {
sql += `${quotedFieldName} + 1`;
}

sql += `, `;
}

sql = sql.substr(0, sql.length - 2) + ' where ';
const pks = Utils.flatten(meta.primaryKeys.map(pk => meta.properties[pk].fieldNames));
sql += pks.length > 1 ? `(${pks.map(pk => `${this.platform.quoteIdentifier(pk)}`).join(', ')})` : this.platform.quoteIdentifier(pks[0]);
Expand Down
2 changes: 1 addition & 1 deletion tests/EntityManager.mysql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2291,7 +2291,7 @@ describe('EntityManagerMySql', () => {
await orm.em.flush();
expect(mock.mock.calls[0][0]).toMatch('begin');
expect(mock.mock.calls[1][0]).toMatch('select `e0`.`id` from `foo_bar2` as `e0` where ((`e0`.`id` = ? and `e0`.`version` = ?) or (`e0`.`id` = ? and `e0`.`version` = ?))');
expect(mock.mock.calls[2][0]).toMatch('update `foo_bar2` set `foo_bar_id` = case when (`id` = ?) then ? when (`id` = ?) then ? else `foo_bar_id` end where `id` in (?, ?)');
expect(mock.mock.calls[2][0]).toMatch('update `foo_bar2` set `foo_bar_id` = case when (`id` = ?) then ? when (`id` = ?) then ? else `foo_bar_id` end, `version` = current_timestamp where `id` in (?, ?)');
expect(mock.mock.calls[3][0]).toMatch('select `e0`.`id`, `e0`.`version` from `foo_bar2` as `e0` where `e0`.`id` in (?, ?)');
expect(mock.mock.calls[4][0]).toMatch('commit');
});
Expand Down
13 changes: 13 additions & 0 deletions tests/EntityManager.postgre.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,19 @@ describe('EntityManagerPostgre', () => {
await expect(orm.em.lock(test, LockMode.OPTIMISTIC)).rejects.toThrowError('Entity Test2 is not managed. An entity is managed if its fetched from the database or registered as new through EntityManager.persist()');
});

test('batch updates increments version field (optimistic locking)', async () => {
const tests = [
new Test2({ name: 't1' }),
new Test2({ name: 't2' }),
new Test2({ name: 't3' }),
];
await orm.em.persistAndFlush(tests);
expect(tests.map(t => t.version)).toEqual([1, 1, 1]);
tests.forEach(t => t.name += ' changed!');
await orm.em.flush();
expect(tests.map(t => t.version)).toEqual([2, 2, 2]);
});

test('pessimistic locking requires active transaction', async () => {
const test = Test2.create('Lock test');
await orm.em.persistAndFlush(test);
Expand Down
2 changes: 1 addition & 1 deletion tests/EntityManager.sqlite2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ describe('EntityManagerSqlite2', () => {
await orm.em.flush();
expect(mock.mock.calls[0][0]).toMatch('begin');
expect(mock.mock.calls[1][0]).toMatch('select `e0`.`id` from `foo_bar4` as `e0` where ((`e0`.`id` = ? and `e0`.`version` = ?) or (`e0`.`id` = ? and `e0`.`version` = ?))');
expect(mock.mock.calls[2][0]).toMatch('update `foo_bar4` set `foo_bar_id` = case when (`id` = ?) then ? when (`id` = ?) then ? else `foo_bar_id` end, `updated_at` = case when (`id` = ?) then ? when (`id` = ?) then ? else `updated_at` end where `id` in (?, ?)');
expect(mock.mock.calls[2][0]).toMatch('update `foo_bar4` set `foo_bar_id` = case when (`id` = ?) then ? when (`id` = ?) then ? else `foo_bar_id` end, `updated_at` = case when (`id` = ?) then ? when (`id` = ?) then ? else `updated_at` end, `version` = `version` + 1 where `id` in (?, ?)');
expect(mock.mock.calls[3][0]).toMatch('select `e0`.`id`, `e0`.`version` from `foo_bar4` as `e0` where `e0`.`id` in (?, ?)');
expect(mock.mock.calls[4][0]).toMatch('commit');
});
Expand Down

0 comments on commit 8476400

Please sign in to comment.