mirror of https://github.com/AMT-Cheif/drift.git
Document new features for version 1.5
This commit is contained in:
parent
9082236be8
commit
464754267e
|
@ -6,10 +6,15 @@ permalink: /getting-started/
|
|||
---
|
||||
|
||||
# Getting started
|
||||
_Note:_ If you prefer a tutorial video, Reso Coder has made a detailed video explaining
|
||||
how to get started. You can watch it [here](https://youtu.be/zpWsedYMczM).
|
||||
|
||||
{% include content/getting_started.md %}
|
||||
|
||||
Congratulations, you now have a class which you can use to easily write queries.
|
||||
A detailed guide on how to do that is written [here]({{site.url}}/queries/).
|
||||
A detailed guide on how to do that in Dart is written [here]({{"/queries" | absolute_url}}).
|
||||
If you prefer to write SQL and have moor generate the mapping out, check out
|
||||
[custom queries]({{"queries/custom" | absolute_url}})
|
||||
|
||||
PS: You might be asking how you would actually obtain an instance of `MyDatabase` for
|
||||
your widgets. If so, [here]({{site.url}}/faq/#using-the-database) is some guidance.
|
|
@ -11,6 +11,38 @@ features like `GROUP BY` statements or window functions are not yet supported. Y
|
|||
use these features with custom statements. You don't have to miss out on other benefits
|
||||
moor brings, though: Parsing the rows and query-streams also work on custom statements.
|
||||
|
||||
## Statements with a generated api
|
||||
Starting from version `1.5`, you can instruct moor to automatically generate a typesafe
|
||||
API for your select statements. At the moment, this feature is in an experimental state
|
||||
but it can already handle most statements (`select`, `update` and `delete`). Of course,
|
||||
you can still write custom sql manually. See the sections below for details.
|
||||
|
||||
To use this feature, all you need to is define your queries in your `UseMoor` annotation:
|
||||
```dart
|
||||
@UseMoor(
|
||||
tables: [Todos, Categories],
|
||||
queries: {
|
||||
'categoriesWithCount':
|
||||
'SELECT *, (SELECT COUNT(*) FROM todos WHERE category = c.id) AS "amount" FROM categories c;'
|
||||
},
|
||||
)
|
||||
class MyDatabase extends _$MyDatabase {
|
||||
// rest of class stays the same
|
||||
}
|
||||
```
|
||||
After running the build step again, moor will have written the `CategoriesWithCountResult` class for you -
|
||||
it will hold the result of your query. Also, the `_$MyDatabase` class from which you inherit will have the
|
||||
methods `categoriesWithCount` (which runs the query once) and `watchCategoriesWithCount` (which returns
|
||||
an auto-updating stream).
|
||||
|
||||
Queries can have parameters in them by using the `?` or `:name` syntax. When your queries contain parameters,
|
||||
moor will figure out an appropriate type for them and include them in the generated methods. For instance,
|
||||
`'categoryById': 'SELECT * FROM categories WHERE id = :id'` will generate the method `categoryById(int id)`.
|
||||
|
||||
You can also use `UPDATE` or `DELETE` statements here. Of course, this feature is also available for [daos]({{"/daos" | absolute_url}}),
|
||||
and it perfectly integrates with auto-updating streams by analyzing what tables you're reading from or
|
||||
writing to.
|
||||
|
||||
## Custom select statements
|
||||
You can issue custom queries by calling `customSelect` for a one-time query or
|
||||
`customSelectStream` for a query stream that automatically emits a new set of items when
|
||||
|
|
|
@ -51,17 +51,17 @@ Future<List<TodoEntry>> sortEntriesAlphabetically() {
|
|||
You can also reverse the order by setting the `mode` property of the `OrderingTerm` to
|
||||
`OrderingMode.desc`.
|
||||
## Updates and deletes
|
||||
You can use the generated `row` class to update individual fields of any row:
|
||||
You can use the generated classes to update individual fields of any row:
|
||||
```dart
|
||||
Future moveImportantTasksIntoCategory(Category target) {
|
||||
// use update(...).write when you have a custom where clause and want to update
|
||||
// only the columns that you specify (here, only "category" will be updated, the
|
||||
// title and description of the rows affected will be left unchanged).
|
||||
// Notice that you can't set fields back to null with this method.
|
||||
// for updates, we use the "companion" version of a generated class. This wraps the
|
||||
// fields in a "Value" type which can be set to be absent using "Value.absent()". This
|
||||
// allows us to separate between "SET category = NULL" (`category: Value(null)`) and not
|
||||
// updating the category at all: `category: Value.absent()`.
|
||||
return (update(todos)
|
||||
..where((t) => t.title.like('%Important%'))
|
||||
).write(TodoEntry(
|
||||
category: target.id
|
||||
).write(TodosCompanion(
|
||||
category: Value(target.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -70,13 +70,13 @@ Future update(TodoEntry entry) {
|
|||
// using replace will update all fields from the entry that are not marked as a primary key.
|
||||
// it will also make sure that only the entry with the same primary key will be updated.
|
||||
// Here, this means that the row that has the same id as entry will be updated to reflect
|
||||
// the entry's title, content and category. Unlike write, this supports setting columns back
|
||||
// to null. As it set's its where clause automatically, it can not be used together with where.
|
||||
// the entry's title, content and category. As it set's its where clause automatically, it
|
||||
// can not be used together with where.
|
||||
return update(todos).replace(entry);
|
||||
}
|
||||
|
||||
Future feelingLazy() {
|
||||
// delete the oldest nine entries
|
||||
// delete the oldest nine tasks
|
||||
return (delete(todos)..where((t) => t.id.isSmallerThanValue(10))).go();
|
||||
}
|
||||
```
|
||||
|
|
|
@ -21,6 +21,52 @@ and more!
|
|||
|
||||
---
|
||||
|
||||
# Features
|
||||
Moor contains a whole set of features that makes working with persistence much easier and safer.
|
||||
|
||||
## Declarative tables
|
||||
With moor, you can declare your tables in pure dart without having to miss out on advanced sqlite
|
||||
features. Moor will take care of writing the `CREATE TABLE` statements when the database is created.
|
||||
|
||||
## Fluent queries
|
||||
Thanks to the power of Dart build system, moor will let you write typesafe queries:
|
||||
```dart
|
||||
Future<User> userById(int id) {
|
||||
return (select(users)..where((user) => user.id.equals(id))).getSingle();
|
||||
// runs SELECT * FROM users WHERE id = ?, automatically binds the parameter
|
||||
// and parses the result row.
|
||||
}
|
||||
```
|
||||
No more hard to debug typos in sql, no more annoying to write mapping code - moor takes
|
||||
care of all the boring parts.
|
||||
|
||||
## Prefer SQL? Moor got you covered
|
||||
Moor contains a powerful sql parser and analyzer, allowing it to create typesafe APIs for
|
||||
all your sql queries:
|
||||
```dart
|
||||
@UseMoor(
|
||||
tables: [Categories],
|
||||
queries: {
|
||||
'categoryById': 'SELECT * FROM categories WHERE id = :id'
|
||||
},
|
||||
)
|
||||
class MyDatabase extends _$MyDatabase {
|
||||
// the _$MyDatabase class will have the categoryById(int id) and watchCategoryById(int id)
|
||||
// methods that execute the sql and parse its result into a generated class.
|
||||
```
|
||||
All queries are validated and analyzed during build-time, so that moor can provide hints
|
||||
about potential errors quickly and generate efficient mapping code once.
|
||||
|
||||
## Auto-updating streams
|
||||
For all your queries, moor can generate a `Stream` that will automatically emit new results
|
||||
whenever the underlying data changes. This is first-class feature that perfectly integrates
|
||||
with custom queries, daos and all the other features. Having an auto-updating single source
|
||||
of truth makes managing perstistent state much easier!
|
||||
|
||||
## And much moor...
|
||||
Moor also supports transactions, DAOs, powerful helpers for migrations, batched inserts and
|
||||
many more features that makes writing persistence code much easier.
|
||||
|
||||
## Getting started
|
||||
{% include content/getting_started.md %}
|
||||
|
||||
|
@ -28,21 +74,3 @@ You can ignore the `schemaVersion` at the moment, the important part is that you
|
|||
now run your queries with fluent Dart code
|
||||
|
||||
## [Writing queries]({{"queries" | absolute_url }})
|
||||
|
||||
## TODO-List
|
||||
There are some sql features like `group by` statements which aren't natively supported by moor yet.
|
||||
However, as moor supports [custom sql queries]({{"queries/custom" | absolute_url}}), there are easy
|
||||
workarounds for most entries on this list. Custom queries work well together with the regular api,
|
||||
as they integrate with stream queries and automatic result parsing. Starting from version 1.5, moor
|
||||
also has a custom sql parser that can infer types for variables and result columns. It can generate
|
||||
typesafe APIs for sql queries.
|
||||
### Limitations (at the moment)
|
||||
These aren't sorted by priority. If you have more ideas or want some features happening soon,
|
||||
let me know by [creating an issue]({{site.github_link}}/issues/new)! Again, note that these only
|
||||
apply to the Dart api - all of these can be expressed using custom queries which nicely integrates
|
||||
with the rest of the library.
|
||||
- No `group by`, count, or window functions
|
||||
- Support other platforms:
|
||||
- VM apps
|
||||
- Web apps via `AlaSQL` or a different engine?
|
||||
- References (can be expressed via custom constraints, see issue [#14](https://github.com/simolus3/moor/issues/14))
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
## 1.5.0
|
||||
This version introduces some new concepts and features, which are explained in more detail below.
|
||||
Here is a quick overview of the new features.
|
||||
Here is a quick overview of the new features:
|
||||
- More consistent and reliable callbacks for migrations. You can now use `MigrationStrategy.beforeOpen`
|
||||
to run queries after migrations, but before fully opening the database. This is useful to initialize data.
|
||||
- Greatly expanded documentation, introduced additional checks to provide more helpful error messages
|
||||
- New `getSingle` and `watchSingle` methods on queries: Queries that you know will only
|
||||
return one row can now be instructed to return the value directly instead of wrapping it in a list.
|
||||
- New "update companion" classes to clearly separate between absent values and explicitly setting
|
||||
values back to null.
|
||||
- Experimental support for compiled sql queries. Moor can now generate typesafe APIs for
|
||||
written sql.
|
||||
values back to null - explained below.
|
||||
- Experimental support for compiled sql queries: __Moor can now generate typesafe APIs for
|
||||
written sql__. Read on to get started.
|
||||
|
||||
### Update companions
|
||||
Newly introduced "Update companions" allow you to insert or update data more precisely than before.
|
||||
|
@ -19,12 +22,15 @@ default `Value.absent()`.
|
|||
|
||||
Don't worry, all your existing code will continue to work, this change is fully backwards
|
||||
compatible. You might get analyzer warnings about missing required fields. The migration to
|
||||
update companions will fix that.
|
||||
update companions will fix that. Replacing normal classes with their update companions is simple
|
||||
and the only thing needed to fix that. The [documentation](https://moor.simonbinder.eu/queries/#updates-and-deletes)
|
||||
has been updated to reflect this. If you have additional questions, feel free to
|
||||
[create an issue](https://github.com/simolus3/moor/issues/new).
|
||||
### Compiled sql queries
|
||||
Experimental support for compile time custom statements. Sounds super boring, but it
|
||||
actually gives you a fluent way to write queries in pure sql. The moor generator will figure
|
||||
out what your queries return and automatically generate the boring mapping part. Head on to
|
||||
`TODO: Documentation link` to find out how to use this new feature.
|
||||
[the documentation](https://moor.simonbinder.eu/queries/custom) to find out how to use this new feature.
|
||||
|
||||
Please note that this feature is in an experimental state: Expect minor, but breaking changes
|
||||
in the API and in the generated code. Also, if you run into any issues with this feature,
|
||||
|
|
|
@ -58,7 +58,7 @@ class TableWithoutPK extends Table {
|
|||
queries: {
|
||||
'allTodosWithCategory': 'SELECT t.*, c.id as catId, c."desc" as catDesc '
|
||||
'FROM todos t INNER JOIN categories c ON c.id = t.category',
|
||||
'deleteTodoById': 'DELETE FROM todos WHERE id = ?'
|
||||
'deleteTodoById': 'DELETE FROM todos WHERE id = ?',
|
||||
},
|
||||
)
|
||||
class TodoDb extends _$TodoDb {
|
||||
|
|
|
@ -1,3 +1,41 @@
|
|||
## 1.5.0
|
||||
This version introduces some new concepts and features, which are explained in more detail below.
|
||||
Here is a quick overview of the new features:
|
||||
- More consistent and reliable callbacks for migrations. You can now use `MigrationStrategy.beforeOpen`
|
||||
to run queries after migrations, but before fully opening the database. This is useful to initialize data.
|
||||
- Greatly expanded documentation, introduced additional checks to provide more helpful error messages
|
||||
- New `getSingle` and `watchSingle` methods on queries: Queries that you know will only
|
||||
return one row can now be instructed to return the value directly instead of wrapping it in a list.
|
||||
- New "update companion" classes to clearly separate between absent values and explicitly setting
|
||||
values back to null - explained below.
|
||||
- Experimental support for compiled sql queries: __Moor can now generate typesafe APIs for
|
||||
written sql__. Read on to get started.
|
||||
|
||||
### Update companions
|
||||
Newly introduced "Update companions" allow you to insert or update data more precisely than before.
|
||||
Previously, there was no clear separation between "null" and absent values. For instance, let's
|
||||
say we had a table "users" that stores an id, a name, and an age. Now, let's say we wanted to set
|
||||
the age of a user to null without changing its name. Would we use `User(age: null)`? Here,
|
||||
the `name` column would implicitly be set to null, so we can't cleanly separate that. However,
|
||||
with `UsersCompanion(age: Value(null))`, we know the difference between `Value(null)` and the
|
||||
default `Value.absent()`.
|
||||
|
||||
Don't worry, all your existing code will continue to work, this change is fully backwards
|
||||
compatible. You might get analyzer warnings about missing required fields. The migration to
|
||||
update companions will fix that. Replacing normal classes with their update companions is simple
|
||||
and the only thing needed to fix that. The [documentation](https://moor.simonbinder.eu/queries/#updates-and-deletes)
|
||||
has been updated to reflect this. If you have additional questions, feel free to
|
||||
[create an issue](https://github.com/simolus3/moor/issues/new).
|
||||
### Compiled sql queries
|
||||
Experimental support for compile time custom statements. Sounds super boring, but it
|
||||
actually gives you a fluent way to write queries in pure sql. The moor generator will figure
|
||||
out what your queries return and automatically generate the boring mapping part. Head on to
|
||||
[the documentation](https://moor.simonbinder.eu/queries/custom) to find out how to use this new feature.
|
||||
|
||||
Please note that this feature is in an experimental state: Expect minor, but breaking changes
|
||||
in the API and in the generated code. Also, if you run into any issues with this feature,
|
||||
[reporting them](https://github.com/simolus3/moor/issues/new) would be super appreciated.
|
||||
|
||||
## 1.4.0
|
||||
- Added the `RealColumn`, which stores floating point values
|
||||
- Better configuration for the serializer with the `JsonKey` annotation and the ability to
|
||||
|
|
|
@ -3,6 +3,54 @@
|
|||
Moor is an easy to use, reactive persistence library for Flutter apps. Define your database tables in pure Dart and
|
||||
enjoy a fluent query API, auto-updating streams and more!
|
||||
|
||||
Here are just some of the many features moor provides to make dealing with persistence much
|
||||
easier:
|
||||
|
||||
## Declarative tables
|
||||
With moor, you can declare your tables in pure dart without having to miss out on advanced sqlite
|
||||
features. Moor will take care of writing the `CREATE TABLE` statements when the database is created.
|
||||
|
||||
## Fluent queries
|
||||
Thanks to the power of Dart build system, moor will let you write typesafe queries:
|
||||
```dart
|
||||
Future<User> userById(int id) {
|
||||
return (select(users)..where((user) => user.id.equals(id))).getSingle();
|
||||
// runs SELECT * FROM users WHERE id = ?, automatically binds the parameter
|
||||
// and parses the result row.
|
||||
}
|
||||
```
|
||||
|
||||
No more hard to debug typos in sql, no more annoying to write mapping code - moor takes
|
||||
care of all the boring parts. Moor supports features like order by statements, limits and
|
||||
even joins with this api.
|
||||
|
||||
## Prefer SQL? Moor got you covered
|
||||
Moor contains a powerful sql parser and analyzer, allowing it to create typesafe APIs for
|
||||
all your sql queries:
|
||||
```dart
|
||||
@UseMoor(
|
||||
tables: [Categories],
|
||||
queries: {
|
||||
'categoryById': 'SELECT * FROM categories WHERE id = :id'
|
||||
},
|
||||
)
|
||||
class MyDatabase extends _$MyDatabase {
|
||||
// the _$MyDatabase class will have the categoryById(int id) and watchCategoryById(int id)
|
||||
// methods that execute the sql and parse its result into a generated class.
|
||||
```
|
||||
All queries are validated and analyzed during build-time, so that moor can provide hints
|
||||
about potential errors quickly and generate efficient mapping code once.
|
||||
|
||||
## Auto-updating streams
|
||||
For all your queries, moor can generate a `Stream` that will automatically emit new results
|
||||
whenever the underlying data changes. This is first-class feature that perfectly integrates
|
||||
with custom queries, daos and all the other features. Having an auto-updating single source
|
||||
of truth makes managing perstistent state much easier!
|
||||
|
||||
## And much moor...
|
||||
Moor also supports transactions, DAOs, powerful helpers for migrations, batched inserts and
|
||||
many more features that makes writing persistence code much easier.
|
||||
|
||||
## Getting started
|
||||
For a more detailed guide on using moor, check out the [documentation](https://moor.simonbinder.eu/).
|
||||
### Adding the dependency
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
## 1.5.0
|
||||
- Parse custom queries and write generated mapping code.
|
||||
- Refactorings and minor improvements in the generator
|
||||
|
||||
For more details on the new features, check out changelog of the
|
||||
[moor](https://pub.dev/packages/moor#-changelog-tab-) package.
|
||||
|
||||
## 1.4.0
|
||||
- Added the `RealColumn`, which stores floating point values
|
||||
- Better configuration for the serializer with the `JsonKey` annotation and the ability to
|
||||
|
|
|
@ -36,8 +36,15 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
|||
tablesForThisDb.add(state.parseType(table, element));
|
||||
}
|
||||
|
||||
if (queries.isNotEmpty) {
|
||||
final parser = SqlParser(state, tablesForThisDb, queries)..parse();
|
||||
|
||||
resolvedQueries = parser.foundQueries;
|
||||
}
|
||||
|
||||
if (state.errors.errors.isNotEmpty) {
|
||||
print('Warning: There were some errors while running moor_generator:');
|
||||
print('Warning: There were some errors while running '
|
||||
'moor_generator on ${buildStep.inputId.path}:');
|
||||
|
||||
for (var error in state.errors.errors) {
|
||||
print(error.message);
|
||||
|
@ -50,12 +57,6 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
|||
state.errors.errors.clear();
|
||||
}
|
||||
|
||||
if (queries.isNotEmpty) {
|
||||
final parser = SqlParser(state, tablesForThisDb, queries)..parse();
|
||||
|
||||
resolvedQueries = parser.foundQueries;
|
||||
}
|
||||
|
||||
if (tablesForThisDb.isEmpty) return '';
|
||||
|
||||
final specifiedDb = SpecifiedDatabase(
|
||||
|
|
|
@ -38,6 +38,7 @@ class SqlParser {
|
|||
state.errors.add(MoorError(
|
||||
critical: true,
|
||||
message: 'Error while trying to parse $sql: $e, $s'));
|
||||
return;
|
||||
}
|
||||
|
||||
for (var error in context.errors) {
|
||||
|
|
|
@ -12,6 +12,7 @@ class ColumnResolver extends RecursiveVisitor<void> {
|
|||
@override
|
||||
void visitSelectStatement(SelectStatement e) {
|
||||
_resolveSelect(e);
|
||||
visitChildren(e);
|
||||
}
|
||||
|
||||
void _handle(Queryable queryable, List<Column> availableColumns) {
|
||||
|
|
|
@ -94,7 +94,13 @@ class TypeResolver {
|
|||
} else if (expr is CaseExpression) {
|
||||
return resolveExpression(expr.whens.first.then);
|
||||
} else if (expr is SubQuery) {
|
||||
// todo
|
||||
final columns = expr.select.resultSet.resolvedColumns;
|
||||
if (columns.length != 1) {
|
||||
// select queries _must_ have exactly one column
|
||||
return const ResolveResult.unknown();
|
||||
} else {
|
||||
return justResolve(columns.single);
|
||||
}
|
||||
}
|
||||
|
||||
throw StateError('Unknown expression $expr');
|
||||
|
|
Loading…
Reference in New Issue