Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/mainser/cindel/llms.txt

Use this file to discover all available pages before exploring further.

CindelDatabase is the runtime handle that sits between your application code and the native storage engine. It is returned by Cindel.open and Cindel.openInMemory and provides access to typed collections via generated extension getters, raw transaction control via readTxn and writeTxn, and lower-level maintenance operations such as documentIds and documentIdsPage. Every interaction with the database flows through this object until close is called.

Properties

directory

final String directory
The directory path passed to Cindel.open. In-memory databases report the internal sentinel value ':memory:' rather than a real filesystem path.
directory
String
The directory where database files are stored on disk, or ':memory:' for databases opened with Cindel.openInMemory.

backend

final CindelStorageBackend backend
The storage backend that was selected when the database was opened. This value reflects the backend argument passed to Cindel.open or Cindel.openInMemory and does not change for the lifetime of the handle.
backend
CindelStorageBackend
Either CindelStorageBackend.mdbx or CindelStorageBackend.sqlite.

isInWriteTransaction

bool get isInWriteTransaction
Returns true while this handle is executing the callback passed to writeTxn. This is false outside a write transaction and also false inside a readTxn callback.
isInWriteTransaction
bool
true if a write transaction is currently active on this handle; false otherwise.
await db.writeTxn(() async {
  print(db.isInWriteTransaction); // true
  await db.users.put(user);
});

print(db.isInWriteTransaction); // false

Lifecycle

close

Closes the database and releases all native resources held by this handle. Any active transaction is rolled back before the underlying engine connection is released. Registered watchers are cancelled. Calling close more than once is safe — subsequent calls are no-ops.
Future<void> close()
Usage
final db = await Cindel.open(
  directory: dir.path,
  schemas: [UserSchema],
);

try {
  await db.users.put(user);
} finally {
  await db.close();
}
In tests, prefer addTearDown:
final db = await Cindel.openInMemory(schemas: [UserSchema]);
addTearDown(db.close);
Future<void>
Future<void>
Resolves when the native handle has been closed and all internal resources have been freed.

Transactions

readTxn

Runs action inside a native read transaction, providing a consistent snapshot of the database for the duration of the call. All reads performed by this handle inside action observe the same committed state, even if other isolates or processes write to the database concurrently. Attempting to call any write operation — such as put, delete, or writeTxn — inside a readTxn callback throws CindelTransactionError.
Future<T> readTxn<T>(Future<T> Function() action)
Usage
// Read a consistent snapshot of related collections together.
final (users, orders) = await db.readTxn(() async {
  final u = await db.users.filter().activeEqualTo(true).findAll();
  final o = await db.orders.filter().statusEqualTo('open').findAll();
  return (u, o);
});
Parameters
action
Future<T> Function()
required
An asynchronous callback that executes inside the read transaction. The transaction is held open for the entire duration of the Future returned by this callback. The callback must not start a nested transaction.
Returns
Future<T>
Future<T>
Resolves to the value returned by action after the read transaction commits.
Throws
ErrorCondition
CindelTransactionErrorA write operation was attempted inside the read transaction, or a nested transaction was started.

writeTxn

Runs action inside a native write transaction. All writes performed by this handle inside action are committed atomically when action completes successfully. If action throws, the transaction is rolled back and none of the pending writes are persisted. Watchers are not notified on rollback.
Future<T> writeTxn<T>(Future<T> Function() action)
Usage
// Create a user and their first order atomically.
await db.writeTxn(() async {
  await db.users.put(user);
  await db.orders.put(order);
});
Rollback on failure:
try {
  await db.writeTxn(() async {
    await db.users.put(user);
    throw Exception('something went wrong');
    // user is NOT persisted — the transaction rolls back.
  });
} catch (e) {
  // Handle error.
}
Parameters
action
Future<T> Function()
required
An asynchronous callback that executes inside the write transaction. Writes from all typed collection methods called through this handle inside action participate in the same transaction. The callback must not start a nested transaction.
Returns
Future<T>
Future<T>
Resolves to the value returned by action after the write transaction commits. Registered watchers for affected collections are notified after the commit completes.
Throws
ErrorCondition
CindelTransactionErrorA nested transaction was started inside the callback.

Collection Access

typedCollection

Returns a CindelTypedCollection<T> for the given schema. This is the low-level accessor that generated extension getters call internally. In most application code you will use the generated getter — for example db.users — instead of calling typedCollection directly.
CindelTypedCollection<T> typedCollection<T>(CindelCollectionSchema<T> schema)
Usage
// Generated extensions call this internally. You normally write:
final user = await db.users.get(userId);

// Which is equivalent to:
final user = await db.typedCollection(UserSchema).get(userId);
Parameters
schema
CindelCollectionSchema<T>
required
The generated schema constant for the collection, for example UserSchema. The schema must have been passed to Cindel.open via the schemas parameter.
Returns
CindelTypedCollection<T>
CindelTypedCollection<T>
A typed collection accessor for the collection described by schema. The accessor exposes get, put, delete, filter, where, watcher helpers, and other generated operations.

Maintenance

documentIds

Returns the complete list of document ids stored in collection, ordered ascending by id. The result is produced in a single native call and includes every id currently persisted in the collection. For very large collections, prefer documentIdsPage to avoid materializing the full id list at once.
Future<List<int>> documentIds(String collection)
Usage
final allIds = await db.documentIds('users');
print('Total users: ${allIds.length}');
Parameters
collection
String
required
The collection name as declared in the @Collection annotation or the name parameter of CindelCollectionSchema. Must match a collection registered with this database.
Returns
Future<List<int>>
Future<List<int>>
A list of all document ids in the collection, sorted in ascending order. Returns an empty list when the collection is empty.

documentIdsPage

Returns up to limit document ids from collection in ascending order, starting after afterId. This is the recommended approach for backup, export, and maintenance tooling that needs to scan large collections without loading the entire id set into memory at once.
Future<List<int>> documentIdsPage(
  String collection, {
  int? afterId,
  int limit = 1000,
})
Usage
// Stream all orders in bounded pages for backup:
int? afterId;
while (true) {
  final page = await db.documentIdsPage(
    'orders',
    afterId: afterId,
    limit: 500,
  );
  if (page.isEmpty) break;

  final orders = await db.orders.getAll(page);
  await exportPage(orders);

  afterId = page.last;
}
Combine with documentIds when the total count is small enough to hold in memory:
// Small collection — get everything at once:
final ids = await db.documentIds('settings');

// Large collection — page through it:
final firstPage = await db.documentIdsPage('events', limit: 1000);
Parameters
collection
String
required
The collection name. Must match a collection registered with this database.
afterId
int?
When provided, only ids strictly greater than afterId are returned. Omit this parameter (or pass null) to start from the beginning of the collection. On subsequent pages, pass the last id from the previous page.
limit
int
default:"1000"
The maximum number of ids to return. Must be a positive integer. Defaults to 1000. The actual page size may be smaller when fewer ids remain after afterId.
Returns
Future<List<int>>
Future<List<int>>
Up to limit document ids from collection, all strictly greater than afterId, sorted in ascending order. Returns an empty list when the page is exhausted or the collection is empty.

Error Types

The methods on CindelDatabase throw typed errors from package:cindel/cindel.dart:
ErrorWhen thrown
CindelDatabaseClosedErrorA method is called after close() has been called.
CindelTransactionErrorA write is attempted inside readTxn, or a nested transaction is started.
CindelOpenErrorThe native engine could not open the database (thrown by Cindel.open).
CindelNativeErrorThe native engine returned an unexpected error from a storage operation.
CindelSchemaErrorA collection or field referenced in an operation has no registered schema.
CindelQueryErrorA query references a field that is not indexed, or an unsupported query shape is used.
CindelUniqueIndexErrorA put would violate a unique index constraint — a different document already holds the same value for a unique: true index field.

Complete Example

The following shows a representative open–use–close lifecycle using transactions, typed collections, and a paged id scan:
import 'package:cindel/cindel.dart';
import 'package:path_provider/path_provider.dart';

Future<void> main() async {
  final dir = await getApplicationDocumentsDirectory();

  final db = await Cindel.open(
    directory: dir.path,
    schemas: [UserSchema, OrderSchema],
  );

  // Atomic write — both puts commit together or neither does.
  await db.writeTxn(() async {
    final user = User()
      ..email = 'ada@example.com'
      ..name = 'Ada Lovelace';
    await db.users.put(user);

    final order = Order()
      ..userId = user.dbId
      ..total = 42.00;
    await db.orders.put(order);
  });

  // Consistent read snapshot.
  final (users, orders) = await db.readTxn(() async {
    final u = await db.users.filter().activeEqualTo(true).findAll();
    final o = await db.orders.filter().statusEqualTo('open').findAll();
    return (u, o);
  });
  print('Active users: ${users.length}, open orders: ${orders.length}');

  // Page through a large collection for backup.
  int? afterId;
  while (true) {
    final page = await db.documentIdsPage('orders', afterId: afterId, limit: 500);
    if (page.isEmpty) break;
    final batch = await db.orders.getAll(page);
    await exportBatch(batch);
    afterId = page.last;
  }

  await db.close();
}

Build docs developers (and LLMs) love