mirror of https://github.com/AMT-Cheif/drift.git
Report lints about invalid Dart Templates in SQL
This commit is contained in:
parent
3abfbd5963
commit
25ceda3505
|
@ -17,8 +17,9 @@ class _FakeDb extends GeneratedDatabase {
|
|||
},
|
||||
beforeOpen: (details) async {
|
||||
// this fake select query is verified via mocks
|
||||
await customSelect(
|
||||
'opened: ${details.versionBefore} to ${details.versionNow}');
|
||||
await customSelectQuery(
|
||||
'opened: ${details.versionBefore} to ${details.versionNow}')
|
||||
.get();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'package:sqlparser/sqlparser.dart';
|
|||
|
||||
import '../query_handler.dart';
|
||||
|
||||
/// Provides additional hints that aren't implemented in the sqlparser because
|
||||
/// they're specific to moor.
|
||||
class Linter {
|
||||
final QueryHandler handler;
|
||||
final List<AnalysisError> lints = [];
|
||||
|
@ -18,6 +20,39 @@ class _LintingVisitor extends RecursiveVisitor<void> {
|
|||
|
||||
_LintingVisitor(this.linter);
|
||||
|
||||
@override
|
||||
void visitResultColumn(ResultColumn e) {
|
||||
super.visitResultColumn(e);
|
||||
|
||||
if (e is ExpressionResultColumn) {
|
||||
// The generated code will be invalid if knowing the expression is needed
|
||||
// to know the column name (e.g. it's a Dart template without an AS), or
|
||||
// if the type is unknown.
|
||||
final expression = e.expression;
|
||||
final resolveResult = linter.handler.context.typeOf(expression);
|
||||
|
||||
if (resolveResult.type == null) {
|
||||
linter.lints.add(AnalysisError(
|
||||
type: AnalysisErrorType.other,
|
||||
message: 'Expression has an unknown type, the generated code can be'
|
||||
' inaccurate.',
|
||||
relevantNode: expression,
|
||||
));
|
||||
}
|
||||
|
||||
final dependsOnPlaceholder = e.as == null &&
|
||||
expression.allDescendants.whereType<DartPlaceholder>().isNotEmpty;
|
||||
if (dependsOnPlaceholder) {
|
||||
linter.lints.add(AnalysisError(
|
||||
type: AnalysisErrorType.other,
|
||||
message: 'The name of this column depends on a Dart template, which '
|
||||
'breaks generated code. Try adding an `AS` alias to fix this.',
|
||||
relevantNode: e,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitInsertStatement(InsertStatement e) {
|
||||
final targeted = e.resolvedTargetColumns;
|
||||
|
|
|
@ -82,11 +82,11 @@ class QueryHandler {
|
|||
final type = context.typeOf(column).type;
|
||||
final moorType = mapper.resolvedToMoor(type);
|
||||
UsedTypeConverter converter;
|
||||
if (type.hint is TypeConverterHint) {
|
||||
if (type?.hint is TypeConverterHint) {
|
||||
converter = (type.hint as TypeConverterHint).converter;
|
||||
}
|
||||
|
||||
columns.add(ResultColumn(column.name, moorType, type.nullable,
|
||||
columns.add(ResultColumn(column.name, moorType, type?.nullable ?? true,
|
||||
converter: converter));
|
||||
|
||||
final table = _tableOfColumn(column);
|
||||
|
|
|
@ -113,7 +113,8 @@ class QueryWriter {
|
|||
String _readingCode(ResultColumn column) {
|
||||
final readMethod = readFromMethods[column.type];
|
||||
|
||||
var code = "row.$readMethod('${column.name}')";
|
||||
final dartLiteral = asDartLiteral(column.name);
|
||||
var code = 'row.$readMethod($dartLiteral)';
|
||||
|
||||
if (column.converter != null) {
|
||||
final converter = column.converter;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import 'package:moor_generator/src/analyzer/sql_queries/query_handler.dart';
|
||||
import 'package:moor_generator/src/analyzer/sql_queries/type_mapping.dart';
|
||||
import 'package:sqlparser/sqlparser.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
final engine = SqlEngine(useMoorExtensions: true);
|
||||
final mapper = TypeMapper();
|
||||
|
||||
test('warns when a result column is unresolved', () {
|
||||
final result = engine.analyze('SELECT ?;');
|
||||
final moorQuery = QueryHandler('query', result, mapper).handle();
|
||||
|
||||
expect(moorQuery.lints,
|
||||
anyElement((AnalysisError q) => q.message.contains('unknown type')));
|
||||
});
|
||||
|
||||
test('warns when the result depends on a Dart template', () {
|
||||
final result = engine.analyze(r"SELECT 'string' = $expr;");
|
||||
final moorQuery = QueryHandler('query', result, mapper).handle();
|
||||
|
||||
expect(moorQuery.lints,
|
||||
anyElement((AnalysisError q) => q.message.contains('Dart template')));
|
||||
});
|
||||
}
|
|
@ -62,7 +62,7 @@ class TypeResolver {
|
|||
// todo probably needs to be nullable when coming from a join?
|
||||
return ResolveResult(column.type);
|
||||
} else if (column is ExpressionColumn) {
|
||||
return resolveExpression(column.expression);
|
||||
return resolveOrInfer(column.expression);
|
||||
}
|
||||
|
||||
throw StateError('Unknown column $column');
|
||||
|
|
Loading…
Reference in New Issue