Store constructor

Store(
  1. ModelDefinition modelDefinition, {
  2. String? directory,
  3. int? maxDBSizeInKB,
  4. int? fileMode,
  5. int? maxReaders,
  6. int? debugFlags,
  7. bool queriesCaseSensitiveDefault = true,
  8. String? macosApplicationGroup,
})

Creates a BoxStore using the model definition from your objectbox.g.dart file in the given directory path (or if null the defaultDirectoryPath).

For example in a Flutter app:

getApplicationDocumentsDirectory().then((dir) {
  _store = Store(getObjectBoxModel(), directory: dir.path + "/objectbox");
});

Or for a Dart app:

final store = Store(getObjectBoxModel());

Case insensitive queries

By default, ObjectBox queries are case sensitive. Set queriesCaseSensitiveDefault to false to make queries ignore case by default.

Case sensitivity can also be set for each query.

macOS application group

If you're creating a sandboxed macOS app use macosApplicationGroup to specify the application group. For more details see our online docs.

Maximum database size

maxDBSizeInKB sets the maximum size the database file can grow to. When applying a transaction (e.g. putting an object) would exceed it a DbFullException is thrown.

By default, this is 1 GB, which should be sufficient for most applications. In general, a maximum size prevents the database from growing indefinitely when something goes wrong (for example data is put in an infinite loop).

This value can be changed, so increased or also decreased, each time when opening a store.

File mode

Specify unix-style file permissions for database files with fileMode. E.g. for -rw-r---- (owner, group, other) pass the octal code 0640. Any newly generated directory additionally gets searchable (01) for groups with read or write permissions. It's not allowed to pass in an executable flag.

Maximum number of readers

maxReaders sets the maximum number of concurrent readers. For most applications, the default is fine (about 126 readers).

A "reader" is short for a thread involved in a read transaction. If the maximum is exceeded the store throws DbMaxReadersExceededException. In this case check that your code only uses a reasonable amount of threads.

For highly concurrent setups (e.g. you are using ObjectBox on the server side) it may make sense to increase the number.

Note: Each thread that performed a read transaction and is still alive holds on to a reader slot. These slots only get vacated when the thread ends. Thus, be mindful with the number of active threads.

Debug flags

Pass one or more DebugFlags to debugFlags to enable debug log output:

final store = Store(getObjectBoxModel(),
    debugFlag: DebugFlags.logQueries | DebugFlags.logQueryParameters);

See our examples for more details.

Implementation

Store(ModelDefinition modelDefinition,
    {String? directory,
    int? maxDBSizeInKB,
    int? fileMode,
    int? maxReaders,
    int? debugFlags,
    bool queriesCaseSensitiveDefault = true,
    String? macosApplicationGroup})
    : _defs = modelDefinition,
      _weak = false,
      _queriesCaseSensitiveDefault = queriesCaseSensitiveDefault,
      directoryPath = _safeDirectoryPath(directory),
      _absoluteDirectoryPath =
          path.context.canonicalize(_safeDirectoryPath(directory)) {
  try {
    if (Platform.isMacOS && macosApplicationGroup != null) {
      if (!macosApplicationGroup.endsWith('/')) {
        macosApplicationGroup += '/';
      }
      if (macosApplicationGroup.length > 20) {
        ArgumentError.value(macosApplicationGroup, 'macosApplicationGroup',
            'Must be at most 20 characters long');
      }
      final cStr = macosApplicationGroup.toNativeUtf8();
      try {
        C.posix_sem_prefix_set(cStr.cast());
      } finally {
        malloc.free(cStr);
      }
    }
    _checkStoreDirectoryNotOpen();
    final model = Model(modelDefinition.model);

    final opt = C.opt();
    checkObxPtr(opt, 'failed to create store options');

    try {
      checkObx(C.opt_model(opt, model.ptr));
      final cStr = directoryPath.toNativeUtf8();
      try {
        checkObx(C.opt_directory(opt, cStr.cast()));
      } finally {
        malloc.free(cStr);
      }
      if (maxDBSizeInKB != null && maxDBSizeInKB > 0) {
        C.opt_max_db_size_in_kb(opt, maxDBSizeInKB);
      }
      if (fileMode != null && fileMode >= 0) {
        C.opt_file_mode(opt, fileMode);
      }
      if (maxReaders != null && maxReaders > 0) {
        C.opt_max_readers(opt, maxReaders);
      }
      if (debugFlags != null) {
        C.opt_debug_flags(opt, debugFlags);
      }
    } catch (e) {
      C.opt_free(opt);
      rethrow;
    }
    if (debugLogs) {
      print('Opening store (C lib V${libraryVersion()})... path=$directory'
          ' isOpen=${isOpen(directory)}');
    }

    _cStore = C.store_open(opt);

    _checkStorePointer(_cStore);

    // Always create _reference, so it can be non-nullable.
    // Ensure we only try to access the store created in the same process.
    // Also serves as a simple sanity check/hash.
    _reference = ByteData(2 * _int64Size);
    _reference.setUint64(0 * _int64Size, pid);
    _reference.setUint64(1 * _int64Size, _ptr.address);

    _openStoreDirectories.add(_absoluteDirectoryPath);

    _attachFinalizer();
  } catch (e) {
    _reader.clear();
    rethrow;
  }
}