# Ecto coverage
QuackDB's Ecto adapter covers analytical reads plus common write and setup workflows. DuckDB's SQL surface is larger than Ecto's native AST, so coverage is tracked in three buckets:
- **Ecto-native**: expressible with normal `Ecto.Query`, schema, repo, or migration APIs and generated by the adapter.
- **Helper/source**: expressible through `QuackDB.Ecto.Analytics`, `QuackDB.Ecto.Spatial`, Ecto `fragment/1`, or QuackDB source helpers.
- **Raw SQL**: DuckDB-native syntax that should be exercised through `Repo.query/3` or `QuackDB.query/4`.
This file is a roadmap, not a claim of complete DuckDB support.
## Coverage matrix
| Area | Feature | Path | SQL generation | Real server | Status |
| --- | --- | --- | --- | --- | --- |
| Basic reads | select/where/order/limit/offset | Ecto-native | yes | yes | covered |
| Schema reads | full schema select / `Repo.get!/2` | Ecto-native | yes | yes | covered |
| Parameters | pinned params and raw params | Ecto-native/raw | yes | yes | covered |
| Joins | inner/left/right/full/cross | Ecto-native | yes | yes | covered |
| Aggregates | count/sum/avg/min/max | Ecto-native | partial | yes | partial |
| Analytical aggregates | median/quantile/list/string_agg/arg_max/arg_min | Helper | yes | yes | covered |
| Aggregate filter | `FILTER (WHERE ...)` | Ecto-native | yes | partial | partial |
| Grouping | group by/having | Ecto-native | yes | yes | covered |
| CTEs | non-recursive CTEs | Ecto-native | yes | yes | covered |
| Windows | row_number/rank/dense_rank/percent_rank/cume_dist | Ecto-native | yes | partial | partial |
| Windows | lag/lead/first_value/last_value/nth_value | Fragment/raw | partial | no | missing |
| Windows | custom frame clauses | Fragment/raw | no | no | missing |
| Sources | CSV/Parquet helpers | Source helpers | yes | yes | covered |
| Sources | JSON/XLSX helpers | Source helpers/raw | partial | partial | partial |
| Source analytics | source helper + aggregate/window | Ecto-native/source | yes | partial | partial |
| Nested analytics | list/struct/map functions | Fragment/raw | partial | no | missing |
| JSON analytics | json_extract/path queries | Helper/source/raw | yes | yes | partial |
| Time series | date_trunc/time_bucket/generate_series | Helper/raw | yes | yes | partial |
| Grouping extensions | grouping sets/rollup/cube | Raw SQL | no | yes | partial |
| QUALIFY | window filtering | Raw SQL | no | yes | partial |
| Pivoting | pivot/unpivot | Raw SQL | no | yes | partial |
| Sampling | using sample | Raw SQL | no | yes | partial |
| Set operations | union/intersect/except | Ecto combinations | yes | yes | covered |
| Inserts | `Repo.insert/2`, `Repo.insert_all/3` | Ecto-native | yes | yes | covered |
| Upserts | `DO NOTHING`, `set`, `inc`, replacement fields | Ecto-native | yes | yes | covered |
| Native append | `insert_all(..., insert_method: :append)` | Adapter option | yes | yes | covered |
| Mutations | `update_all` / `delete_all` | Ecto-native | yes | yes | covered |
| Schema lifecycle | `Repo.update/2` / `Repo.delete/2` | Ecto-native | yes | yes | covered |
| Migrations | create/drop/alter table, rename table/column, indexes, references | Ecto migration DDL | yes | yes | covered |
| Explain | `Ecto.Adapters.SQL.explain/4` | Ecto SQL | yes | yes | covered |
| Full-text search | BM25 ranking and stemming | Ecto helper fragments | yes | yes | covered |
| Advanced joins | semi/anti/asof/positional | Raw SQL | no | no | missing |
| DuckDB select extensions | `* EXCLUDE`, `* REPLACE`, `COLUMNS(*)` | Raw SQL | no | no | missing |
| Introspection | summarize/describe/pragma | Raw SQL | no | no | missing |
## Migration boundaries
Basic migration DDL is generated for table creation/drop, column add/drop/modify, table and column renames, references, primary keys, composite primary keys, and ordinary/unique indexes. DuckDB-incompatible index options such as concurrent indexes, covering indexes, raw index options, index comments, custom `USING`, and `nulls_distinct` raise explicit QuackDB errors instead of being ignored.
Advanced constraints and comments should be added only where DuckDB can enforce the same semantics. Until then, prefer raw SQL for DuckDB-specific DDL.
## Test organization
Coverage should stay split by expression path:
```text
test/quack_db/ecto/sql_generation/
analytical_test.exs
aggregates_test.exs
fragments_test.exs
migration_test.exs
source_analytics_test.exs
sources_test.exs
update_delete_test.exs
window_functions_test.exs
test/quack_db/integration/ecto/
migration_test.exs
query_test.exs
```
Use SQL generation tests to pin what QuackDB emits for Ecto-native queries. Use real-server tests for DuckDB-native semantics and raw SQL pass-through.
## Boundaries
QuackDB should not try to reimplement all DuckDB syntax as Ecto macros. For DuckDB-specific syntax that Ecto cannot represent cleanly, prefer:
1. raw SQL through `Repo.query/3` or `QuackDB.query/4`;
2. `QuackDB.Ecto.Analytics` for common DuckDB analytical expressions;
3. `QuackDB.Ecto.Spatial` for common spatial expressions;
4. source helpers for table functions such as CSV/Parquet/JSON;
5. `fragment/1` for expressions inside otherwise-normal Ecto queries;
6. explicit unsupported errors for Ecto AST shapes that would generate misleading SQL.
Future adapter-specific helpers may make sense for repeated patterns such as `QUALIFY`, lakehouse sources, or Arrow handoff, but those should be added only after the protocol and result semantics are stable.