Skip to main content

Typed Data

Description — How to Access Strongly Typed Data in a Type Safe Manner
caution

The typed data API is experimental and might be missing some feature that you need. Please file an issue if you find a bug or have a feature request.

Couchbase Lite allows dynamic access to data without a fixed data model, not requiring any code generation. This is useful when the data is very dynamic or code generation is undesirable.

Often though, the data is known to have a regular structure, and accessing it through a typed Dart API makes working with it easier and safer.

With the help of the cbl_generator package you can quickly create Dart classes that can be used to access data in a typed way. Theses classes can be used with specialized APIs of Database, Query and Replicator.

Getting started

  1. Make sure your app is setup for using Couchbase Lite.

  2. Add cbl_generator and build_runner as development dependencies:

    flutter pub add --dev cbl_generator build_runner
  3. Create typed data classes and annotated them with TypedDocument and TypedDictionary:

    // user.dart

    import 'package:cbl/cbl.dart';

    // Declare the part file into which the generated code will be written.
    part 'user.cbl.type.g.dart';

    // Per default the type of a document is encoded in the `type` property in
    // the underlying data. The value is a string that is the name of the annotated
    // class. This can be customized by setting `TypedDocument.typeMatcher`.
    ()
    abstract class User with _$User {
    factory User({
    () String? id,
    required PersonalName name,
    String? email,
    required String username,
    required DateTime createdAt,
    }) = MutableUser;
    }

    ()
    abstract class PersonalName with _$PersonalName {
    factory PersonalName({
    required String first,
    required String last,
    }) = MutablePersonalName;
    }
  4. Create a typed database by annotating a class with TypedDatabase:

    // app_database.dart

    import 'package:cbl/cbl.dart';

    import 'user.dart';

    (
    // List all the typed data classes that will be used in the database.
    types: {
    User,
    PersonalName,
    },
    )
    abstract class $AppDatabase {}
  5. Run the build runner to invoke the generator:

    dart run build_runner build
    # or
    flutter run build_runner build
  6. Open an instance of the typed database and use it:

    import 'app_database.cbl.database.g.dart';
    import 'user.dart';

    Future<void> useTypedDatabase() {
    // Use a static method on the generated typed database class to open an instance.
    final db = await AppDatabase.openAsync('app');

    // Every typed data class has a mutable and immutable variant. The mutable
    // class has the same name as the immutable class, but with the `Mutable`
    // suffix. A mutable instance can be created by constructing it, or from
    // an immutable instance, through the `toMutable` method.
    final user = MutableUser(
    name: PersonalName(first: 'Alice', last: 'Green'),
    email: 'alice@green.com',
    username: 'ali',
    createdAt: DateTime.now(),
    );

    // The API to save typed documents is slightly different than the API to
    // save plain documents. `saveTypedDocument` returns an object that has methods
    // for saving the document with conflict resolution through concurrency control or
    // a custom conflict handler.
    await database.saveTypedDocument(user).withConcurrencyControl();

    // To retrieve a typed document, use the `typedDocument` method and pass it the
    // type of the requested document through the type parameter.
    final savedUser = await database.typedDocument<User>(user.id);
    }