Skip to content

Commit a8ccf9e

Browse files
committed
Query - reimplement findFirst() using DataVisitor to avoid side-effects
1 parent b8585e6 commit a8ccf9e

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

objectbox/lib/src/native/bindings/data_visitor.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ import 'bindings.dart';
3333
/// visitor.userData, offset, limit);
3434
/// visitor.close(); // make sure to close the visitor
3535
/// checkObx(err);
36+
///
37+
/// TODO do we actually need to go through these hoops?
38+
/// Why don't we create a `Pointer.fromFunction((...) => ...), 0)` as needed?
39+
/// Or better yet, create them only once and reuse (where possible)?
3640
3741
int _lastId = 0;
3842
final _callbacks = <int, bool Function(Pointer<Uint8> dataPtr, int length)>{};
@@ -49,12 +53,14 @@ int _forwarder(Pointer<Void> callbackId, Pointer<Void> dataPtr, int size) {
4953
return callback(dataPtr.cast<Uint8>(), size) ? 1 : 0;
5054
}
5155

56+
final Pointer<NativeFunction<obx_data_visitor>> _forwarderPtr =
57+
Pointer.fromFunction(_forwarder, 0);
58+
5259
/// A data visitor wrapper/forwarder to be used where obx_data_visitor is expected.
5360
class DataVisitor {
5461
final Pointer<Int64> _idPtr = malloc<Int64>();
5562

56-
Pointer<NativeFunction<obx_data_visitor>> get fn =>
57-
Pointer.fromFunction(_forwarder, 0);
63+
Pointer<NativeFunction<obx_data_visitor>> get fn => _forwarderPtr;
5864

5965
Pointer<Void> get userData => _idPtr.cast<Void>();
6066

objectbox/lib/src/native/query/query.dart

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ class _ConditionGroupAll extends _ConditionGroup {
611611
/// Use [property] to only return values or an aggregate of a single Property.
612612
class Query<T> {
613613
final Pointer<OBX_query> _cQuery;
614-
final Store store;
614+
final Store store; // TODO make private
615615
final EntityDefinition<T> _entity;
616616

617617
int get entityId => _entity.model.id.id;
@@ -672,15 +672,23 @@ class Query<T> {
672672
void close() => checkObx(C.query_close(_cQuery));
673673

674674
/// Finds Objects matching the query and returns the first result or null
675-
/// if there are no results.
676-
/// Warning: this implicitly sets offset=0 & limit=1 and leaves them set.
677-
/// In the future, this behaviour will change.
675+
/// if there are no results. Note: [offset] and [limit] are respected, if set.
678676
T? findFirst() {
679-
// TODO move to the core to avoid side-effects
680-
offset(0);
681-
limit(1);
682-
final list = find();
683-
return (list.isEmpty ? null : list[0]);
677+
T? result;
678+
final visitor = DataVisitor((Pointer<Uint8> dataPtr, int length) {
679+
result = _entity.objectFromFB(store, dataPtr.asTypedList(length));
680+
return false; // we only want to visit the first element
681+
});
682+
683+
try {
684+
store.runInTransaction(TxMode.read, () {
685+
checkObx(C.query_visit(_cQuery, visitor.fn, visitor.userData));
686+
});
687+
} finally {
688+
visitor.close();
689+
}
690+
691+
return result;
684692
}
685693

686694
/// Finds Objects matching the query and returns their IDs.

0 commit comments

Comments
 (0)