Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 2.4.6

- Fix crash when manually issuing a transaction statement like `BEGIN` without
using the high-level transaction APIs. [#47](https://github.com/isoos/postgresql-dart/pull/47) by [simolus3](https://github.com/simolus3).

## 2.4.5

- Added support for boolean arrays. [#41](https://github.com/isoos/postgresql-dart/pull/41) by [slightfoot](https://github.com/slightfoot).
Expand Down
6 changes: 3 additions & 3 deletions lib/src/connection_fsm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class _PostgreSQLConnectionStateBusy extends _PostgreSQLConnectionState {
if (message.state == ReadyForQueryMessage.StateTransactionError) {
query.completeError(returningException!);
return _PostgreSQLConnectionStateReadyInTransaction(
query.transaction as _TransactionProxy);
query.transaction as _PostgreSQLExecutionContextMixin);
}
if (returningException != null) {
query.completeError(returningException!);
Expand All @@ -285,7 +285,7 @@ class _PostgreSQLConnectionStateBusy extends _PostgreSQLConnectionState {

if (message.state == ReadyForQueryMessage.StateTransaction) {
return _PostgreSQLConnectionStateReadyInTransaction(
query.transaction as _TransactionProxy);
query.transaction as _PostgreSQLExecutionContextMixin);
}

return _PostgreSQLConnectionStateIdle();
Expand Down Expand Up @@ -314,7 +314,7 @@ class _PostgreSQLConnectionStateReadyInTransaction
extends _PostgreSQLConnectionState {
_PostgreSQLConnectionStateReadyInTransaction(this.transaction);

_TransactionProxy transaction;
_PostgreSQLExecutionContextMixin transaction;

@override
_PostgreSQLConnectionState onEnter() {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: postgres
description: PostgreSQL database driver. Supports statement reuse and binary protocol.
version: 2.4.5
version: 2.4.6
homepage: https://github.com/isoos/postgresql-dart

environment:
Expand Down
11 changes: 11 additions & 0 deletions test/transaction_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -633,5 +633,16 @@ void main() {
});
expect(result, []);
});

test('can start transactions manually', () async {
await conn.execute('BEGIN');
await conn.execute(
'INSERT INTO t VALUES (@a)',
substitutionValues: {'a': 123},
);
await conn.execute('ROLLBACK');

await expectLater(conn.query('SELECT * FROM t'), completion(isEmpty));
});
Copy link

@marcotas marcotas Jul 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@simolus3 and @isoos is it possible to run queries inside the transaction? Something like this:

test('some tests in a transaction', () {
  await conn.execute('begin');
  await conn.execute('insert somethings');
  var results = await conn.query('select somethings');
  expect(results.length, 2);
  await conn.execute('rollback');
});

The reason why is because I'm running each tests inside transactions to increase test performance significantly. Laravel framework does this in their tests and it works perfectly. I've being using this approach for years and it is a very good feature during testing. This is a real example of how I can run the tests on Tunder framework (for dart):

main() {
  group('Some tests', () {
    useDatabaseTransactions();
    
    test('this test will execute inside a transction so you can follow the AAA approach', () async {
      // Arrange
      ContactFactory().createMany(10);
      
      // Act
      var contacts = Query<Contact>().paginate(5);
      
      // Assert
      expect(contacts.data.length, 5);
      expect(contacts.meta.perPage, 5);
    });
  });
}

We have many benefits of this approach:

  1. Faster queries because they're executed in memory and not really persisted in the hard drive or SSD. So no heavy IO operations.
  2. Cleaner tests because we don't need to cleanup the database after each test to make them isolated and less queries per test.
  3. Each test runs completely isolated from contexts because after each test the transaction is rolled back.

If this is not possible right now, how hard would be to implement something like this?

I'm really really looking forward to work with this. If this is possible I'll be definitely migrating it to this package. And thank you so much for all of you guys maintaining this package.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other projects we are using testWithX methods, e.g. testWithDbTransactions, where the helper method sets up the test, prepends it with DB connection initialization and cleanup afterwards. It is nice as the test's inner method is a callback, so you can do anything before/after easily.

For this specific case, I'm not familiar what the contactfactory does, but it looks like as a global variable, which will usually cause conflicts with tests that may be running concurrently.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Thank you for sharing that. It seems it's a pattern in Dart community. I'm reading the tests to understand the behaviour of the package. Thank you for your help @isoos 👍🏻

});
}