Document list subqueries, add test

This commit is contained in:
Simon Binder 2022-02-05 20:01:58 +01:00
parent a102323857
commit df89513130
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
2 changed files with 98 additions and 12 deletions

View File

@ -225,6 +225,56 @@ from the referred table. For instance, if we had a table `foo` with an `id INT`
and a `bar TEXT` column. Then, `SELECT foo.** FROM foo` might be desugared to and a `bar TEXT` column. Then, `SELECT foo.** FROM foo` might be desugared to
`SELECT foo.id AS "nested_0.id", foo.bar AS "nested_0".bar FROM foo`. `SELECT foo.id AS "nested_0.id", foo.bar AS "nested_0".bar FROM foo`.
## `LIST` subqueries
Starting from Drift version `1.4.0`, subqueries can also be selected as a full
list. Simply put the subquery in a `LIST()` function to include all rows of the
subquery in the result set.
Re-using the `coordinates` and `saved_routes` tables introduced in the example
for [nested results](#nested-results), we add a new table storing coordinates
along a route:
```sql
CREATE TABLE route_points (
route INTEGER NOT NULL REFERENCES saved_routes (id),
point INTEGER NOT NULL REFERENCES coordinates (id),
index_on_route INTEGER,
PRIMARY KEY (route, point)
);
```
Now, assume we wanted to query a route with information about all points
along the way. While this requires two SQL statements, we can write this as a
single drift query that is then split into the two statements automatically:
```sql
routeWithPoints: SELECT
route.**
LIST(SELECT coordinates.* FROM route_points
INNER JOIN coordinates ON id = point
WHERE route = route.id
ORDER BY index_on_route
) AS points
FROM saved_routes route;
```
This will generate a result set containing a `SavedRoute route` field along with a
`List<Point> points` list of all points along the route.
Internally, drift will split this query into two separate queries:
- The outer `SELECT route.** FROM saved_routes route` SQL queries
- A separate `SELECT coordinates.* FROM route_points ... ORDER BY index_on_route` query
that is run for each row in the outer query. The `route.id` reference in the inner
query is replaced with a variable that drift binds to the actual value in the
outer query.
While `LIST()` subqueries are a very powerful feature, they can be costly when the outer query
has lots of rows (as the inner query is executed for each outer row).
Also, as `LIST()` needs a semantic rewrite of the original statement, this feature is only
supported with the `new_sql_code_generation` [build option]({{ '../Advanced Features/builder_options.md' | pageUrl }}).
## Dart interop ## Dart interop
Drift files work perfectly together with drift's existing Dart API: Drift files work perfectly together with drift's existing Dart API:

View File

@ -0,0 +1,36 @@
@TestOn('vm')
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:test/test.dart';
import '../data/tables/custom_tables.dart';
void main() {
late CustomTablesDb db;
setUp(() {
db = CustomTablesDb(NativeDatabase.memory());
});
tearDown(() => db.close());
test('collects results for LIST subqueries', () async {
var results = await db.nested('a').get();
expect(results, isEmpty);
final defaults = await db.withDefaults.insertReturning(
WithDefaultsCompanion.insert(a: const Value('a'), b: const Value(1)));
final constraints = await db.withConstraints
.insertReturning(WithConstraintsCompanion.insert(
a: const Value('one'),
b: 1,
));
results = await db.nested('a').get();
expect(results, hasLength(1));
final result = results.single;
expect(result.defaults, defaults);
expect(result.nestedQuery0, [constraints]);
});
}