Skip to main content

Driver Internals

This section explains how drivers plug into Ormed and how queries/mutations are represented internally.

Prerequisites

What You’ll Learn

  • How plans move from ORM APIs to driver execution
  • How preview vs execute paths differ
  • Where to hook custom extensions for advanced driver behavior

Step Outcome

By the end of this page, you should be able to:

  • Explain how QueryPlan/MutationPlan become driver statements
  • Use describe/preview paths for debugging without side effects
  • Decide when driver extensions are better than raw SQL snippets

If you are building tooling (SQL previews, migrations UI, diagnostics) or implementing a custom driver adapter, these are the core concepts you’ll interact with.

The pipeline

At a high level:

  1. The query builder produces an immutable plan (QueryPlan or MutationPlan)
  2. A QueryContext (created by DataSource) asks the driver to describe or execute the plan
  3. The driver uses its compiler/dialect to produce a StatementPreview
  4. The driver executes the statement and returns rows / affected counts

Important distinction:

  • Describe returns a preview (useful for logging/testing/dry-runs)
  • Execute performs the operation on the backend

Use describe paths in observability tooling and test diagnostics; use execute paths only in runtime mutation/read flows.

Debugging SQL without executing

StatementPreview previewSelectSql(DataSource dataSource) {
return dataSource.query<$User>().whereEquals('email', 'a@b.com').toSql();
}

Next:

  • “Plans & Previews” dives into what lives inside QueryPlan / MutationPlan and how previews are normalized.
  • “Schema” covers the schema interfaces used by migrations, schema dumps, and introspection.

Driver extensions

Driver extensions let third-party packages register custom query clause compilers without resorting to raw SQL helpers. Extensions are registered per driver and exposed through query builder helpers:

final dataSource = DataSource(
DataSourceOptions(
driver: PostgresDriverAdapter.fromUrl(env['DATABASE_URL']!),
driverExtensions: [MyVectorSearchExtension()],
entities: registry.allDefinitions,
),
);
final preview = dataSource.query<Post>()
.selectExtension('vector_rank', payload: {'query': embedding}, alias: 'rank')
.whereExtension('vector_match', {'query': embedding})
.orderByExtension('vector_rank', payload: {'query': embedding}, descending: true)
.toSql();

Supported hooks include:

  • selectExtension
  • whereExtension / havingExtension
  • orderByExtension / groupByExtension
  • JoinBuilder.onExtension for JOIN constraints

If a custom clause key is missing for the active driver, compilation fails with an actionable error that includes the missing key and driver name.

Extension Design Guidelines

  1. Keep payload schemas explicit and typed where possible.
  2. Provide deterministic SQL generation for preview + execution parity.
  3. Add integration tests per driver capability.
  4. Fail loudly on unsupported clause keys.

Postgres extensions example package

A consolidated Postgres extensions package lives in packages/ormed_postgres_extensions. It ships typed payloads and handlers for PostGIS (ST_DWithin, ST_Distance, ST_AsGeoJSON), pgvector distance operations, and contrib extensions like pg_trgm, hstore, ltree, citext, uuid-ossp, and pgcrypto. This package is a reference implementation and is not published.

Integration tests and Docker Compose setups live alongside it:

  • packages/ormed_postgres_extensions/test/postgis_extension_integration_test.dart
  • packages/ormed_postgres_extensions/test/pgvector_extension_integration_test.dart
  • tool/docker/postgis/docker-compose.yml
  • tool/docker/postgres/docker-compose.yml
  • tool/docker/pgvector/docker-compose.yml