How to access/inject ObjectBox database in repository in Flutter - Reso Coder DDD

739

So following another answer of vaind, I implemented this as follows. My architecture follows a merge of Reso Coder's DDD and Clean Architecture tutorials. Basically it is DDD with the local/remote data source layer of Clean Architecture.

INFRASTRUCTURE directory

abstract data sources

abstract class ILocalDataSource {
  Future<JournalDto> getJournal(int id);
  Future<void> storeJournal(JournalDto record);
}
abstract class IRemoteDataSource {
  Future<JournalDto> getJournal(int problemClassId);
}

data source implementation

@LazySingleton (as: ILocalDataSource)
class ObjectBoxDataSource implements ILocalDataSource {
  final Store _store;
  final Box<JournalOboxEntity> _box;
  ObjectBoxDataSource(this._store) : _box = _store.box();

injectable module in infrastructure/core

@module
abstract class ObjectBoxInjectableModule {
  @preResolve               // <<<<<<<<<<<<< needed for async init
  @lazySingleton
  Future<Store> get store async => await openStore();
}

And now the trick to get it work: My later errors where caused by an injector init not yet finished. After changing injection.dart in the root folder to a Future and awaiting the call in main(), it worked. injection.dart now looks like this:

final GetIt getIt = GetIt.instance;

@injectableInit
Future<void> configureInjection(String env) async {
  $initGetIt(getIt, environment: env);
}
Share:
739
w461
Author by

w461

Programmed C long time ago, did some minor VBA in between and currently I am trying to create some basic home schooling apps in flutter and/or swift - just in case...

Updated on November 23, 2022

Comments

  • w461
    w461 over 1 year

    all the examples, I have seen, initialize ObjectBox in a State(less/full)Widget. I am using a layered architecture (currently refactoring to DDD) and wonder, how to inject my ObjectBox properly.

    In my repository, I inject the data sources using the injectable and the getit packages with

    @injectable
    @LazySingleton (as: IJournalsRepository)
    class JournalsRepository implements IJournalsRepository {
      final JournalsRemoteDataSource journalsRemoteDataSource;
      final JournalsLocalDataSource journalsLocalDataSource;
      JournalsRepository(this.journalsLocalDataSource, this.journalsRemoteDataSource);
    

    Those packages then create an instance of JournalsRemoteDataSource and of JournalsRemoteDataSource and inject it into the repository.

    The ObjectBox example shows for initialization

    class _MyHomePageState extends State<MyHomePage> {
      Store? _store;
      @override
      void initState() {
        super.initState();
        openStore().then((Store store) => _store = store;);
      }
    
      @override
      void dispose() {
        _store?.close();  // don't forget to close the store
        super.dispose();
      }
    }
    

    So I am lacking an idea on how an injector could initialize ObjectBox or how I could access the objectBox object from within the injected JournalsRemoteDataSource if I would initialize objectBox in MyApp() (which is upstream to the HomePage)

    PS: reopening the box in JournalsRemoteDataSource on every read/write event has a very poor performance

    ========== UPDATE ========== supplementing my comment to @vaind

    I have found your answer on this similar question in the meantime (not sure why I did not see it, initially). I hope to get this approach working here, too. However, I have still issues initializing the store. My prototype comes from Firestore and looks like this:

    import 'package:firebase_auth/firebase_auth.dart';
    import 'package:injectable/injectable.dart';
    
    @module
    abstract class FirebaseInjectableModule {
      @lazySingleton
      FirebaseAuth get firebaseAuth => FirebaseAuth.instance;
    }
    

    though I do not understand where the getter firebaseAuth comes from and haven't found any explanation, yet. Anyways, I adapted that to

    import 'package:injectable/injectable.dart';
    import 'package:objectbox/objectbox.dart';
    import 'package:test/objectbox.g.dart';
    
    @module
    abstract class ObjectboxInjectableModule {
      @lazySingleton
      Future<Store> get store async => await openStore();
    }
    

    and use this with

    @LazySingleton (as: ILocalDataSource)
    class ObjectBoxDataSource implements ILocalDataSource {
      final Store _store;
      final Box<JournalOboxEntity> _box;
      ObjectBoxDataSource(this._store) : _box = _store.box();
    

    Besides final Store _store being grey in IntelliJ (unused variable), I receive the error

    You tried to access an instance of Store that is not ready yet
    'package:get_it/get_it_impl.dart':
    Failed assertion: line 404 pos 9: 'instanceFactory.isReady'
    
  • w461
    w461 over 2 years
    Hey vaind, thanks for your answer. I am refactoring my code to the splendid tutorial of Reso Coder regarding DDD and unfortunately, I am also not familiar with those packages (why I moving from one problem to the next, currently). I am following a different approach based on another answer of yours and have updated my question accordingly. Maybe you have an idea, how to overcome the new hurdles...
  • w461
    w461 over 2 years
    got it, solution follows