mirror of https://github.com/AMT-Cheif/drift.git
Serialize and restore file dependencies too
This commit is contained in:
parent
e51bb0976e
commit
a6549425ef
|
@ -1,6 +1,7 @@
|
|||
## 2.7.0-dev
|
||||
|
||||
- Make `validateDatabaseSchema()` work in migration tests.
|
||||
- Fix elements from transitive imports in drift files not being added reliably.
|
||||
|
||||
## 2.6.0
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'state.dart';
|
|||
///
|
||||
/// At the moment, the cache is not set up to handle changing files.
|
||||
class DriftAnalysisCache {
|
||||
final Map<Uri, Map<String, Object?>> serializedElements = {};
|
||||
final Map<Uri, CachedSerializationResult> serializationCache = {};
|
||||
final Map<Uri, FileState> knownFiles = {};
|
||||
final Map<DriftElementId, DiscoveredElement> discoveredElements = {};
|
||||
|
||||
|
@ -16,7 +16,7 @@ class DriftAnalysisCache {
|
|||
FileState notifyFileChanged(Uri uri) {
|
||||
// todo: Mark references for files that import this one as stale.
|
||||
// todo: Mark elements that reference an element in this file as stale.
|
||||
serializedElements.remove(uri);
|
||||
serializationCache.remove(uri);
|
||||
|
||||
return knownFiles.putIfAbsent(uri, () => FileState(uri))
|
||||
..errorsDuringDiscovery.clear()
|
||||
|
@ -62,8 +62,7 @@ class DriftAnalysisCache {
|
|||
final found = pending.removeLast();
|
||||
yield found;
|
||||
|
||||
for (final imported
|
||||
in found.discovery?.importDependencies ?? const <Uri>[]) {
|
||||
for (final imported in found.imports ?? const <Uri>[]) {
|
||||
if (seenUris.add(imported)) {
|
||||
pending.add(knownFiles[imported]!);
|
||||
}
|
||||
|
@ -71,3 +70,10 @@ class DriftAnalysisCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CachedSerializationResult {
|
||||
final List<Uri> cachedImports;
|
||||
final Map<String, Map<String, Object?>> cachedElements;
|
||||
|
||||
CachedSerializationResult(this.cachedImports, this.cachedElements);
|
||||
}
|
||||
|
|
|
@ -98,8 +98,8 @@ class DriftAnalysisDriver {
|
|||
///
|
||||
/// Returns non-null if analysis results were found and successfully restored.
|
||||
Future<Map<String, Object?>?> readStoredAnalysisResult(Uri uri) async {
|
||||
final cached = cache.serializedElements[uri];
|
||||
if (cached != null) return cached;
|
||||
final cached = cache.serializationCache[uri];
|
||||
if (cached != null) return cached.cachedElements;
|
||||
|
||||
// Not available in in-memory cache, so let's read it from the file system.
|
||||
final reader = cacheReader;
|
||||
|
@ -109,7 +109,15 @@ class DriftAnalysisDriver {
|
|||
if (found == null) return null;
|
||||
|
||||
final parsed = json.decode(found) as Map<String, Object?>;
|
||||
return cache.serializedElements[uri] = parsed;
|
||||
final data = CachedSerializationResult(
|
||||
[
|
||||
for (final entry in parsed['imports'] as List)
|
||||
Uri.parse(entry as String)
|
||||
],
|
||||
(parsed['elements'] as Map<String, Object?>).cast(),
|
||||
);
|
||||
cache.serializationCache[uri] = data;
|
||||
return data.cachedElements;
|
||||
}
|
||||
|
||||
Future<bool> _recoverFromCache(FileState state) async {
|
||||
|
@ -128,6 +136,21 @@ class DriftAnalysisDriver {
|
|||
}
|
||||
}
|
||||
|
||||
final cachedImports = cache.serializationCache[state.ownUri]?.cachedImports;
|
||||
if (cachedImports != null && state.discovery == null) {
|
||||
state.cachedImports = cachedImports;
|
||||
for (final import in cachedImports) {
|
||||
final found = cache.stateForUri(import);
|
||||
|
||||
if (found.imports == null) {
|
||||
// Attempt to recover this file as well to make sure we know the
|
||||
// imports for every file transitively reachable from the sources
|
||||
// analyzed.
|
||||
await _recoverFromCache(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allRecovered;
|
||||
}
|
||||
|
||||
|
@ -231,6 +254,24 @@ class DriftAnalysisDriver {
|
|||
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Serializes imports and locally-defined elements of the file.
|
||||
///
|
||||
/// Serialized data can later be recovered if a [cacheReader] is set on this
|
||||
/// driver, which avoids running duplicate analysis runs across build steps.
|
||||
SerializedElements serializeState(FileState state) {
|
||||
final data = ElementSerializer.serialize(
|
||||
state.analysis.values.map((e) => e.result).whereType());
|
||||
|
||||
final imports = state.discovery?.importDependencies;
|
||||
if (imports != null) {
|
||||
data.serializedData['imports'] = [
|
||||
for (final import in imports) import.toString()
|
||||
];
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads serialized data and a generated Dart helper file used to serialize
|
||||
|
|
|
@ -15,6 +15,8 @@ class FileState {
|
|||
final Uri ownUri;
|
||||
|
||||
DiscoveredFileState? discovery;
|
||||
List<Uri>? cachedImports;
|
||||
|
||||
final List<DriftAnalysisError> errorsDuringDiscovery = [];
|
||||
|
||||
final Map<DriftElementId, ElementAnalysisState> analysis = {};
|
||||
|
@ -24,6 +26,8 @@ class FileState {
|
|||
|
||||
FileState(this.ownUri);
|
||||
|
||||
Iterable<Uri>? get imports => discovery?.importDependencies ?? cachedImports;
|
||||
|
||||
String get extension => url.extension(ownUri.path);
|
||||
|
||||
/// Whether this file contains a drift database or a drift accessor / DAO.
|
||||
|
|
|
@ -10,9 +10,13 @@ import 'results/results.dart';
|
|||
|
||||
class SerializedElements {
|
||||
final List<AnnotatedDartCode> dartTypes;
|
||||
final Map<String, Object?> serializedElements;
|
||||
final Map<String, Object?> serializedData;
|
||||
final Map<String, Object?> _serializedElements;
|
||||
|
||||
SerializedElements(this.dartTypes, this.serializedElements);
|
||||
SerializedElements(
|
||||
this.dartTypes, this.serializedData, this._serializedElements) {
|
||||
serializedData['elements'] = _serializedElements;
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes [DriftElement]s to JSON.
|
||||
|
@ -22,13 +26,13 @@ class SerializedElements {
|
|||
/// a single file changes). However, it means that we have to serialize analysis
|
||||
/// results to read them back in in a later build step.
|
||||
class ElementSerializer {
|
||||
final SerializedElements _result = SerializedElements([], {});
|
||||
final SerializedElements _result = SerializedElements([], {}, {});
|
||||
|
||||
ElementSerializer._();
|
||||
|
||||
void _serializeElements(Iterable<DriftElement> elements) {
|
||||
for (final element in elements) {
|
||||
_result.serializedElements[element.id.name] = _serialize(element);
|
||||
_result._serializedElements[element.id.name] = _serialize(element);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:convert';
|
|||
import 'package:build/build.dart';
|
||||
|
||||
import '../../analysis/driver/driver.dart';
|
||||
import '../../analysis/serializer.dart';
|
||||
import '../../analysis/options.dart';
|
||||
import '../../writer/import_manager.dart';
|
||||
import '../../writer/writer.dart';
|
||||
|
@ -45,10 +44,9 @@ class DriftAnalyzer extends Builder {
|
|||
}
|
||||
}
|
||||
|
||||
final serialized = ElementSerializer.serialize(
|
||||
results.analysis.values.map((e) => e.result).whereType());
|
||||
final serialized = driver.serializeState(results);
|
||||
final asJson =
|
||||
JsonUtf8Encoder(' ' * 2).convert(serialized.serializedElements);
|
||||
JsonUtf8Encoder(' ' * 2).convert(serialized.serializedData);
|
||||
|
||||
final jsonOutput = buildStep.inputId.addExtension('.drift_module.json');
|
||||
final typesOutput = buildStep.inputId.addExtension('.types.temp.dart');
|
||||
|
|
|
@ -347,4 +347,37 @@ class Database extends $Database {}
|
|||
'a|lib/db.drift.dart': decodedMatches(contains(r'.$drift0];'))
|
||||
}, result.dartOutputs, result);
|
||||
});
|
||||
|
||||
test('writes query from transitive import', () async {
|
||||
final result = await emulateDriftBuild(
|
||||
inputs: {
|
||||
'a|lib/main.dart': '''
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
@DriftDatabase(include: {'a.drift'})
|
||||
class MyDatabase {}
|
||||
''',
|
||||
'a|lib/a.drift': '''
|
||||
import 'b.drift';
|
||||
|
||||
CREATE TABLE foo (bar INTEGER);
|
||||
''',
|
||||
'a|lib/b.drift': '''
|
||||
import 'c.drift';
|
||||
|
||||
CREATE TABLE foo2 (bar INTEGER);
|
||||
''',
|
||||
'a|lib/c.drift': '''
|
||||
q: SELECT 1;
|
||||
''',
|
||||
},
|
||||
logger: loggerThat(neverEmits(anything)),
|
||||
);
|
||||
|
||||
checkOutputs({
|
||||
'a|lib/main.drift.dart': decodedMatches(
|
||||
contains(r'Selectable<int> q()'),
|
||||
)
|
||||
}, result.dartOutputs, result);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ abstract class $Database extends i0.GeneratedDatabase {
|
|||
likes,
|
||||
follows,
|
||||
popularUsers,
|
||||
i1.usersName,
|
||||
i4.$drift0
|
||||
];
|
||||
@override
|
||||
|
|
Loading…
Reference in New Issue