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
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ class FirebaseDatabasePlugin :
callback(KotlinResult.success(Unit))
}
}
})
}, request.applyLocally)
} catch (e: Exception) {
// Convert generic exceptions to FlutterFirebaseDatabaseException for proper error handling
val flutterException = if (e is FlutterFirebaseDatabaseException) e else FlutterFirebaseDatabaseException.unknown(e.message ?: "Unknown transaction error")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public class FLTFirebaseDatabasePlugin: NSObject, FlutterPlugin, FLTFirebasePlug
let database = getDatabaseFromPigeonApp(app)
let reference = database.reference(withPath: request.path)

reference.runTransactionBlock { currentData in
reference.runTransactionBlock({ currentData in
let semaphore = DispatchSemaphore(value: 0)
var transactionResult: TransactionHandlerResult?

Expand Down Expand Up @@ -284,7 +284,7 @@ public class FLTFirebaseDatabasePlugin: NSObject, FlutterPlugin, FLTFirebasePlug

currentData.value = result.value
return TransactionResult.success(withValue: currentData)
} andCompletionBlock: { error, committed, snapshot in
}, andCompletionBlock: { error, committed, snapshot in
if let error {
completion(.failure(self.createFlutterError(error)))
return
Expand All @@ -304,7 +304,7 @@ public class FLTFirebaseDatabasePlugin: NSObject, FlutterPlugin, FLTFirebasePlug
]

completion(.success(()))
}
}, withLocalEvents: request.applyLocally)
}

func databaseReferenceGetTransactionResult(app: DatabasePigeonFirebaseApp, transactionKey: Int64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,41 @@ void setupDatabaseReferenceTests() {
expect(result.snapshot.value, 5);
});

test('does not emit local transaction events when disabled', () async {
final ref = database.ref('tests/transaction-apply-locally-false');
await ref.set({'count': 0});

final initialEvent = Completer<void>();
final events = <Object?>[];
final subscription = ref.onValue.listen((event) {
if (!initialEvent.isCompleted) {
initialEvent.complete();
return;
}

events.add(event.snapshot.value);
});

try {
await initialEvent.future.timeout(const Duration(seconds: 5));

await ref.runTransaction(
(value) => Transaction.success({
'count': ((value as Map?)?['count'] as int? ?? 0) + 1,
'timestamp': ServerValue.timestamp,
}),
applyLocally: false,
);

await Future<void>.delayed(const Duration(seconds: 1));

expect(events, hasLength(1));
} finally {
await database.goOnline();
Copy link
Copy Markdown

@cabljac cabljac May 7, 2026

Choose a reason for hiding this comment

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

nit: this reconnects to firebase? is this required here? I may be missing something

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When running applyLocally false, it's like you "disconnect" from realtime database, so you need to go back online after the test for the following to run properly :)

await subscription.cancel();
}
});

test('executes transaction', () async {
final ref = database.ref('tests/transaction-exec');
await ref.set(0);
Expand Down
Loading