dorm_framework 2.0.0-dev.5 copy "dorm_framework: ^2.0.0-dev.5" to clipboard
dorm_framework: ^2.0.0-dev.5 copied to clipboard

Exposes classes, filters and joins to implement the dORM framework.

dorm_framework #

dorm_framework on pub.flutter-io.cn dorm_framework pub points dorm_framework popularity dorm_framework likes dorm_framework documentation dORM repository License Dart CI

dorm_annotations dorm_generator dorm_memory_database dorm_bloc_database dorm_firebase_database dorm_firestore_database dorm_http_database dorm_mongo_database dorm_mysql_database dorm_postgres_database dorm_sqlite_database dorm_example

dorm_framework defines the engine-independent types used by dORM applications. It describes how generated models become entities and repositories, how reads and writes are expressed, and how engines expose their backend-specific execution through one common contract.

Install #

Add the framework to the application:

dart pub add dorm_framework

A working generated model also needs dorm_annotations, dorm_generator, build_runner, and one engine. The framework package is the center of those contracts; it does not open a database by itself.

The model and repository boundary #

dORM separates three values that are easy to confuse:

  • Data is input used to create or update a model.
  • Model is an identified value that can be persisted or returned by a read.
  • Dependency carries identities needed to construct related data.
  • Entity connects generated data/model types to schema and repository behavior.
  • Repository is the application-facing object for CRUD and reads.

A typical generated flow looks like this:

final User user = await dorm.users.repository.put(
  Creation.auto(
    dependency: const UserDependency(),
    data: UserData(
      username: 'ada',
      email: 'ada@example.com',
      profile: Profile(
        name: 'Ada Lovelace',
        birthDate: DateTime(1815, 12, 10),
        bio: 'Mathematician',
      ),
    ),
  ),
);

final User? loaded = await dorm.users.repository.peek(user.id);

Creation resolves the identity and passes a ResolvedCreation to the generated Entity. The resulting Model is the identified form returned by the repository.

Creating the generated facade #

The generated Dorm class is parameterized by the engine query and page types. Type inference normally handles both:

final Engine engine = Engine();
final dorm = Dorm(engine);

The facade exposes generated accessors such as dorm.users and dorm.products. Each accessor carries its Entity, Repository, schema fields, and relationship paths.

Creating and updating data #

Use put for new Data values. Use push when a Model already has its final identity:

final User created = await dorm.users.repository.put(
  Creation.auto(
    dependency: const UserDependency(),
    data: UserData(
      username: 'ada',
      email: 'ada@example.com',
      profile: Profile(
        name: 'Ada Lovelace',
        birthDate: DateTime(1815, 12, 10),
        bio: 'Mathematician',
      ),
    ),
  ),
);

await dorm.users.repository.push(
  created.copyWith(email: 'ada@lovelace.org'),
);

Use Creation.explicit when the application already owns the final identity:

final User imported = await dorm.users.repository.put(
  Creation.explicit(
    dependency: const UserDependency(),
    data: UserData(
      username: 'grace',
      email: 'grace@example.com',
      profile: Profile(
        name: 'Grace Hopper',
        birthDate: DateTime(1906, 12, 9),
        bio: 'Computer scientist',
      ),
    ),
    identity: 'external-user-42',
  ),
);

For a model whose backend supplies its identity, Creation.auto uses the declared DatabaseGeneratedIdSpec and returns the model after the backend has returned the key.

Reading, filtering, sorting, and pages #

Filters resolve application fields through generated FieldSchema values:

final List<User> users = await dorm.users.repository.peekAll(
  Filter.text('ada', field: UserEntity.fields.username),
  QueryOptions(
    orderBy: [
      OrderBy(UserEntity.fields.username),
    ],
  ),
);

The filter API describes the condition. The engine Query turns the resolved field name into SQL, a selector, a Firebase query, or an HTTP parameter. OffsetPageRequest is the page request accepted by current engines:

final Page<User> page = await dorm.users.repository.peekPage(
  const BaseFilter.empty(),
  const OffsetPageRequest(size: 20, offset: 0),
);

Relationships #

Foreign fields become generated relationship paths. The application uses the same relationship vocabulary regardless of whether the selected engine joins SQL tables, reads documents, or performs several repository reads:

final List<Join<Cart, CartItem>> items = await dorm
    .relations
    .carts
    .items
    .peekAll();

Relationship cardinality is declared by the model metadata and the generated path. Backend query counts and relation optimizations can differ by engine.

Transactions #

Engines that implement TransactionalEngine also generate TransactionalDorm:

final txDorm = TransactionalDorm(engine);

await txDorm.transaction((tx) async {
  final User? user = await tx.users.repository.peek(userId);
  if (user != null) {
    await tx.users.repository.push(user.copyWith(email: 'new@example.com'));
  }
});

The callback receives a temporary Dorm context. Streams are not available in that context. Engines without the capability keep the normal Dorm API.

Swapping engines #

The generated model source is independent of the backend object. To change engines, construct a different Engine and regenerate only when the selected engine changes the generated type context:

final engine = Engine(databaseOrClient);
final dorm = Dorm(engine);

The repository calls stay the same. Backend-specific capabilities do not: identity types, live streams, transactions, query operators, schema setup, and atomicity depend on the selected engine.

Implementing an engine #

A custom engine implements BaseEngine<Q, P>, creates references and relationships, and provides a concrete BaseQuery. Reference methods receive generated Entity metadata and perform the backend operation. The engine owns connection setup and backend-specific serialization details; the framework does not create or close external connections.

Use dorm_test from development code to exercise the portable contract. Keep engine-specific behavior in separate tests.

Important boundaries #

dorm_framework does not execute schemas or migrations itself. It exposes optional migration contracts for dorm_migrations, while each adapter owns the backend-specific execution. It does not make every backend transactional or reactive. A stream may represent a live subscription or only the initial read, depending on the engine. Query features must be supported by the selected backend; dORM does not silently download and filter data on the client.

Learn more #

0
likes
160
points
272
downloads

Documentation

API reference

Publisher

verified publisherenzosantos.dev

Weekly Downloads

Exposes classes, filters and joins to implement the dORM framework.

Homepage
Repository (GitHub)
View/report issues

License

GPL-3.0 (license)

More

Packages that depend on dorm_framework