Store constructor

Store(
  1. ModelDefinition modelDefinition, {
  2. String? directory,
  3. int? maxDBSizeInKB,
  4. int? maxDataSizeInKB,
  5. int? fileMode,
  6. int? maxReaders,
  7. int? debugFlags,
  8. bool queriesCaseSensitiveDefault = true,
  9. 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());

In-memory database

To use a file-less in-memory database, instead of a directory path pass memory: together with an identifier string as the directory:

final inMemoryStore =
    Store(getObjectBoxModel(), directory: "memory:test-db");

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

When creating a sandboxed macOS app use macosApplicationGroup to specify the application group.

This string value is the DEVELOPMENT_TEAM you can find in your Xcode settings, plus an application-specific suffix. Also check that all macos/Runner/*.entitlements contain a

<dict>
  <key>com.apple.security.application-groups</key>
  <array>
    <string>FGDTDLOBXDJ.demo</string>
  </array>
</dict>

Note: due to limitations in macOS the value must be at most 19 characters.

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.

Maximum data size

maxDataSizeInKB sets the maximum size the data stored in the database can grow to. When applying a transaction (e.g. putting an object) would exceed it a DbMaxDataSizeExceededException is thrown.

Must be below maxDBSizeInKB.

Different from maxDBSizeInKB this only counts bytes stored in objects, excluding system and metadata. However, it is more involved than database size tracking, e.g. it stores an internal counter. Only use this if a stricter, more accurate limit is required.

When the data limit is reached, data can be removed to get below the limit again (assuming the database size limit is not also reached).

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? maxDataSizeInKB,
    int? fileMode,
    int? maxReaders,
    int? debugFlags,
    bool queriesCaseSensitiveDefault = true,
    String? macosApplicationGroup})
    : _closesNativeStore = true,
      _absoluteDirectoryPath = _safeAbsoluteDirectoryPath(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');
      }
      withNativeString(macosApplicationGroup, C.posix_sem_prefix_set);
    }
    _checkStoreDirectoryNotOpen();
    final model = Model(modelDefinition.model);
    final safeDirectoryPath = _safeDirectoryPath(directory);

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

    try {
      checkObx(C.opt_model(opt, model.ptr));
      checkObx(withNativeString(
          safeDirectoryPath, (cStr) => C.opt_directory(opt, cStr)));
      if (maxDBSizeInKB != null && maxDBSizeInKB > 0) {
        C.opt_max_db_size_in_kb(opt, maxDBSizeInKB);
      }
      if (maxDataSizeInKB != null && maxDataSizeInKB > 0) {
        C.opt_max_data_size_in_kb(opt, maxDataSizeInKB);
      }
      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=$safeDirectoryPath"
          " isOpen=${isOpen(safeDirectoryPath)}");
    }

    _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);
    _attachConfiguration(_cStore, modelDefinition, safeDirectoryPath,
        queriesCaseSensitiveDefault);
    _attachFinalizer();
  } catch (e) {
    _readPointers.clear();
    rethrow;
  }
}