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.

Cindel generates typed collection accessors directly on the CindelDatabase handle so your application code never has to deal with string collection names, raw documents, or id bookkeeping. After running build_runner for a User model you get a db.users getter that exposes put, get, delete, and their bulk counterparts — all fully typed, all backed by the same efficient binary storage used internally by Cindel’s query engine.

Accessing Generated Collections

The generator emits a Dart extension on CindelDatabase for each collection you define. The extension getter name is the lower-camel-case plural of your collection’s stored name:
// Generated extension (in user.g.dart):
// extension UserCindelCollectionAccessor on CindelDatabase {
//   CindelTypedCollection<User> get users => typedCollection(UserSchema);
// }

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

// db.users is a CindelTypedCollection<User>
You must pass the corresponding XyzSchema to Cindel.open before using a collection getter — the database needs to register the schema to serve queries and id allocation.

Writing a Single Object — put

put(object) stores one typed object. If the object’s dbId is autoIncrement, Cindel allocates the next id from the native engine and writes it back to the field before the object is stored, so the same instance reflects the assigned id after await:
final ada = User()
  ..email = 'ada@example.com'
  ..name = 'Ada Lovelace';

await db.users.put(ada);

print(ada.dbId); // e.g. 1 — assigned by Cindel

Reading a Single Object — get

get(id) returns the typed object stored under id, or null if no document exists:
final saved = await db.users.get(ada.dbId);

if (saved != null) {
  print(saved.name); // 'Ada Lovelace'
}

Deleting a Single Object — delete

delete(id) removes the document stored under id. If no document exists for that id the call is a no-op:
await db.users.delete(ada.dbId);

Bulk Writes — putAll

putAll stores multiple objects atomically. Input order is preserved and auto-increment ids are allocated before storage:
final grace = User()
  ..email = 'grace@example.com'
  ..name = 'Grace Hopper';

final linus = User()
  ..email = 'linus@example.com'
  ..name = 'Linus Torvalds';

await db.users.putAll([ada, grace, linus]);
Duplicate ids within the same batch are rejected before the batch reaches storage.

Bulk Reads — getAll

getAll([ids]) returns typed objects in the same order as the input id list. Missing ids produce null at that position:
final users = await db.users.getAll([ada.dbId, 404, grace.dbId]);
// [User(ada), null, User(grace)]

Bulk Deletes — deleteAll

deleteAll([ids]) removes every document in the id list atomically. Passing an empty list is a no-op:
await db.users.deleteAll([ada.dbId, grace.dbId]);

// No-op — empty list is safe
await db.users.deleteAll([]);

Unique-Replace Upsert Helpers

When a field is annotated with @Index(unique: true, replace: true), the generator produces a putByFieldName(object) helper that performs a natural-key upsert. Before writing, it looks up any existing document that holds the same indexed value and reuses its id, so you never accidentally create duplicate rows:
@collection
class Account {
  Id dbId = autoIncrement;

  @Index(unique: true, replace: true)
  late String username;

  String? displayName;
}
final account = Account()
  ..username = 'ada'
  ..displayName = 'Ada Lovelace';

// First call — inserts a new row and assigns an id.
await db.accounts.putByUsername(account);

// Second call with the same username — reuses the existing id,
// effectively updating the existing row in place.
account.displayName = 'Ada Augusta Lovelace';
await db.accounts.putByUsername(account);
If another document already holds username == 'ada', putByUsername sets account.dbId to that document’s id before calling put, so the write replaces the existing document rather than inserting a duplicate.

Transactions and Writes

Single writes (one put or delete call outside an explicit transaction) are automatically wrapped in an internal write transaction by Cindel. When you need to write to multiple collections atomically, use an explicit writeTxn block — see Transactions for the full story:
await db.writeTxn(() async {
  await db.users.put(ada);
  await db.accounts.put(account);
});

Build docs developers (and LLMs) love