drift/drift_dev/lib/src/writer/modules.dart

123 lines
3.9 KiB
Dart

import 'package:recase/recase.dart';
import '../analysis/driver/driver.dart';
import '../analysis/driver/state.dart';
import '../analysis/results/results.dart';
import '../utils/string_escaper.dart';
import 'queries/query_writer.dart';
import 'writer.dart';
/// Write a modular database accessor for a drift file.
///
/// In drift's (opt-in) modular build set, a `.drift.dart` file is generated for
/// each `.drift` file. This file defines elements defined in that drift file
/// (like tables, data classes, companions, fields for indexes and triggers).
///
/// If queries are defined in that drift file, a "modular accessor" is generated
/// as well. This accessor contains generated methods for all queries. The main
/// database will make these accessor available as getters.
class ModularAccessorWriter {
final Scope scope;
final FileState file;
final DriftAnalysisDriver driver;
ModularAccessorWriter(this.scope, this.file, this.driver);
void write() {
if (!file.needsModularAccessor(driver)) return;
final className = scope.modularAccessor(file.ownUri);
final generatedDatabase = scope.drift('GeneratedDatabase');
scope.leaf()
..write('class $className extends ')
..write(_modular('ModularAccessor'))
..writeln('{ $className($generatedDatabase db): super(db);');
final referencedElements = <DriftElement>{};
final queries = file.fileAnalysis?.resolvedQueries ?? const {};
for (final query in queries.entries) {
final queryElement = file.analysis[query.key]?.result;
if (queryElement != null) {
referencedElements.addAll(queryElement.references);
}
final value = query.value;
if (value is SqlSelectQuery) {
referencedElements.addAll(value.readsFromTables);
}
QueryWriter(scope.child()).write(value);
}
final restOfClass = scope.leaf();
for (final reference in referencedElements) {
// This element is referenced in a query, and the query writer expects it
// to be available as a getter. So, let's generate that getter:
if (reference is DriftElementWithResultSet) {
final infoType = restOfClass.entityInfoType(reference);
restOfClass
..writeDart(infoType)
..write(' get ${reference.dbGetterName} => this.resultSet<')
..writeDart(infoType)
..write('>(${asDartLiteral(reference.schemaName)});');
}
}
// Also make imports available
final imports = file.discovery?.importDependencies ?? const [];
for (final import in imports) {
final file = driver.cache.knownFiles[import];
if (file != null && file.needsModularAccessor(driver)) {
final moduleClass = restOfClass.modularAccessor(import);
final getterName = ReCase(moduleClass.toString()).camelCase;
restOfClass
..writeDart(moduleClass)
..write(' get $getterName => this.accessor(')
..writeDart(moduleClass)
..writeln('.new);');
}
}
restOfClass.writeln('}');
}
String _modular(String element) {
return scope.refUri(modularSupport, element);
}
static final Uri modularSupport =
Uri.parse('package:drift/internal/modular.dart');
}
extension WriteImplicitDaoGetter on Scope {
void writeGetterForIncludedDriftFile(
FileState import, DriftAnalysisDriver driver,
{required bool isAccessor}) {
assert(generationOptions.isModular);
if (import.needsModularAccessor(driver)) {
final type = modularAccessor(import.ownUri);
final getter = ReCase(type.toString()).camelCase;
final db = isAccessor ? 'attachedDatabase' : 'this';
leaf()
..writeDart(type)
..write(' get $getter => ')
..writeUriRef(
ModularAccessorWriter.modularSupport, 'ReadDatabaseContainer')
..writeln('($db).accessor<')
..writeDart(type)
..write('>(')
..writeDart(type)
..writeln('.new);');
}
}
}