Skip to content

Commit

Permalink
ok
Browse files Browse the repository at this point in the history
  • Loading branch information
dickermoshe committed Oct 20, 2024
1 parent 209ae69 commit 7fb21ba
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 75 deletions.
98 changes: 84 additions & 14 deletions docs/docs/dart_api/manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,99 @@ description: Use easier bindings for common queries.

---

Drift offers three main approaches for querying your database:

The examples on this page use the database from the [setup](../setup.md)
instructions.
- **Manages API**: The Manager API provides a simpler, more intuitive interface for common operations
- **Core API**: The Core API provides a more flexible and powerful interface for complex queries
- **Raw SQL**: For those comfortable with SQL, you can write raw SQL queries directly. The SQL is parsed and validated at compile time.

When manager generation is enabled (default), drift will generate a manager for each table in the database.
A collection of these managers are accessed by a getter `managers` on the database class.
Each table will have a manager generated for it unless it uses a custom row class.
This page will cover the Manager API and the Core API. For more information on raw SQL queries, see the [Raw SQL](./raw_sql.md) page.

## Select
??? tip "Disable Manager API"
If you don't want to use the Manager API, you can disable it by setting `generate_manager` to `false` in the `drift` section of your `build.yaml` file. This will save you some build time and reduce the size of your generated code.

```yaml title="build.yaml"
targets:
$default:
builders:
drift_dev:
options:
generate_manager: false
```

### Example schema

The examples on this page use the following database schema:

{{ load_snippet('before_generation','lib/snippets/setup/database.dart.excerpt.json') }}


## Read

=== "Manager API"


To select all rows from a table, just call the `get()`/`watch()` method on the table manager. This will return a list of all rows in the table.

{{ load_snippet('manager_select','lib/snippets/dart_api/manager.dart.excerpt.json') }}

=== "Core API"

Write `SELECT` queries using the `select` method on the database class. This method returns a query object which can be used to retrieve rows from the database.

Any query can be run once with `get()` or be turned into an auto-updating stream using `watch()`.

{{ load_snippet('core_select','lib/snippets/dart_api/manager.dart.excerpt.json') }}


### Limit and Offset

You can limit the amount of results returned by calling `limit` on queries. The method accepts
the amount of rows to return and an optional offset.

=== "Manager API"

{{ load_snippet('manager_limit','lib/snippets/dart_api/manager.dart.excerpt.json') }}

=== "Core API"

{{ load_snippet('core_limit','lib/snippets/dart_api/manager.dart.excerpt.json') }}



### Filtering

#### Simple filters

Drift generates prebuilt filters for each column in your table. These filters can be used to filter rows based on the value of a column.

=== "Manager API"

You can apply filters to a query by calling `filter()`. The filter method takes a function that should return a filter on the given table.

{{ load_snippet('manager_filter','lib/snippets/dart_api/manager.dart.excerpt.json') }}

=== "Core API"

You can apply filters to a query by calling `where()`. The `where` method takes a function that should map the given table to an `Expression` of boolean. For more details on expressions, see the [expression](./expressions.md) docs.

{{ load_snippet('core_filter','lib/snippets/dart_api/manager.dart.excerpt.json') }}

#### Complex filters

- Use the `&` and `|` operators to combine multiple filters.
- Use `()` to group filters.
- Use `.not` to negate a condition.

The manager simplifies the process of retrieving rows from a table. Use it to read rows from the table or watch
for changes.

{{ load_snippet('manager_select','lib/snippets/dart_api/manager.dart.excerpt.json') }}
=== "Manager API"

The manager provides a really easy to use API for selecting rows from a table. These can be combined with `|` and `&` and parenthesis to construct more complex queries. Use `.not` to negate a condition.
{{ load_snippet('manager_complex_filter','lib/snippets/dart_api/manager.dart.excerpt.json') }}

{{ load_snippet('manager_filter','lib/snippets/dart_api/manager.dart.excerpt.json') }}
=== "Core API"

Every column has filters for equality, inequality and nullability.
Type specific filters for `int`, `double`, `Int64`, `DateTime` and `String` are included out of the box.
{{ load_snippet('core_complex_filter','lib/snippets/dart_api/manager.dart.excerpt.json') }}

{{ load_snippet('manager_type_specific_filter','lib/snippets/dart_api/manager.dart.excerpt.json') }}


### Referencing other tables
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/dart_api/tables.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---

title: Tables
title: Schema
description: Define the schema of your database.

---
Expand Down
185 changes: 130 additions & 55 deletions docs/lib/snippets/dart_api/manager.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: invalid_use_of_internal_member, unused_local_variable, unused_element
// ignore_for_file: invalid_use_of_internal_member, unused_local_variable, unused_element, avoid_single_cascade_in_expression_statements

import 'package:drift/drift.dart';

Expand Down Expand Up @@ -103,43 +103,6 @@ extension ManagerExamples on AppDatabase {
}
// #enddocregion manager_delete

// #docregion manager_select
Future<void> selectTodoItems() async {
// Get all items
managers.todoItems.get();

// A stream of all the todo items, updated in real-time
managers.todoItems.watch();

// To get a single item, apply a filter and call `getSingle`
await managers.todoItems.filter((f) => f.id(1)).getSingle();
}
// #enddocregion manager_select

// #docregion manager_filter
Future<void> filterTodoItems() async {
// All items with a title of "Title"
managers.todoItems.filter((f) => f.title("Title"));

// All items with a title of "Title" and content of "Content"
managers.todoItems.filter((f) => f.title("Title") & f.content("Content"));

// All items with a title of "Title" or content that is not null
managers.todoItems.filter((f) => f.title("Title") | f.content.not.isNull());
}
// #enddocregion manager_filter

// #docregion manager_type_specific_filter
Future<void> filterWithType() async {
// Filter all items created since 7 days ago
managers.todoItems.filter(
(f) => f.createdAt.isAfter(DateTime.now().subtract(Duration(days: 7))));

// Filter all items with a title that starts with "Title"
managers.todoItems.filter((f) => f.title.startsWith('Title'));
}
// #enddocregion manager_type_specific_filter

// #docregion manager_ordering
Future<void> orderWithType() async {
// Order all items by their creation date in ascending order
Expand Down Expand Up @@ -210,23 +173,6 @@ extension ManagerExamples on AppDatabase {
}
// #enddocregion manager_filter_custom_back_references

// #docregion manager_references
Future<void> references() async {
/// Get each todo, along with a its categories
final todosWithRefs = await managers.todoItems.withReferences().get();
for (final (todo, refs) in todosWithRefs) {
final category = await refs.category?.getSingle();
}

/// This also works in the reverse
final categoriesWithRefs =
await managers.todoCategory.withReferences().get();
for (final (category, refs) in categoriesWithRefs) {
final todos = await refs.todoItemsRefs.get();
}
}

// #enddocregion manager_references
// #docregion manager_prefetch_references
Future<void> referencesPrefetch() async {
/// Get each todo, along with a its categories
Expand Down Expand Up @@ -392,3 +338,132 @@ void _managerAggregatedAnnotations(AppDatabase db) async {
}
// #enddocregion aggregated_annotations
}

Future<void> selectTodoItems(AppDatabase db) async {
// #docregion manager_select
await db.managers.todoItems.get();
// #enddocregion manager_select
// #docregion core_select
await db.select(db.todoItems).get();
// #enddocregion core_select

// #docregion manager_watch
db.managers.todoItems.watch();

// #enddocregion manager_watch
// #docregion core_watch
db.select(db.todoItems).watch();
// #enddocregion core_watch

// #docregion manager_limit
// Get 1st 10 items
await db.managers.todoItems.limit(10).get();
// Get the next 10 items
await db.managers.todoItems.limit(10, offset: 10).get();
// #enddocregion manager_limit
// #docregion core_limit
// Get 1st 10 items
await (db.select(db.todoItems)..limit(10)).get();
// Get the next 10 items
await (db.select(db.todoItems)..limit(10, offset: 10)).get();
// #enddocregion core_limit
}

Future<void> filterTodoItems(AppDatabase db) async {
// #docregion manager_filter
// All items with a title of "Title"
db.managers.todoItems.filter((f) => f.title("Title"));
// #enddocregion manager_filter

// #docregion core_filter
// All items with a title of "Title"
db.select(db.todoItems)..where((tbl) => tbl.title.equals("Title"));
// #enddocregion core_filter

// #docregion manager_complex_filter
// All items with a title of "Title" and content of "Content"
db.managers.todoItems.filter((f) => f.title("Title") & f.content("Content"));

/// Todos that:
/// 1. Have a title that is not "Title"
/// OR
/// 2. Have no content and start with "Hello World"
db.managers.todoItems.filter(
(f) =>
f.title("Title").not() |
(f.content.isNull() & f.content.startsWith("Hello World")),
);
// #enddocregion manager_complex_filter

// #docregion core_complex_filter
// All items with a title of "Title" and content of "Content"
db.select(db.todoItems)
..where((tbl) => tbl.title.equals("Title") & tbl.content.equals("Content"));

/// Todos that:
/// 1. Have a title that is not "Title"
/// OR
/// 2. Have no content and start with "Hello World"
db.select(db.todoItems)
..where(
(tbl) =>
tbl.title.equals("Title").not() |
(tbl.content.isNull() & tbl.content.like("Hello World%")),
);
// #enddocregion core_complex_filter
}

Future<void> filterTodoItemsRefs(AppDatabase db) async {
// #docregion manager_filter_references
// All items with a category description of "School"
db.managers.todoItems.filter((f) => f.category.description("School"));
// #enddocregion manager_filter_references

// #docregion core_filter_references
// All items with a title of "Title"
db.select(db.todoItems).join([
leftOuterJoin(
db.todoCategory, db.todoCategory.id.equalsExp(db.todoItems.category),
useColumns: false)
]).where(db.todoCategory.description.equals("School"));
// #enddocregion core_filter_references

// #docregion manager_references
for (final (todo, refs)
in await db.managers.todoItems.withReferences().get()) {
final category = await refs.category?.getSingle();
print(
'Todo ${todo.id} has a category with the description ${category?.description}');
}
// #enddocregion manager_references
// #docregion manager_references_prefetch
for (final (todo, refs) in await db.managers.todoItems
.withReferences((prefetch) => prefetch(category: true))
.get()) {
final category = refs.category?.prefetchedData?.firstOrNull;
print(
'Todo ${todo.id} has a category with the description ${category?.description}');
}
// #enddocregion manager_references_prefetch

// #docregion core_references
// Build a select statement with a left outer join to fetch the referenced data
final query = db.select(db.todoItems).join([
leftOuterJoin(
db.todoCategory, db.todoCategory.id.equalsExp(db.todoItems.category))
])
..where(db.todoCategory.description.equals("School"));

// Map the results to a list of tuples containing the todo and category
final results = await query
.asyncMap((p0) =>
(p0.readTable(db.todoItems), p0.readTableOrNull(db.todoCategory)))
.get();

// Print the results
for (final (todo, category) in results) {
print(
'Todo ${todo.id} has a category with the description ${category?.description}');
}
// #enddocregion core_references
}
5 changes: 1 addition & 4 deletions docs/lib/snippets/setup/database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class TodoCategory extends Table {
TextColumn get description => text()();
}

// #enddocregion before_generation
// #enddocregion table
@DriftDatabase(tables: [TodoItems, TodoCategory])
class AppDatabase extends _$AppDatabase {
// #enddocregion before_generation
// After generating code, this class needs to define a `schemaVersion` getter
// and a constructor telling drift where the database should be stored.
// These are described in the getting started guide: https://drift.simonbinder.eu/getting-started/#open
Expand All @@ -50,10 +50,7 @@ class AppDatabase extends _$AppDatabase {
static QueryExecutor _openConnection() {
throw 'should not show as snippet';
}

// #docregion before_generation
}
// #enddocregion before_generation

class OpenFlutter {
// #docregion flutter
Expand Down
3 changes: 2 additions & 1 deletion docs/mkdocs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ theme:
logo: images/icon.png
favicon: images/icon.png
features:
- content.tabs.link
- content.tooltips
- navigation.instant
- navigation.tracking
Expand Down Expand Up @@ -94,8 +95,8 @@ nav:
- Documentation:
- Getting Started: setup.md
- dart_api/tables.md
- dart_api/dataclass.md
- dart_api/manager.md
- dart_api/dataclass.md
- dart_api/transactions.md
- Core API:
- dart_api/select.md
Expand Down

0 comments on commit 7fb21ba

Please sign in to comment.