Generate code for Dart-defined index

This commit is contained in:
Simon Binder 2023-09-14 17:57:57 +02:00
parent f81e9d8c4b
commit 78b520f55d
10 changed files with 85 additions and 10 deletions

View File

@ -12,6 +12,7 @@ class TodoCategories extends Table {
TextColumn get name => text()();
}
@TableIndex(name: 'item_title', columns: {#title})
class TodoItems extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get title => text()();

View File

@ -689,10 +689,17 @@ abstract class _$Database extends GeneratedDatabase {
$TodoCategoryItemCountView(this);
late final $TodoItemWithCategoryNameViewView customViewName =
$TodoItemWithCategoryNameViewView(this);
late final Index itemTitle =
Index('item_title', 'CREATE INDEX item_title ON todo_items (title)');
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities =>
[todoCategories, todoItems, todoCategoryItemCount, customViewName];
List<DatabaseSchemaEntity> get allSchemaEntities => [
todoCategories,
todoItems,
todoCategoryItemCount,
customViewName,
itemTitle
];
}

View File

@ -65,6 +65,9 @@ class DartTableResolver extends LocalElementResolver<DiscoveredDartTable> {
],
overrideTableConstraints: tableConstraints,
withoutRowId: await _overrideWithoutRowId(element) ?? false,
attachedIndices: [
for (final id in discovered.attachedIndices) id.name,
],
);
if (primaryKey != null &&

View File

@ -216,11 +216,14 @@ class _FindDartElements extends RecursiveElementVisitor<void> {
_pendingWork.add(Future.sync(() async {
final name = await _sqlNameOfTable(element);
final id = _discoverStep._id(name);
found.add(DiscoveredDartTable(id, element));
final attachedIndices = <DriftElementId>[];
for (final (annotation, indexId) in _tableIndexAnnotation(element)) {
attachedIndices.add(indexId);
found.add(DiscoveredDartIndex(indexId, element, id, annotation));
}
found.add(DiscoveredDartTable(id, element, attachedIndices));
}));
}
} else if (_isDslView(element)) {

View File

@ -42,14 +42,34 @@ class FileAnalyzer {
await driver.resolveElements(import.ownUri);
}
final availableByDefault = <DriftSchemaElement>{
...element.declaredTables,
...element.declaredViews,
};
// For indices added to tables via an annotation, the index should
// also be available.
for (final table in element.declaredTables) {
final fileState = driver.cache.knownFiles[table.id.libraryUri]!;
for (final attachedIndex in table.attachedIndices) {
final index =
fileState.analysis[fileState.id(attachedIndex)]?.result;
if (index is DriftIndex) {
availableByDefault.add(index);
}
}
}
final availableElements = imported
.expand((reachable) {
final elementAnalysis = reachable.analysis.values;
return elementAnalysis.map((e) => e.result).where(
(e) => e is DefinedSqlQuery || e is DriftSchemaElement);
})
.whereType<DriftElement>()
.followedBy(element.references)
.followedBy(availableByDefault)
.transitiveClosureUnderReferences()
.sortTopologicallyOrElse(driver.backend.log.severe);
@ -58,15 +78,11 @@ class FileAnalyzer {
// from a Dart file that hasn't been added to `tables`, emit a warning.
// https://github.com/simolus3/drift/issues/2462#issuecomment-1620107751
if (element is DriftDatabase) {
final explicitlyAdded = <DriftElementWithResultSet>{
...element.declaredTables,
...element.declaredViews,
};
final implicitlyAdded = availableElements
.whereType<DriftElementWithResultSet>()
.where((element) =>
element.declaration.isDartDeclaration &&
!explicitlyAdded.contains(element));
!availableByDefault.contains(element));
if (implicitlyAdded.isNotEmpty) {
final names = implicitlyAdded
@ -97,6 +113,9 @@ class FileAnalyzer {
result.resolvedDatabases[element.id] =
ResolvedDatabaseAccessor(queries, imports, availableElements);
} else if (element is DriftIndex) {
// We need the SQL AST for each index to create them in code
element.createStatementForDartDefinition();
}
}
} else if (state.extension == '.drift' || state.extension == '.moor') {

View File

@ -38,7 +38,15 @@ class DiscoveredDartTable extends DiscoveredDartElement<ClassElement> {
@override
DriftElementKind get kind => DriftElementKind.table;
DiscoveredDartTable(super.ownId, super.dartElement);
/// The element ids of [DiscoveredDartIndex] entries that have been added to
/// this table with a `@TableIndex` annotation on the table class.
final List<DriftElementId> attachedIndices;
DiscoveredDartTable(
super.ownId,
super.dartElement,
this.attachedIndices,
);
}
class DiscoveredDartView extends DiscoveredDartElement<ClassElement> {

View File

@ -48,6 +48,27 @@ class DriftIndex extends DriftSchemaElement {
/// This node is not serialized and only set in the late-state, local file
/// analysis.
CreateIndexStatement? parsedStatement;
/// At the moment, the index implementation in the generator writes the
/// `CREATE INDEX` definition as a string into the generated code. This
/// requires [parsedStatement] to be available when generating code. To ensure
/// this for Dart-based index declarations, this method creates a suitable AST
/// for a create index statement based on the information available in our
/// element model.
///
/// Note that Dart index definitions are less expressive than the ones in SQL,
/// so this method should not be used for indices defined with SQL.
void createStatementForDartDefinition() {
parsedStatement = CreateIndexStatement(
indexName: id.name,
on: TableReference(table?.id.name ?? ''),
unique: unique,
columns: [
for (final column in indexedColumns)
IndexedColumn(Reference(columnName: column.nameInSql))
],
);
}
}
sealed class DriftIndexDefintion {}

View File

@ -53,6 +53,14 @@ class DriftTable extends DriftElementWithResultSet {
/// `customConstraints` getter in the table class with this value.
final List<String> overrideTableConstraints;
/// The names of indices that have been attached to this table using the
/// `@TableIndex` annotation in drift.
///
/// This field only has the purpose of implicitly adding these indices to each
/// database adding this table, so that code for that index will get generated
/// without an explicit reference.
final List<String> attachedIndices;
DriftColumn? _rowIdColumn;
DriftTable(
@ -71,6 +79,7 @@ class DriftTable extends DriftElementWithResultSet {
this.virtualTableData,
this.writeDefaultConstraints = true,
this.overrideTableConstraints = const [],
this.attachedIndices = const [],
}) {
_rowIdColumn = DriftColumn(
sqlType: DriftSqlType.int,

View File

@ -62,6 +62,7 @@ class ElementSerializer {
'virtual': _serializeVirtualTableData(element.virtualTableData!),
'write_default_constraints': element.writeDefaultConstraints,
'custom_constraints': element.overrideTableConstraints,
'attached_indices': element.attachedIndices,
};
} else if (element is DriftIndex) {
additionalInformation = {
@ -516,6 +517,7 @@ class ElementDeserializer {
overrideTableConstraints: json['custom_constraints'] != null
? (json['custom_constraints'] as List).cast()
: const [],
attachedIndices: (json['attached_indices'] as List).cast(),
);
for (final column in columns) {

View File

@ -311,6 +311,8 @@ class SchemaReader {
if (sql != null) {
index.parsedStatement =
_engine.parse(sql).rootNode as CreateIndexStatement;
} else {
index.createStatementForDartDefinition();
}
return index;