mirror of https://github.com/AMT-Cheif/drift.git
Option to get raw data in result sets (#615)
This commit is contained in:
parent
7ff91a620a
commit
fa1e76f8f3
|
@ -65,6 +65,7 @@ At the moment, moor supports these options:
|
|||
data classes.
|
||||
* `mutable_classes` (defaults to `false`): The fields generated in generated data, companion and result set classes are final
|
||||
by default. You can make them mutable by setting `mutable_classes: true`.
|
||||
* `raw_result_set_data`: The generator will expose the underlying `QueryRow` for generated result set classes
|
||||
|
||||
## Available extensions
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ targets:
|
|||
generate_connect_constructor: true
|
||||
compact_query_methods: true
|
||||
write_from_json_string_constructor: true
|
||||
raw_result_set_data: true
|
||||
# eagerly_load_dart_ast: true
|
||||
sqlite_modules:
|
||||
- json1
|
||||
|
|
|
@ -1013,6 +1013,7 @@ abstract class _$Database extends GeneratedDatabase {
|
|||
variables: [],
|
||||
readsFrom: {recipes, ingredientInRecipes}).map((QueryRow row) {
|
||||
return TotalWeightResult(
|
||||
row: row,
|
||||
title: row.readString('title'),
|
||||
totalWeight: row.readInt('total_weight'),
|
||||
);
|
||||
|
@ -1026,13 +1027,14 @@ abstract class _$Database extends GeneratedDatabase {
|
|||
[categories, recipes, ingredients, ingredientInRecipes];
|
||||
}
|
||||
|
||||
class TotalWeightResult {
|
||||
class TotalWeightResult extends CustomResultSet {
|
||||
final String title;
|
||||
final int totalWeight;
|
||||
TotalWeightResult({
|
||||
@required QueryRow row,
|
||||
this.title,
|
||||
this.totalWeight,
|
||||
});
|
||||
}) : super(row);
|
||||
@override
|
||||
int get hashCode => $mrjf($mrjc(title.hashCode, totalWeight.hashCode));
|
||||
@override
|
||||
|
|
|
@ -13,6 +13,7 @@ export 'package:moor/src/runtime/query_builder/query_builder.dart';
|
|||
export 'package:moor/src/runtime/executor/connection_pool.dart';
|
||||
export 'package:moor/src/runtime/executor/executor.dart';
|
||||
export 'package:moor/src/runtime/executor/transactions.dart';
|
||||
export 'package:moor/src/runtime/custom_result_set.dart';
|
||||
export 'package:moor/src/runtime/data_verification.dart';
|
||||
export 'package:moor/src/runtime/data_class.dart';
|
||||
export 'package:moor/src/runtime/api/runtime_api.dart';
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:moor/moor.dart';
|
||||
|
||||
/// Base class for classes generated by custom queries in `.moor` files.
|
||||
abstract class CustomResultSet {
|
||||
/// The raw [QueryRow] from where this result set was extracted.
|
||||
final QueryRow row;
|
||||
|
||||
/// Default constructor.
|
||||
CustomResultSet(this.row);
|
||||
}
|
|
@ -1462,6 +1462,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
variables: [],
|
||||
readsFrom: {config}).map((QueryRow row) {
|
||||
return JsonResult(
|
||||
row: row,
|
||||
key: row.readString('key'),
|
||||
value: row.readString('value'),
|
||||
);
|
||||
|
@ -1474,6 +1475,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
variables: [],
|
||||
readsFrom: {}).map((QueryRow row) {
|
||||
return JsonResult(
|
||||
row: row,
|
||||
key: row.readString('key'),
|
||||
value: row.readString('value'),
|
||||
);
|
||||
|
@ -1487,6 +1489,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
variables: [...generatedpredicate.introducedVariables],
|
||||
readsFrom: {withConstraints, withDefaults}).map((QueryRow row) {
|
||||
return MultipleResult(
|
||||
row: row,
|
||||
a: row.readString('a'),
|
||||
b: row.readInt('b'),
|
||||
c: withConstraints.mapFromRowOrNull(row, tablePrefix: 'nested_0'),
|
||||
|
@ -1508,6 +1511,7 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
variables: [...generatedexpr.introducedVariables],
|
||||
readsFrom: {config}).map((QueryRow row) {
|
||||
return ReadRowIdResult(
|
||||
row: row,
|
||||
rowid: row.readInt('rowid'),
|
||||
configKey: row.readString('config_key'),
|
||||
configValue: row.readString('config_value'),
|
||||
|
@ -1562,13 +1566,14 @@ abstract class _$CustomTablesDb extends GeneratedDatabase {
|
|||
);
|
||||
}
|
||||
|
||||
class JsonResult {
|
||||
class JsonResult extends CustomResultSet {
|
||||
final String key;
|
||||
final String value;
|
||||
JsonResult({
|
||||
@required QueryRow row,
|
||||
this.key,
|
||||
this.value,
|
||||
});
|
||||
}) : super(row);
|
||||
@override
|
||||
int get hashCode => $mrjf($mrjc(key.hashCode, value.hashCode));
|
||||
@override
|
||||
|
@ -1587,15 +1592,16 @@ class JsonResult {
|
|||
}
|
||||
}
|
||||
|
||||
class MultipleResult {
|
||||
class MultipleResult extends CustomResultSet {
|
||||
final String a;
|
||||
final int b;
|
||||
final WithConstraint c;
|
||||
MultipleResult({
|
||||
@required QueryRow row,
|
||||
this.a,
|
||||
this.b,
|
||||
this.c,
|
||||
});
|
||||
}) : super(row);
|
||||
@override
|
||||
int get hashCode => $mrjf($mrjc(a.hashCode, $mrjc(b.hashCode, c.hashCode)));
|
||||
@override
|
||||
|
@ -1616,19 +1622,20 @@ class MultipleResult {
|
|||
}
|
||||
}
|
||||
|
||||
class ReadRowIdResult {
|
||||
class ReadRowIdResult extends CustomResultSet {
|
||||
final int rowid;
|
||||
final String configKey;
|
||||
final String configValue;
|
||||
final SyncType syncState;
|
||||
final SyncType syncStateImplicit;
|
||||
ReadRowIdResult({
|
||||
@required QueryRow row,
|
||||
this.rowid,
|
||||
this.configKey,
|
||||
this.configValue,
|
||||
this.syncState,
|
||||
this.syncStateImplicit,
|
||||
});
|
||||
}) : super(row);
|
||||
@override
|
||||
int get hashCode => $mrjf($mrjc(
|
||||
rowid.hashCode,
|
||||
|
|
|
@ -1563,6 +1563,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
variables: [],
|
||||
readsFrom: {categories, todosTable}).map((QueryRow row) {
|
||||
return AllTodosWithCategoryResult(
|
||||
row: row,
|
||||
id: row.readInt('id'),
|
||||
title: row.readString('title'),
|
||||
content: row.readString('content'),
|
||||
|
@ -1628,7 +1629,7 @@ abstract class _$TodoDb extends GeneratedDatabase {
|
|||
];
|
||||
}
|
||||
|
||||
class AllTodosWithCategoryResult {
|
||||
class AllTodosWithCategoryResult extends CustomResultSet {
|
||||
final int id;
|
||||
final String title;
|
||||
final String content;
|
||||
|
@ -1637,6 +1638,7 @@ class AllTodosWithCategoryResult {
|
|||
final int catId;
|
||||
final String catDesc;
|
||||
AllTodosWithCategoryResult({
|
||||
@required QueryRow row,
|
||||
this.id,
|
||||
this.title,
|
||||
this.content,
|
||||
|
@ -1644,7 +1646,7 @@ class AllTodosWithCategoryResult {
|
|||
this.category,
|
||||
this.catId,
|
||||
this.catDesc,
|
||||
});
|
||||
}) : super(row);
|
||||
@override
|
||||
int get hashCode => $mrjf($mrjc(
|
||||
id.hashCode,
|
||||
|
|
|
@ -137,8 +137,7 @@ void main() {
|
|||
final mock = MockExecutor();
|
||||
final db = CustomTablesDb(mock);
|
||||
|
||||
when(mock.runSelect(any, any)).thenAnswer((_) {
|
||||
final row = {
|
||||
const row = {
|
||||
'a': 'text for a',
|
||||
'b': 42,
|
||||
'nested_0.a': 'text',
|
||||
|
@ -146,6 +145,7 @@ void main() {
|
|||
'nested_0.c': 18.7,
|
||||
};
|
||||
|
||||
when(mock.runSelect(any, any)).thenAnswer((_) {
|
||||
return Future.value([row]);
|
||||
});
|
||||
|
||||
|
@ -154,6 +154,7 @@ void main() {
|
|||
expect(
|
||||
result,
|
||||
MultipleResult(
|
||||
row: QueryRow(row, db),
|
||||
a: 'text for a',
|
||||
b: 42,
|
||||
c: WithConstraint(a: 'text', b: 1337, c: 18.7),
|
||||
|
@ -165,16 +166,16 @@ void main() {
|
|||
final mock = MockExecutor();
|
||||
final db = CustomTablesDb(mock);
|
||||
|
||||
when(mock.runSelect(any, any)).thenAnswer((_) {
|
||||
return Future.value([
|
||||
{
|
||||
const row = {
|
||||
'a': 'text for a',
|
||||
'b': 42,
|
||||
'nested_0.a': 'text',
|
||||
'nested_0.b': null, // note: with_constraints.b is NOT NULL in the db
|
||||
'nested_0.c': 18.7,
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
when(mock.runSelect(any, any)).thenAnswer((_) {
|
||||
return Future.value([row]);
|
||||
});
|
||||
|
||||
final result = await db.multiple(const Constant(true)).getSingle();
|
||||
|
@ -182,6 +183,7 @@ void main() {
|
|||
expect(
|
||||
result,
|
||||
MultipleResult(
|
||||
row: QueryRow(row, db),
|
||||
a: 'text for a',
|
||||
b: 42,
|
||||
// Since a non-nullable column in c was null, table should be null
|
||||
|
|
|
@ -74,6 +74,11 @@ class MoorOptions {
|
|||
@JsonKey(name: 'mutable_classes', defaultValue: false)
|
||||
final bool generateMutableClasses;
|
||||
|
||||
/// Whether generated query classes should inherit from the `CustomResultSet`
|
||||
/// and expose their underlying raw `row`.
|
||||
@JsonKey(name: 'raw_result_set_data', defaultValue: false)
|
||||
final bool rawResultSetData;
|
||||
|
||||
/// Whether the [module] has been enabled in this configuration.
|
||||
bool hasModule(SqlModule module) => modules.contains(module);
|
||||
|
||||
|
@ -89,6 +94,7 @@ class MoorOptions {
|
|||
this.eagerlyLoadDartAst = false,
|
||||
this.dataClassToCompanions = true,
|
||||
this.generateMutableClasses = false,
|
||||
this.rawResultSetData = false,
|
||||
this.modules = const [],
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ MoorOptions _$MoorOptionsFromJson(Map<String, dynamic> json) {
|
|||
'sqlite_modules',
|
||||
'eagerly_load_dart_ast',
|
||||
'data_class_to_companions',
|
||||
'mutable_classes'
|
||||
'mutable_classes',
|
||||
'raw_result_set_data'
|
||||
]);
|
||||
final val = MoorOptions(
|
||||
generateFromJsonStringConstructor: $checkedConvert(
|
||||
|
@ -57,6 +58,9 @@ MoorOptions _$MoorOptionsFromJson(Map<String, dynamic> json) {
|
|||
true,
|
||||
generateMutableClasses:
|
||||
$checkedConvert(json, 'mutable_classes', (v) => v as bool) ?? false,
|
||||
rawResultSetData:
|
||||
$checkedConvert(json, 'raw_result_set_data', (v) => v as bool) ??
|
||||
false,
|
||||
modules: $checkedConvert(
|
||||
json,
|
||||
'sqlite_modules',
|
||||
|
@ -80,7 +84,8 @@ MoorOptions _$MoorOptionsFromJson(Map<String, dynamic> json) {
|
|||
'eagerlyLoadDartAst': 'eagerly_load_dart_ast',
|
||||
'dataClassToCompanions': 'data_class_to_companions',
|
||||
'generateMutableClasses': 'mutable_classes',
|
||||
'modules': 'sqlite_modules'
|
||||
'modules': 'sqlite_modules',
|
||||
'rawResultSetData': 'raw_result_set_data',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -176,6 +176,7 @@ class InferredResultSet {
|
|||
///
|
||||
/// See [NestedResultTable] for further discussion and examples.
|
||||
final List<NestedResultTable> nestedResults;
|
||||
Map<NestedResultTable, String> _expandedNestedPrefixes;
|
||||
|
||||
final List<ResultColumn> columns;
|
||||
final Map<ResultColumn, String> _dartNames = {};
|
||||
|
@ -217,6 +218,17 @@ class InferredResultSet {
|
|||
bool get singleColumn =>
|
||||
matchingTable == null && nestedResults.isEmpty && columns.length == 1;
|
||||
|
||||
String nestedPrefixFor(NestedResultTable table) {
|
||||
if (_expandedNestedPrefixes == null) {
|
||||
var index = 0;
|
||||
_expandedNestedPrefixes = {
|
||||
for (final nested in nestedResults) nested: 'nested_${index++}',
|
||||
};
|
||||
}
|
||||
|
||||
return _expandedNestedPrefixes[table];
|
||||
}
|
||||
|
||||
void forceDartNames(Map<ResultColumn, String> names) {
|
||||
_dartNames
|
||||
..clear()
|
||||
|
|
|
@ -19,8 +19,6 @@ class QueryWriter {
|
|||
final SqlQuery query;
|
||||
final Scope scope;
|
||||
|
||||
final Map<NestedResultTable, String> _expandedNestedPrefixes = {};
|
||||
|
||||
SqlSelectQuery get _select => query as SqlSelectQuery;
|
||||
UpdatingQuery get _update => query as UpdatingQuery;
|
||||
|
||||
|
@ -64,8 +62,6 @@ class QueryWriter {
|
|||
}
|
||||
|
||||
void _writeSelect() {
|
||||
_createNamesForNestedResults();
|
||||
|
||||
_writeSelectStatementCreator();
|
||||
|
||||
if (!_newSelectableMode) {
|
||||
|
@ -82,22 +78,16 @@ class QueryWriter {
|
|||
}
|
||||
}
|
||||
|
||||
void _createNamesForNestedResults() {
|
||||
var index = 0;
|
||||
|
||||
for (final nested in _select.resultSet.nestedResults) {
|
||||
_expandedNestedPrefixes[nested] = 'nested_${index++}';
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the function literal that turns a "QueryRow" into the desired
|
||||
/// custom return type of a select statement.
|
||||
void _writeMappingLambda() {
|
||||
if (_select.resultSet.singleColumn) {
|
||||
final column = _select.resultSet.columns.single;
|
||||
_buffer.write('(QueryRow row) => ${_readingCode(column)}');
|
||||
return;
|
||||
_buffer.write('(QueryRow row) => ${readingCode(column)}');
|
||||
} else if (_select.resultSet.matchingTable != null) {
|
||||
// note that, even if the result set has a matching table, we can't just
|
||||
// use the mapFromRow() function of that table - the column names might
|
||||
// be different!
|
||||
final match = _select.resultSet.matchingTable;
|
||||
final table = match.table;
|
||||
|
||||
|
@ -118,22 +108,19 @@ class QueryWriter {
|
|||
|
||||
_buffer.write('})');
|
||||
}
|
||||
} else {
|
||||
_buffer.write('(QueryRow row) { return ${_select.resultClassName}(');
|
||||
|
||||
return;
|
||||
if (options.rawResultSetData) {
|
||||
_buffer.write('row: row,\n');
|
||||
}
|
||||
|
||||
_buffer.write('(QueryRow row) {\n');
|
||||
|
||||
// note that, even if the result set has a matching table, we can't just
|
||||
// use the mapFromRow() function of that table - the column names might
|
||||
// be different!
|
||||
_buffer.write('return ${_select.resultClassName}(');
|
||||
for (final column in _select.resultSet.columns) {
|
||||
final fieldName = _select.resultSet.dartNameFor(column);
|
||||
_buffer.write('$fieldName: ${_readingCode(column)},');
|
||||
_buffer.write('$fieldName: ${readingCode(column)},');
|
||||
}
|
||||
for (final nested in _select.resultSet.nestedResults) {
|
||||
final prefix = _expandedNestedPrefixes[nested];
|
||||
final prefix = _select.resultSet.nestedPrefixFor(nested);
|
||||
if (prefix == null) continue;
|
||||
|
||||
final fieldName = nested.dartFieldName;
|
||||
|
@ -144,11 +131,12 @@ class QueryWriter {
|
|||
}
|
||||
_buffer.write(');\n}');
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns Dart code that, given a variable of type `QueryRow` named `row`
|
||||
/// in the same scope, reads the [column] from that row and brings it into a
|
||||
/// suitable type.
|
||||
String _readingCode(ResultColumn column) {
|
||||
static String readingCode(ResultColumn column) {
|
||||
final readMethod = readFromMethods[column.type];
|
||||
|
||||
final dartLiteral = asDartLiteral(column.name);
|
||||
|
@ -430,7 +418,7 @@ class QueryWriter {
|
|||
final result = doubleStarColumnToResolvedTable[rewriteTarget];
|
||||
if (result == null) continue;
|
||||
|
||||
final prefix = _expandedNestedPrefixes[result];
|
||||
final prefix = _select.resultSet.nestedPrefixFor(result);
|
||||
final table = rewriteTarget.tableName;
|
||||
|
||||
// Convert foo.** to "foo.a" AS "nested_0.a", ... for all columns in foo
|
||||
|
|
|
@ -14,12 +14,20 @@ class ResultSetWriter {
|
|||
final fieldNames = <String>[];
|
||||
final into = scope.leaf();
|
||||
|
||||
into.write('class $className {\n');
|
||||
final resultSet = query.resultSet;
|
||||
|
||||
into.write('class $className ');
|
||||
if (scope.options.rawResultSetData) {
|
||||
into.write('extends CustomResultSet {\n');
|
||||
} else {
|
||||
into.write('{\n');
|
||||
}
|
||||
|
||||
final modifier = scope.options.fieldModifier;
|
||||
|
||||
// write fields
|
||||
for (final column in query.resultSet.columns) {
|
||||
final name = query.resultSet.dartNameFor(column);
|
||||
for (final column in resultSet.columns) {
|
||||
final name = resultSet.dartNameFor(column);
|
||||
final runtimeType = column.dartType;
|
||||
|
||||
into.write('$modifier $runtimeType $name\n;');
|
||||
|
@ -27,7 +35,7 @@ class ResultSetWriter {
|
|||
fieldNames.add(name);
|
||||
}
|
||||
|
||||
for (final nested in query.resultSet.nestedResults) {
|
||||
for (final nested in resultSet.nestedResults) {
|
||||
final typeName = nested.table.dartTypeName;
|
||||
final fieldName = nested.dartFieldName;
|
||||
|
||||
|
@ -37,11 +45,21 @@ class ResultSetWriter {
|
|||
}
|
||||
|
||||
// write the constructor
|
||||
if (scope.options.rawResultSetData) {
|
||||
into.write('$className({@required QueryRow row,');
|
||||
} else {
|
||||
into.write('$className({');
|
||||
}
|
||||
|
||||
for (final column in fieldNames) {
|
||||
into.write('this.$column,');
|
||||
}
|
||||
|
||||
if (scope.options.rawResultSetData) {
|
||||
into.write('}): super(row);\n');
|
||||
} else {
|
||||
into.write('});\n');
|
||||
}
|
||||
|
||||
// if requested, override hashCode and equals
|
||||
if (scope.writer.options.overrideHashAndEqualsInResultSets) {
|
||||
|
|
Loading…
Reference in New Issue