Bug fixes and support for dart placeholder

This commit is contained in:
Daniel Brauner 2022-01-20 12:08:39 +01:00
parent add33e339c
commit b5acbbf374
7 changed files with 57 additions and 50 deletions

View File

@ -107,11 +107,11 @@ class TypeMapper {
return engineView;
}
/// Extracts variables and Dart templates from the [ctx]. Variables are
/// sorted by their ascending index. Placeholders are sorted by the position
/// they have in the query. When comparing variables and placeholders, the
/// variable comes first if the first variable with the same index appears
/// before the placeholder.
/// Extracts variables and Dart templates from the AST tree starting at
/// [root], but nested queries are excluded. Variables are sorted by their
/// ascending index. Placeholders are sorted by the position they have in the
/// query. When comparing variables and placeholders, the variable comes first
/// if the first variable with the same index appears before the placeholder.
///
/// Additionally, the following assumptions can be made if this method returns
/// without throwing:
@ -125,14 +125,16 @@ class TypeMapper {
// this contains variable references. For instance, SELECT :a = :a would
// contain two entries, both referring to the same variable. To do that,
// we use the fact that each variable has a unique index.
final collector = _VariableCollector();
root.accept(collector, null);
final variableCollector = _ElementCollector<Variable>();
final placeholderCollector = _ElementCollector<DartPlaceholder>();
final variables = collector.result;
final placeholders =
root.allDescendants.whereType<DartPlaceholder>().toList();
root.accept(variableCollector, null);
root.accept(placeholderCollector, null);
final merged = _mergeVarsAndPlaceholders(variables, placeholders);
final merged = _mergeVarsAndPlaceholders(
variableCollector.result,
placeholderCollector.result,
);
final foundElements = <FoundElement>[];
// we don't allow variables with an explicit index after an array. For
@ -356,16 +358,24 @@ class TypeMapper {
}
}
/// Because nested variables should not be included when extracting all
/// FoundElements allDescendants.whereType<Variable>() no longer works.
class _VariableCollector extends RecursiveVisitor<void, void> {
final List<Variable> result;
/// Because FoundElements from nested queries should not be added to the parent
/// query, it is necessary to use a visitor to decide when to stop collection
/// elements.
///
/// [T] can either be a [Variable] or [DartPlaceholder]. If the type is anything
/// else the result list will be empty.
class _ElementCollector<T> extends RecursiveVisitor<void, void> {
final List<T> result;
_VariableCollector() : result = [];
_ElementCollector()
: result = [],
assert(T == Variable || T == DartPlaceholder, 'T is: $T');
@override
void visitVariable(Variable e, void arg) {
result.add(e);
if (T == Variable) {
result.add(e as T);
}
super.visitVariable(e, arg);
}
@ -373,8 +383,13 @@ class _VariableCollector extends RecursiveVisitor<void, void> {
@override
void visitMoorSpecificNode(MoorSpecificNode e, void arg) {
if (e is NestedQueryColumn) {
// If the node ist a nested query, return to avoid collecting elements
// inside of it
return;
}
if (e is DartPlaceholder && T == DartPlaceholder) {
result.add(e as T);
}
super.visitMoorSpecificNode(e, arg);
}

View File

@ -521,18 +521,12 @@ class NestedResultQuery extends NestedResult {
required this.query,
});
String filedName(String? nestedPrefix) {
String filedName() {
if (from.as != null) {
return from.as!;
}
final name = ReCase(query.resultClassName).camelCase;
if (nestedPrefix != null) {
return name + nestedPrefix;
}
return name;
return ReCase(query.name).camelCase;
}
String resultTypeCode(String parentResultClassName) {

View File

@ -45,7 +45,8 @@ class QueryWriter {
// We do this transformation so late because it shouldn't have an impact on
// analysis, Dart getter names stay the same.
if (resultSet != null && options.newSqlCodeGeneration) {
ExplicitAliasTransformer().rewrite(query.root!);
_transformer = ExplicitAliasTransformer();
_transformer.rewrite(query.root!);
NestedQueryTransformer().rewrite(query.root!);
}
@ -61,6 +62,12 @@ class QueryWriter {
}
void _writeSelect(SqlSelectQuery select) {
if (select.hasNestedQuery && !scope.options.newSqlCodeGeneration) {
throw UnsupportedError(
'To use nested result queries enable new_sql_code_generation',
);
}
_writeSelectStatementCreator(select);
if (!select.declaredInMoorFile && !options.compactQueryMethods) {
@ -140,16 +147,7 @@ class QueryWriter {
_buffer.write('$fieldName: $tableGetter.$mappingMethod(row, '
'tablePrefix: ${asDartLiteral(prefix)}),');
} else if (nested is NestedResultQuery) {
if (!scope.options.newSqlCodeGeneration) {
throw UnsupportedError(
'To use nested result queries enable new_sql_code_generation',
);
}
final prefix = resultSet.nestedPrefixFor(nested);
if (prefix == null) continue;
final fieldName = nested.filedName(prefix);
final fieldName = nested.filedName();
_buffer.write('$fieldName: await ');
_writeCustomSelectStatement(nested.query);
@ -554,7 +552,9 @@ class QueryWriter {
_buffer.write('${table.dbGetterName},');
}
for (final element in select.elements.whereType<FoundDartPlaceholder>()) {
for (final element in select
.elementsWithNestedQueries()
.whereType<FoundDartPlaceholder>()) {
_buffer.write('...${placeholderContextName(element)}.watchedTables,');
}
@ -686,7 +686,7 @@ class _ExpandedDeclarationWriter {
}
needsIndexCounter = true;
for (final element in query.elements) {
for (final element in query.elementsWithNestedQueries()) {
if (element is FoundVariable) {
if (element.isArray) {
_writeArrayVariable(element);

View File

@ -52,8 +52,7 @@ class ResultSetWriter {
fieldNames.add(fieldName);
if (!nested.isNullable) nonNullableFields.add(fieldName);
} else if (nested is NestedResultQuery) {
final nestedPrefix = resultSet.nestedPrefixFor(nested);
final fieldName = nested.filedName(nestedPrefix);
final fieldName = nested.filedName();
final typeName = nested.resultTypeCode(className);
if (nested.query.resultSet.needsOwnClass) {

View File

@ -100,11 +100,7 @@ class ReferenceScope {
///
/// If [includeParents] is set to false, resolve will only search the current
/// scope.
T? resolve<T extends Referencable>(
String name, {
Function()? orElse,
bool includeParents = true,
}) {
T? resolve<T extends Referencable>(String name, {Function()? orElse}) {
ReferenceScope? scope = this;
var isAtParent = false;
final upper = name.toUpperCase();
@ -122,8 +118,6 @@ class ReferenceScope {
scope = scope.parent;
isAtParent = true;
if (!includeParents) break;
}
if (orElse != null) orElse();

View File

@ -34,8 +34,7 @@ class _NestedQueryTransformer extends Transformer<void> {
AstNode? visitReference(Reference e, void arg) {
// if the scope of the nested query cannot resolve the reference, the
// reference needs to be retrieved from the parent query
if (e.entityName != null &&
e.scope.resolve(e.entityName!, includeParents: false) == null) {
if (e.resultEntity != null && e.resultEntity!.origin.scope != e.scope) {
final result = e.scope.resolve(e.entityName!);
if (result == null) {
@ -62,7 +61,7 @@ class _NestedQueryTransformer extends Transformer<void> {
return e;
} else {
super.visitMoorSpecificNode(e, arg);
return super.visitMoorSpecificNode(e, arg);
}
}
}

View File

@ -172,6 +172,12 @@ class AstPreparingVisitor extends RecursiveVisitor<void, void> {
@override
void visitNestedQueryVariable(NestedQueryVariable e, void arg) {
assert(
false,
'This should be unreachable, because NestedQueryVariables are only'
'introduced later in the NestedQueryResolver',
);
_foundVariables.add(e);
visitChildren(e, arg);
}