Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
schultek committed May 1, 2023
2 parents 4caf1a7 + 18be07a commit ef930bc
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 7 deletions.
80 changes: 77 additions & 3 deletions doc/queries_and_actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,90 @@
You can specify a custom query with custom sql by extending the `Query<T, U>` class.
You will then need to implement the `Future<T> apply(Database db, U params)` method.

Additionally to the model tables, you can query the model views to automatically get all resolved
relations without needing to do manual joins. Table names are always plural, e.g. `users` and view
names are in the format as `complete_user_view`.
```dart
class FindInfoPostByTitleQuery extends Query<InfoPostView?, QueryParams> {
final String title;
FindInfoPostByTitleQuery({required this.title});
@override
Future<InfoPostView?> apply(Database db, QueryParams params) async {
final queryable = InfoPostViewQueryable();
final tableName = queryable.tableAlias;
final customQuery = """
SELECT * FROM $tableName
WHERE title='$title'
${params.orderBy != null ? "ORDER BY ${params.orderBy}" : ""}
${params.limit != null ? "LIMIT ${params.limit}" : ""}
${params.offset != null ? "OFFSET ${params.offset}" : ""}
""";
var postgreSQLResult = await db.query(customQuery, params.values);
var objects = postgreSQLResult.map((row) => queryable.decode(TypedMap(row.toColumnMap()))).toList();
return objects.isNotEmpty ? objects.first : null;
}
}
```
then you can query via `db` like below

```dart
final postWithId = await db.posts.query(
FindInfoPostByTitleQuery(title: 'post title'),
QueryParams(),
);
```

## Actions

You can also specify custom `Action`s to perform on your table.
Similar to the queries, you extend the `Action<T>` class and implement the
`Future<void> apply(Database db, T request)` method.

```dart
class UpdateTitleAction extends Action<InfoPostView> {
final String title;
UpdateTitleAction(this.title);
@override
Future<void> apply(Database db, InfoPostView request) async {
await db.query("""
UPDATE posts
SET title = @title
WHERE id = @id
""", {
'title': title,
'id': request.id,
});
}
}
```

then you can run the action via `db` like below

```dart
await db.posts.run(UpdateTitleAction(newTitle), infoPost);
```

Optionally you can define extension functions on Model Repositories for your custom Queries and Actions, just to make it more clear and concise. here is an extension function for the action we defined above on `PostRepository`

```dart
extension PostRespositoryX on PostRepository {
Future<void> updatePostTitle(InfoPostView post, String newTitle) async {
await run(UpdateTitleAction(title: newTitle), post);
}
}
```

and this would be how you run that method via `db` object

```dart
await db.posts.updatePostTitle(infoPost, newTitle);
```

---

<p align="right"><a href="../topics/Migration-topic.html">Next: Migration</a></p>
28 changes: 25 additions & 3 deletions doc/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ For the above example with two views `Complete` and `Reduced`, this would have t
methods:

- `Future<CompleteUserView?> queryCompleteView(String id)`
- `Future<List<CompleteUserView>> queryCompleteViews()`
- `Future<List<CompleteUserView>> queryCompleteViews([QueryParams? params])`
- `Future<ReducedUserView?> queryReducedView(String id)`
- `Future<List<ReducedUserView>> queryReducedViews()`
- `Future<List<ReducedUserView>> queryReducedViews([QueryParams? params])`
- `Future<void> insertOne(UserInsertRequest request)`
- `Future<void> insertMany(List<UserInsertRequest> requests)`
- `Future<void> updateOne(UserUpdateRequest request)`
- `Future<void> updateMany(List<UserUpdateRequest> requests)`
- `Future<void> deleteOne(String id)`
- `Future<void> updateMany(List<String> ids)`
- `Future<void> deleteMany(List<String> ids)`

Each method has a single and multi variant. `UserInsertRequest` and `UserUpdateRequest` are
special generated classes that enable type-safe inserts and updates while respecting data relations
Expand All @@ -37,6 +37,28 @@ the name of a user while keeping the other fields untouched like this:
await db.users.updateOne(UserUpdateRequest(id: 'abc', name: 'Tom'));
```

#### QueryParams

Query methods that return a list of models will accept a `QueryParams` argument
where you can set conditions for you query like where conditions for example.

```dart
// Check if user already exists
final matchingUser = (await db.users.queryUsers(const QueryParams(
where: "email='[email protected]'",
)));
```

**NOTE**: Alternatively to avoid SQL injection it is recommended to use `values` property of `QueryParams` like below example

```dart
// Check if user already exists
final matchingUser = (await db.users.queryUsers(const QueryParams(
where: 'email=@email',
values: {'email': '[email protected]'},
)));
```

---

<p align="right"><a href="../topics/Queries%20&%20Actions-topic.html">Next: Queries & Actions</a></p>
Expand Down
2 changes: 1 addition & 1 deletion doc/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ abstract class User {
@HiddenIn(#Reduced)
String get address;
@ViewedIn(#Company, as: #Info)
@ViewedIn(#Complete, as: #Info)
@HiddenIn(#Reduced)
List<Post> get posts;
}
Expand Down

0 comments on commit ef930bc

Please sign in to comment.