Moving name reservation into Scope

This commit is contained in:
Joshua Matthews 2023-09-18 11:03:07 -04:00
parent ed1cd9f4e9
commit 10e0336310
No known key found for this signature in database
GPG Key ID: 207AC8D5EABDE954
2 changed files with 45 additions and 33 deletions

View File

@ -71,21 +71,6 @@ class SchemaVersionWriter {
final Map<String, String> _columnCodeToFactory = {}; final Map<String, String> _columnCodeToFactory = {};
final Map<_TableShape, String> _shapes = {}; final Map<_TableShape, String> _shapes = {};
// A list of member names already in use in the generated class. This is used
// to prevent table getters from conflicting with other class members.
final Set<String> _usedNames = {};
void _resetUsedNames() {
_usedNames.clear();
_usedNames.addAll([
'database',
'entities',
'version',
'stepByStepHelper',
'runMigrationSteps',
]);
}
SchemaVersionWriter(this.versions, this.libraryScope) { SchemaVersionWriter(this.versions, this.libraryScope) {
assert(versions.isSortedBy<num>((element) => element.version)); assert(versions.isSortedBy<num>((element) => element.version));
} }
@ -173,15 +158,6 @@ class SchemaVersionWriter {
}); });
} }
String _getNonCollidingGetterName(DriftSchemaElement element) {
var name = element.dbGetterName!;
while (_usedNames.contains(name)) {
name = '$name${_suffixForElement(element)}';
}
_usedNames.add(name);
return name;
}
String _suffixForElement(DriftSchemaElement element) => switch (element) { String _suffixForElement(DriftSchemaElement element) => switch (element) {
DriftTable() => 'Table', DriftTable() => 'Table',
DriftView() => 'View', DriftView() => 'View',
@ -191,8 +167,10 @@ class SchemaVersionWriter {
}; };
String _writeWithResultSet( String _writeWithResultSet(
DriftElementWithResultSet entity, TextEmitter writer) { String getterName,
final getterName = _getNonCollidingGetterName(entity); DriftElementWithResultSet entity,
TextEmitter writer,
) {
final shape = _shapeClass(entity); final shape = _shapeClass(entity);
writer writer
..write('late final $shape $getterName = ') ..write('late final $shape $getterName = ')
@ -298,19 +276,20 @@ class SchemaVersionWriter {
required DriftSchemaElement element, required DriftSchemaElement element,
required TextEmitter definition, required TextEmitter definition,
}) { }) {
String name; final name = definition.parent!.getNonConflictingName(
element.dbGetterName!,
(name) => name + _suffixForElement(element),
);
if (element is DriftElementWithResultSet) { if (element is DriftElementWithResultSet) {
name = _writeWithResultSet(element, definition); _writeWithResultSet(name, element, definition);
} else if (element is DriftIndex) { } else if (element is DriftIndex) {
name = _getNonCollidingGetterName(element);
final index = definition.drift('Index'); final index = definition.drift('Index');
definition definition
..write('final $index $name = ') ..write('final $index $name = ')
..writeln(DatabaseWriter.createIndex(definition.parent!, element)); ..writeln(DatabaseWriter.createIndex(definition.parent!, element));
} else if (element is DriftTrigger) { } else if (element is DriftTrigger) {
name = _getNonCollidingGetterName(element);
final trigger = definition.drift('Trigger'); final trigger = definition.drift('Trigger');
definition definition
@ -345,7 +324,14 @@ class SchemaVersionWriter {
final versionNo = version.version; final versionNo = version.version;
final versionClass = '_S$versionNo'; final versionClass = '_S$versionNo';
final versionScope = libraryScope.child(); final versionScope = libraryScope.child();
_resetUsedNames();
versionScope.reserveNames([
'database',
'entities',
'version',
'stepByStepHelper',
'runMigrationSteps',
]);
// Write an _S<x> class for each schema version x. // Write an _S<x> class for each schema version x.
versionScope.leaf() versionScope.leaf()

View File

@ -1,10 +1,10 @@
import 'package:drift/drift.dart'; import 'package:drift/drift.dart';
import 'package:path/path.dart' show url;
import 'package:recase/recase.dart'; import 'package:recase/recase.dart';
import 'package:sqlparser/sqlparser.dart' as sql; import 'package:sqlparser/sqlparser.dart' as sql;
import 'package:path/path.dart' show url;
import '../analysis/results/results.dart';
import '../analysis/options.dart'; import '../analysis/options.dart';
import '../analysis/results/results.dart';
import 'import_manager.dart'; import 'import_manager.dart';
import 'queries/sql_writer.dart'; import 'queries/sql_writer.dart';
@ -298,6 +298,10 @@ class Scope extends _Node {
/// This can be used to generated methods which must have a unique name- /// This can be used to generated methods which must have a unique name-
int counter = 0; int counter = 0;
/// The set of names already used in this scope. Used by methos like
/// [getNonConflictingName] to prevent name collisions.
final Set<String> _usedNames = {};
Scope({required Scope? parent, Writer? writer}) Scope({required Scope? parent, Writer? writer})
: writer = writer ?? parent!.writer, : writer = writer ?? parent!.writer,
super(parent); super(parent);
@ -325,6 +329,28 @@ class Scope extends _Node {
_children.add(child); _children.add(child);
return child; return child;
} }
/// Reserve a collection of names in this scope. See [getNonConflictingName]
/// for more information.
void reserveNames(Iterable<String> names) {
_usedNames.addAll(names);
}
/// Returns a variation of [name] that does not conflict with any names
/// already in use in this [Scope].
///
/// If [name] does not conflict with any existing names then it is returned
/// unmodified. If a conflict is detected then [name] is repeatedly passed to
/// [modify] until the result no longer conflicts. Each result returned from
/// this method is recorded in an internal set, so subsequent calls with the
/// same name will produce a different, non-conflicting result.
String getNonConflictingName(String name, String Function(String) modify) {
while (_usedNames.contains(name)) {
name = modify(name);
}
_usedNames.add(name);
return name;
}
} }
class TextEmitter extends _Node { class TextEmitter extends _Node {