diff --git a/drift_dev/CHANGELOG.md b/drift_dev/CHANGELOG.md index b904ae0a1..fa82b8c37 100644 --- a/drift_dev/CHANGELOG.md +++ b/drift_dev/CHANGELOG.md @@ -4,6 +4,8 @@ JSON type to nullable column. - Fix missing outputs for drift files only consisting of imports in modular generation mode. +- Allow generating manager references across different files in modular + generation mode. ## 2.24.0 diff --git a/drift_dev/lib/src/analysis/resolver/file_analysis.dart b/drift_dev/lib/src/analysis/resolver/file_analysis.dart index d6bf60a55..df2070a98 100644 --- a/drift_dev/lib/src/analysis/resolver/file_analysis.dart +++ b/drift_dev/lib/src/analysis/resolver/file_analysis.dart @@ -22,6 +22,13 @@ class FileAnalyzer { final knownTypes = await driver.knownTypes; final typeMapping = await driver.typeMapping; + for (final file in driver.cache.crawl(state).toList()) { + await driver.resolveElements(file.ownUri); + + result.allAvailableElements + .addAll(file.analysis.values.map((e) => e.result).whereType()); + } + if (state.extension == '.dart') { for (final elementAnalysis in state.analysis.values) { final element = elementAnalysis.result; diff --git a/drift_dev/lib/src/analysis/results/file_results.dart b/drift_dev/lib/src/analysis/results/file_results.dart index c2b51bbfa..cf386c232 100644 --- a/drift_dev/lib/src/analysis/results/file_results.dart +++ b/drift_dev/lib/src/analysis/results/file_results.dart @@ -6,6 +6,9 @@ import 'query.dart'; class FileAnalysisResult { final List analysisErrors = []; + /// All elements either declared in this file or transitively imported. + final List allAvailableElements = []; + final Map resolvedQueries = {}; final Map resolvedDatabases = {}; } diff --git a/drift_dev/lib/src/backends/build/drift_builder.dart b/drift_dev/lib/src/backends/build/drift_builder.dart index 00ed30f31..967884c15 100644 --- a/drift_dev/lib/src/backends/build/drift_builder.dart +++ b/drift_dev/lib/src/backends/build/drift_builder.dart @@ -393,6 +393,16 @@ class _DriftBuildRun { ModularAccessorWriter(writer.child(), entrypointState, driver).write(); if (options.generateManager) { + final all = entrypointState.fileAnalysis?.allAvailableElements + .whereType() ?? + const Iterable.empty(); + + for (final element in all) { + if (element.id.libraryUri != entrypointState.ownUri) { + managerWriter.addTableWithoutGeneration(element); + } + } + managerWriter.writeTableManagers(); } } diff --git a/drift_dev/lib/src/writer/manager/database_manager_writer.dart b/drift_dev/lib/src/writer/manager/database_manager_writer.dart index dbe9e965f..a7d566853 100644 --- a/drift_dev/lib/src/writer/manager/database_manager_writer.dart +++ b/drift_dev/lib/src/writer/manager/database_manager_writer.dart @@ -10,10 +10,14 @@ part 'table_manager_writer.dart'; class DatabaseManagerWriter { final Scope _scope; final String _dbClassName; - final List _addedTables; + final List _addedTables = []; + + /// Tables which may be referenced in added tables, but for which no code + /// should be generated. + final List _additionalTables = []; /// Class used to write a manager for a database - DatabaseManagerWriter(this._scope, this._dbClassName) : _addedTables = []; + DatabaseManagerWriter(this._scope, this._dbClassName); _ManagerCodeTemplates get _templates => _ManagerCodeTemplates(_scope); @@ -24,15 +28,23 @@ class DatabaseManagerWriter { _addedTables.add(table); } + /// Add a table for which no code should be generated by this manager writer. + /// + /// This is useful to track external tables in modular code generation mode. + void addTableWithoutGeneration(DriftTable table) { + _additionalTables.add(table); + } + /// Write a table manager for each table. void writeTableManagers() { final leaf = _scope.leaf(); for (var table in _addedTables) { - final otherTables = _addedTables - .whereNot( - (otherTable) => otherTable.equals(table), - ) - .toList(); + final otherTables = [ + for (final other in _addedTables) + if (other != table) other, + ..._additionalTables, + ]; + _TableManagerWriter( table: table, scope: _scope, diff --git a/drift_dev/test/backends/build/build_integration_test.dart b/drift_dev/test/backends/build/build_integration_test.dart index 2034b354d..d1fdc995f 100644 --- a/drift_dev/test/backends/build/build_integration_test.dart +++ b/drift_dev/test/backends/build/build_integration_test.dart @@ -1298,4 +1298,44 @@ second: SELECT 2; 'a|lib/src/second.drift.dart': anything, }, build.dartOutputs, build.writer); }); + + test('generates manager references for tables in different files', () async { + final build = await emulateDriftBuild( + inputs: { + 'a|lib/users.dart': ''' +import 'package:drift/drift.dart'; + +import 'groups.dart'; + +class Users extends Table { + late final id = integer().autoIncrement()(); + late final name = text()(); +} +''', + 'a|lib/groups.dart': ''' +import 'package:drift/drift.dart'; + +import 'users.dart'; + +class Groups extends Table { + late final id = integer().autoIncrement()(); + late final name = text()(); + @ReferenceName('administeredGroups') + late final admin = integer().nullable().references(Users, #id)(); + @ReferenceName('ownedGroups') + late final owner = integer().references(Users, #id)(); +} +''', + }, + modularBuild: true, + logger: loggerThat(neverEmits(anything)), + ); + + checkOutputs({ + 'a|lib/users.drift.dart': decodedMatches( + allOf(contains('ownedGroups'), contains('administeredGroups')), + ), + 'a|lib/groups.drift.dart': anything, + }, build.dartOutputs, build.writer); + }); } diff --git a/examples/modular/lib/src/posts.drift.dart b/examples/modular/lib/src/posts.drift.dart index 602fdff26..dc9b92844 100644 --- a/examples/modular/lib/src/posts.drift.dart +++ b/examples/modular/lib/src/posts.drift.dart @@ -298,7 +298,7 @@ class $PostsTableManager extends i0.RootTableManager< getPrefetchedDataCallback: (items) async { return [ if (likesRefs) - await i0.$_getPrefetchedData( + await i0.$_getPrefetchedData( currentTable: table, referencedTable: i1.$PostsReferences._likesRefsTable(db),