mirror of https://github.com/AMT-Cheif/drift.git
Generate selectable for custom queries
This makes is easier to use getSingle() and watchSingle() on them. Fixes #120
This commit is contained in:
parent
5d2149d727
commit
0860b6645a
|
@ -8,6 +8,7 @@ void transactionTests(TestExecutor executor) {
|
|||
test('transactions write data', () async {
|
||||
final db = Database(executor.createExecutor());
|
||||
|
||||
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
|
||||
await db.transaction((_) async {
|
||||
final florianId = await db.writeUser(People.florian);
|
||||
|
||||
|
@ -30,6 +31,7 @@ void transactionTests(TestExecutor executor) {
|
|||
final db = Database(executor.createExecutor());
|
||||
|
||||
try {
|
||||
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
|
||||
await db.transaction((_) async {
|
||||
final florianId = await db.writeUser(People.florian);
|
||||
|
||||
|
|
|
@ -832,22 +832,23 @@ abstract class _$Database extends GeneratedDatabase {
|
|||
);
|
||||
}
|
||||
|
||||
Selectable<TotalWeightResult> _totalWeightQuery(
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelectQuery(
|
||||
' SELECT r.title, SUM(ir.amount) AS total_weight\n FROM recipes r\n INNER JOIN recipe_ingredients ir ON ir.recipe = r.id\n GROUP BY r.id\n ',
|
||||
variables: [],
|
||||
readsFrom: {recipes, ingredientInRecipes}).map(_rowToTotalWeightResult);
|
||||
}
|
||||
|
||||
Future<List<TotalWeightResult>> _totalWeight(
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelect(
|
||||
' SELECT r.title, SUM(ir.amount) AS total_weight\n FROM recipes r\n INNER JOIN recipe_ingredients ir ON ir.recipe = r.id\n GROUP BY r.id\n ',
|
||||
variables: []).then((rows) => rows.map(_rowToTotalWeightResult).toList());
|
||||
return _totalWeightQuery(operateOn: operateOn).get();
|
||||
}
|
||||
|
||||
Stream<List<TotalWeightResult>> _watchTotalWeight() {
|
||||
return customSelectStream(
|
||||
' SELECT r.title, SUM(ir.amount) AS total_weight\n FROM recipes r\n INNER JOIN recipe_ingredients ir ON ir.recipe = r.id\n GROUP BY r.id\n ',
|
||||
variables: [],
|
||||
readsFrom: {
|
||||
recipes,
|
||||
ingredientInRecipes
|
||||
}).map((rows) => rows.map(_rowToTotalWeightResult).toList());
|
||||
return _totalWeightQuery().watch();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -111,6 +111,7 @@ mixin QueryEngine on DatabaseConnectionUser {
|
|||
/// although it is very likely that the user meant to call it on the
|
||||
/// [Transaction] t. We can detect this by calling the function passed to
|
||||
/// `transaction` in a forked [Zone] storing the transaction in
|
||||
@protected
|
||||
bool get topLevel => false;
|
||||
|
||||
/// We can detect when a user called methods on the wrong [QueryEngine]
|
||||
|
@ -169,6 +170,8 @@ mixin QueryEngine on DatabaseConnectionUser {
|
|||
/// You can use the [updates] parameter so that moor knows which tables are
|
||||
/// affected by your query. All select streams that depend on a table
|
||||
/// specified there will then issue another query.
|
||||
@protected
|
||||
@visibleForTesting
|
||||
Future<int> customUpdate(String query,
|
||||
{List<Variable> variables = const [], Set<TableInfo> updates}) async {
|
||||
final engine = _resolvedEngine;
|
||||
|
@ -190,11 +193,12 @@ mixin QueryEngine on DatabaseConnectionUser {
|
|||
/// Executes a custom select statement once. To use the variables, mark them
|
||||
/// with a "?" in your [query]. They will then be changed to the appropriate
|
||||
/// value.
|
||||
@protected
|
||||
@visibleForTesting
|
||||
@Deprecated('use customSelectQuery(...).get() instead')
|
||||
Future<List<QueryRow>> customSelect(String query,
|
||||
{List<Variable> variables = const []}) async {
|
||||
return CustomSelectStatement(
|
||||
query, variables, <TableInfo>{}, _resolvedEngine)
|
||||
.get();
|
||||
return customSelectQuery(query, variables: variables).get();
|
||||
}
|
||||
|
||||
/// Creates a stream from a custom select statement.To use the variables, mark
|
||||
|
@ -202,15 +206,36 @@ mixin QueryEngine on DatabaseConnectionUser {
|
|||
/// appropriate value. The stream will re-emit items when any table in
|
||||
/// [readsFrom] changes, so be sure to set it to the set of tables your query
|
||||
/// reads data from.
|
||||
@protected
|
||||
@visibleForTesting
|
||||
@Deprecated('use customSelectQuery(...).watch() instead')
|
||||
Stream<List<QueryRow>> customSelectStream(String query,
|
||||
{List<Variable> variables = const [], Set<TableInfo> readsFrom}) {
|
||||
final tables = readsFrom ?? <TableInfo>{};
|
||||
final statement =
|
||||
CustomSelectStatement(query, variables, tables, _resolvedEngine);
|
||||
return statement.watch();
|
||||
return customSelectQuery(query, variables: variables, readsFrom: readsFrom)
|
||||
.watch();
|
||||
}
|
||||
|
||||
/// Creates a custom select statement from the given sql [query]. To run the
|
||||
/// query once, use [Selectable.get]. For an auto-updating streams, set the
|
||||
/// set of tables the ready [readsFrom] and use [Selectable.watch]. If you
|
||||
/// know the query will never emit more than one row, you can also use
|
||||
/// [Selectable.getSingle] and [Selectable.watchSingle] which return the item
|
||||
/// directly or wrapping it into a list.
|
||||
///
|
||||
/// If you use variables in your query (for instance with "?"), they will be
|
||||
/// bound to the [variables] you specify on this query.
|
||||
@protected
|
||||
@visibleForTesting
|
||||
Selectable<QueryRow> customSelectQuery(String query,
|
||||
{List<Variable> variables = const [],
|
||||
Set<TableInfo> readsFrom = const {}}) {
|
||||
readsFrom ??= {};
|
||||
return CustomSelectStatement(query, variables, readsFrom, _resolvedEngine);
|
||||
}
|
||||
|
||||
/// Executes the custom sql [statement] on the database.
|
||||
@protected
|
||||
@visibleForTesting
|
||||
Future<void> customStatement(String statement) {
|
||||
return _resolvedEngine.executor.runCustom(statement);
|
||||
}
|
||||
|
@ -226,6 +251,8 @@ mixin QueryEngine on DatabaseConnectionUser {
|
|||
/// might be different than that of the "global" database instance.
|
||||
/// 2. Nested transactions are not supported. Creating another transaction
|
||||
/// inside a transaction returns the parent transaction.
|
||||
@protected
|
||||
@visibleForTesting
|
||||
Future transaction(Future Function(QueryEngine transaction) action) async {
|
||||
final resolved = _resolvedEngine;
|
||||
if (resolved is Transaction) {
|
||||
|
|
|
@ -120,6 +120,33 @@ abstract class Selectable<T> {
|
|||
Stream<T> watchSingle() {
|
||||
return watch().transform(singleElements());
|
||||
}
|
||||
|
||||
/// Maps this selectable by using [mapper].
|
||||
///
|
||||
/// Each entry emitted by this [Selectable] will be transformed by the
|
||||
/// [mapper] and then emitted to the selectable returned.
|
||||
Selectable<N> map<N>(N Function(T) mapper) {
|
||||
return _MappedSelectable<T, N>(this, mapper);
|
||||
}
|
||||
}
|
||||
|
||||
class _MappedSelectable<S, T> extends Selectable<T> {
|
||||
final Selectable<S> _source;
|
||||
final T Function(S) _mapper;
|
||||
|
||||
_MappedSelectable(this._source, this._mapper);
|
||||
|
||||
@override
|
||||
Future<List<T>> get() {
|
||||
return _source.get().then(_mapResults);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<List<T>> watch() {
|
||||
return _source.watch().map(_mapResults);
|
||||
}
|
||||
|
||||
List<T> _mapResults(List<S> results) => results.map(_mapper).toList();
|
||||
}
|
||||
|
||||
mixin SingleTableQueryMixin<T extends Table, D extends DataClass>
|
||||
|
|
|
@ -1303,22 +1303,26 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
);
|
||||
}
|
||||
|
||||
Future<List<AllTodosWithCategoryResult>> allTodosWithCategory(
|
||||
Selectable<AllTodosWithCategoryResult> allTodosWithCategoryQuery(
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelect(
|
||||
'SELECT t.*, c.id as catId, c."desc" as catDesc FROM todos t INNER JOIN categories c ON c.id = t.category',
|
||||
variables: []).then((rows) => rows.map(_rowToAllTodosWithCategoryResult).toList());
|
||||
}
|
||||
|
||||
Stream<List<AllTodosWithCategoryResult>> watchAllTodosWithCategory() {
|
||||
return customSelectStream(
|
||||
return (operateOn ?? this).customSelectQuery(
|
||||
'SELECT t.*, c.id as catId, c."desc" as catDesc FROM todos t INNER JOIN categories c ON c.id = t.category',
|
||||
variables: [],
|
||||
readsFrom: {
|
||||
categories,
|
||||
todosTable
|
||||
}).map((rows) => rows.map(_rowToAllTodosWithCategoryResult).toList());
|
||||
}).map(_rowToAllTodosWithCategoryResult);
|
||||
}
|
||||
|
||||
Future<List<AllTodosWithCategoryResult>> allTodosWithCategory(
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return allTodosWithCategoryQuery(operateOn: operateOn).get();
|
||||
}
|
||||
|
||||
Stream<List<AllTodosWithCategoryResult>> watchAllTodosWithCategory() {
|
||||
return allTodosWithCategoryQuery().watch();
|
||||
}
|
||||
|
||||
Future<int> deleteTodoById(
|
||||
|
@ -1344,7 +1348,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
);
|
||||
}
|
||||
|
||||
Future<List<TodoEntry>> withIn(
|
||||
Selectable<TodoEntry> withInQuery(
|
||||
String var1,
|
||||
String var2,
|
||||
List<int> var3,
|
||||
|
@ -1353,21 +1357,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
var $highestIndex = 3;
|
||||
final expandedvar3 = $expandVar($highestIndex, var3.length);
|
||||
$highestIndex += var3.length;
|
||||
return (operateOn ?? this).customSelect(
|
||||
'SELECT * FROM todos WHERE title = ?2 OR id IN ($expandedvar3) OR title = ?1',
|
||||
variables: [
|
||||
Variable.withString(var1),
|
||||
Variable.withString(var2),
|
||||
for (var $ in var3) Variable.withInt($),
|
||||
]).then((rows) => rows.map(_rowToTodoEntry).toList());
|
||||
}
|
||||
|
||||
Stream<List<TodoEntry>> watchWithIn(
|
||||
String var1, String var2, List<int> var3) {
|
||||
var $highestIndex = 3;
|
||||
final expandedvar3 = $expandVar($highestIndex, var3.length);
|
||||
$highestIndex += var3.length;
|
||||
return customSelectStream(
|
||||
return (operateOn ?? this).customSelectQuery(
|
||||
'SELECT * FROM todos WHERE title = ?2 OR id IN ($expandedvar3) OR title = ?1',
|
||||
variables: [
|
||||
Variable.withString(var1),
|
||||
|
@ -1376,29 +1366,46 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
],
|
||||
readsFrom: {
|
||||
todosTable
|
||||
}).map((rows) => rows.map(_rowToTodoEntry).toList());
|
||||
}).map(_rowToTodoEntry);
|
||||
}
|
||||
|
||||
Future<List<TodoEntry>> withIn(
|
||||
String var1,
|
||||
String var2,
|
||||
List<int> var3,
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return withInQuery(var1, var2, var3, operateOn: operateOn).get();
|
||||
}
|
||||
|
||||
Stream<List<TodoEntry>> watchWithIn(
|
||||
String var1, String var2, List<int> var3) {
|
||||
return withInQuery(var1, var2, var3).watch();
|
||||
}
|
||||
|
||||
Selectable<TodoEntry> searchQuery(
|
||||
int id,
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelectQuery(
|
||||
'SELECT * FROM todos WHERE CASE WHEN -1 = :id THEN 1 ELSE id = :id END',
|
||||
variables: [
|
||||
Variable.withInt(id),
|
||||
],
|
||||
readsFrom: {
|
||||
todosTable
|
||||
}).map(_rowToTodoEntry);
|
||||
}
|
||||
|
||||
Future<List<TodoEntry>> search(
|
||||
int id,
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelect(
|
||||
'SELECT * FROM todos WHERE CASE WHEN -1 = :id THEN 1 ELSE id = :id END',
|
||||
variables: [
|
||||
Variable.withInt(id),
|
||||
]).then((rows) => rows.map(_rowToTodoEntry).toList());
|
||||
return searchQuery(id, operateOn: operateOn).get();
|
||||
}
|
||||
|
||||
Stream<List<TodoEntry>> watchSearch(int id) {
|
||||
return customSelectStream(
|
||||
'SELECT * FROM todos WHERE CASE WHEN -1 = :id THEN 1 ELSE id = :id END',
|
||||
variables: [
|
||||
Variable.withInt(id),
|
||||
],
|
||||
readsFrom: {
|
||||
todosTable
|
||||
}).map((rows) => rows.map(_rowToTodoEntry).toList());
|
||||
return searchQuery(id).watch();
|
||||
}
|
||||
|
||||
FindCustomResult _rowToFindCustomResult(QueryRow row) {
|
||||
|
@ -1408,20 +1415,23 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
);
|
||||
}
|
||||
|
||||
Selectable<FindCustomResult> findCustomQuery(
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelectQuery(
|
||||
'SELECT custom FROM table_without_p_k WHERE some_float < 10',
|
||||
variables: [],
|
||||
readsFrom: {tableWithoutPK}).map(_rowToFindCustomResult);
|
||||
}
|
||||
|
||||
Future<List<FindCustomResult>> findCustom(
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelect(
|
||||
'SELECT custom FROM table_without_p_k WHERE some_float < 10',
|
||||
variables: []).then((rows) => rows.map(_rowToFindCustomResult).toList());
|
||||
return findCustomQuery(operateOn: operateOn).get();
|
||||
}
|
||||
|
||||
Stream<List<FindCustomResult>> watchFindCustom() {
|
||||
return customSelectStream(
|
||||
'SELECT custom FROM table_without_p_k WHERE some_float < 10',
|
||||
variables: [],
|
||||
readsFrom: {tableWithoutPK})
|
||||
.map((rows) => rows.map(_rowToFindCustomResult).toList());
|
||||
return findCustomQuery().watch();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1453,19 +1463,11 @@ mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<List<TodoEntry>> todosForUser(
|
||||
Selectable<TodoEntry> todosForUserQuery(
|
||||
int user,
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return (operateOn ?? this).customSelect(
|
||||
'SELECT t.* FROM todos t INNER JOIN shared_todos st ON st.todo = t.id INNER JOIN users u ON u.id = st.user WHERE u.id = :user',
|
||||
variables: [
|
||||
Variable.withInt(user),
|
||||
]).then((rows) => rows.map(_rowToTodoEntry).toList());
|
||||
}
|
||||
|
||||
Stream<List<TodoEntry>> watchTodosForUser(int user) {
|
||||
return customSelectStream(
|
||||
return (operateOn ?? this).customSelectQuery(
|
||||
'SELECT t.* FROM todos t INNER JOIN shared_todos st ON st.todo = t.id INNER JOIN users u ON u.id = st.user WHERE u.id = :user',
|
||||
variables: [
|
||||
Variable.withInt(user),
|
||||
|
@ -1474,6 +1476,17 @@ mixin _$SomeDaoMixin on DatabaseAccessor<TodoDb> {
|
|||
todosTable,
|
||||
sharedTodos,
|
||||
users
|
||||
}).map((rows) => rows.map(_rowToTodoEntry).toList());
|
||||
}).map(_rowToTodoEntry);
|
||||
}
|
||||
|
||||
Future<List<TodoEntry>> todosForUser(
|
||||
int user,
|
||||
{@Deprecated('No longer needed with Moor 1.6 - see the changelog for details')
|
||||
QueryEngine operateOn}) {
|
||||
return todosForUserQuery(user, operateOn: operateOn).get();
|
||||
}
|
||||
|
||||
Stream<List<TodoEntry>> watchTodosForUser(int user) {
|
||||
return todosForUserQuery(user).watch();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,14 +91,14 @@ class Database extends _$Database {
|
|||
Stream<List<CategoryWithCount>> categoriesWithCount() {
|
||||
// select all categories and load how many associated entries there are for
|
||||
// each category
|
||||
return customSelectStream(
|
||||
return customSelectQuery(
|
||||
'SELECT c.id, c.desc, '
|
||||
'(SELECT COUNT(*) FROM todos WHERE category = c.id) AS amount '
|
||||
'FROM categories c '
|
||||
'UNION ALL SELECT null, null, '
|
||||
'(SELECT COUNT(*) FROM todos WHERE category IS NULL)',
|
||||
readsFrom: {todos, categories},
|
||||
).map((rows) {
|
||||
).watch().map((rows) {
|
||||
// when we have the result set, map each row to the data class
|
||||
return rows.map((row) {
|
||||
final hasId = row.data['id'] != null;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:moor_generator/src/model/specified_column.dart';
|
||||
import 'package:moor_generator/src/model/specified_table.dart';
|
||||
import 'package:moor_generator/src/model/used_type_converter.dart';
|
||||
import 'package:moor_generator/src/parser/sql/type_mapping.dart';
|
||||
import 'package:moor_generator/src/utils/names.dart';
|
||||
import 'package:moor_generator/src/utils/string_escaper.dart';
|
||||
|
@ -33,6 +34,8 @@ class CreateTable {
|
|||
/// The AST of this `CREATE TABLE` statement.
|
||||
final ParseResult ast;
|
||||
|
||||
CreateTable(this.ast);
|
||||
|
||||
SpecifiedTable extractTable(TypeMapper mapper) {
|
||||
final table =
|
||||
SchemaFromCreateTable().read(ast.rootNode as CreateTableStatement);
|
||||
|
@ -47,6 +50,7 @@ class CreateTable {
|
|||
final dartName = ReCase(sqlName).camelCase;
|
||||
final constraintWriter = StringBuffer();
|
||||
final moorType = mapper.resolvedToMoor(column.type);
|
||||
UsedTypeConverter converter;
|
||||
String defaultValue;
|
||||
|
||||
for (var constraint in column.constraints) {
|
||||
|
@ -65,6 +69,12 @@ class CreateTable {
|
|||
defaultValue = '$expressionName(${asDartLiteral(sqlDefault)})';
|
||||
}
|
||||
|
||||
if (constraint is MappedBy) {
|
||||
converter = _readTypeConverter(constraint);
|
||||
// don't write MAPPED BY constraints when creating the table
|
||||
continue;
|
||||
}
|
||||
|
||||
if (constraintWriter.isNotEmpty) {
|
||||
constraintWriter.write(' ');
|
||||
}
|
||||
|
@ -79,6 +89,7 @@ class CreateTable {
|
|||
features: features,
|
||||
customConstraints: constraintWriter.toString(),
|
||||
defaultArgument: defaultValue,
|
||||
typeConverter: converter,
|
||||
);
|
||||
|
||||
foundColumns[column.name] = parsed;
|
||||
|
@ -114,5 +125,8 @@ class CreateTable {
|
|||
);
|
||||
}
|
||||
|
||||
CreateTable(this.ast);
|
||||
UsedTypeConverter _readTypeConverter(MappedBy mapper) {
|
||||
// todo we need to somehow parse the dart expression and check types
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ class QueryWriter {
|
|||
|
||||
void _writeSelect(StringBuffer buffer) {
|
||||
_writeMapping(buffer);
|
||||
_writeSelectStatementCreator(buffer);
|
||||
_writeOneTimeReader(buffer);
|
||||
_writeStreamReader(buffer);
|
||||
}
|
||||
|
@ -54,6 +55,10 @@ class QueryWriter {
|
|||
return '_rowTo${_select.resultClassName}';
|
||||
}
|
||||
|
||||
String _nameOfCreationMethod() {
|
||||
return '${_select.name}Query';
|
||||
}
|
||||
|
||||
/// Writes a mapping method that turns a "QueryRow" into the desired custom
|
||||
/// return type.
|
||||
void _writeMapping(StringBuffer buffer) {
|
||||
|
@ -87,27 +92,50 @@ class QueryWriter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Writes a method returning a `Selectable<T>`, where `T` is the return type
|
||||
/// of the custom query.
|
||||
void _writeSelectStatementCreator(StringBuffer buffer) {
|
||||
final returnType = 'Selectable<${_select.resultClassName}>';
|
||||
final methodName = _nameOfCreationMethod();
|
||||
|
||||
buffer.write('$returnType $methodName(');
|
||||
_writeParameters(buffer);
|
||||
buffer.write(') {\n');
|
||||
|
||||
_writeExpandedDeclarations(buffer);
|
||||
buffer
|
||||
..write('return (operateOn ?? this).')
|
||||
..write('customSelectQuery(${_queryCode()}, ');
|
||||
_writeVariables(buffer);
|
||||
buffer.write(', ');
|
||||
_writeReadsFrom(buffer);
|
||||
|
||||
buffer.write(').map(');
|
||||
buffer.write(_nameOfMappingMethod());
|
||||
buffer.write(');\n}\n');
|
||||
}
|
||||
|
||||
/*
|
||||
Future<List<AllTodosWithCategoryResult>> allTodos(String name,
|
||||
{QueryEngine overrideEngine}) {
|
||||
return _allTodosWithCategoryQuery(name, engine: overrideEngine).get();
|
||||
}
|
||||
*/
|
||||
|
||||
void _writeOneTimeReader(StringBuffer buffer) {
|
||||
buffer.write('Future<List<${_select.resultClassName}>> ${query.name}(');
|
||||
_writeParameters(buffer);
|
||||
buffer.write(') {\n');
|
||||
_writeExpandedDeclarations(buffer);
|
||||
buffer
|
||||
..write('return (operateOn ?? this).') // use custom engine, if set
|
||||
..write('customSelect(${_queryCode()},');
|
||||
_writeVariables(buffer);
|
||||
buffer
|
||||
..write(')')
|
||||
..write(
|
||||
'.then((rows) => rows.map(${_nameOfMappingMethod()}).toList());\n')
|
||||
..write('\n}\n');
|
||||
buffer..write(') {\n')..write('return ${_nameOfCreationMethod()}(');
|
||||
_writeUseParameters(buffer);
|
||||
buffer.write(').get();\n}\n');
|
||||
}
|
||||
|
||||
void _writeStreamReader(StringBuffer buffer) {
|
||||
// turning the query name into pascal case will remove underscores
|
||||
final upperQueryName = ReCase(query.name).pascalCase;
|
||||
|
||||
String methodName;
|
||||
// turning the query name into pascal case will remove underscores, add the
|
||||
// "private" modifier back in if needed
|
||||
if (session.options.fixPrivateWatchMethods && query.name.startsWith('_')) {
|
||||
methodName = '_watch$upperQueryName';
|
||||
} else {
|
||||
|
@ -115,23 +143,10 @@ class QueryWriter {
|
|||
}
|
||||
|
||||
buffer.write('Stream<List<${_select.resultClassName}>> $methodName(');
|
||||
// don't supply an engine override parameter because select streams cannot
|
||||
// be used in transaction or similar context, only on the main database
|
||||
// engine.
|
||||
_writeParameters(buffer, dontOverrideEngine: true);
|
||||
buffer.write(') {\n');
|
||||
|
||||
_writeExpandedDeclarations(buffer);
|
||||
buffer..write('return customSelectStream(${_queryCode()},');
|
||||
|
||||
_writeVariables(buffer);
|
||||
buffer.write(',');
|
||||
_writeReadsFrom(buffer);
|
||||
|
||||
buffer
|
||||
..write(')')
|
||||
..write('.map((rows) => rows.map(${_nameOfMappingMethod()}).toList());\n')
|
||||
..write('\n}\n');
|
||||
buffer..write(') {\n')..write('return ${_nameOfCreationMethod()}(');
|
||||
_writeUseParameters(buffer, dontUseEngine: true);
|
||||
buffer.write(').watch();\n}\n');
|
||||
}
|
||||
|
||||
void _writeUpdatingQuery(StringBuffer buffer) {
|
||||
|
@ -177,6 +192,17 @@ class QueryWriter {
|
|||
}
|
||||
}
|
||||
|
||||
/// Writes code that uses the parameters as declared by [_writeParameters],
|
||||
/// assuming that for each parameter, a variable with the same name exists
|
||||
/// in the current scope.
|
||||
void _writeUseParameters(StringBuffer into, {bool dontUseEngine = false}) {
|
||||
into.write(query.variables.map((v) => v.dartParameterName).join(', '));
|
||||
if (!dontUseEngine) {
|
||||
if (query.variables.isNotEmpty) into.write(', ');
|
||||
into.write('operateOn: operateOn');
|
||||
}
|
||||
}
|
||||
|
||||
// Some notes on parameters and generating query code:
|
||||
// We expand array parameters to multiple variables at runtime (see the
|
||||
// documentation of FoundVariable and SqlQuery for further discussion).
|
||||
|
|
Loading…
Reference in New Issue