Skip to content

Commit 865d4de

Browse files
committed
chore(ast): Add version field to DatabaseSchema
1 parent 0b20b8a commit 865d4de

File tree

8 files changed

+519
-317
lines changed

8 files changed

+519
-317
lines changed

apps/cli/lib/src/analyzer/celest_analysis_helpers.dart

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import 'package:analyzer/dart/analysis/analysis_context.dart';
22
import 'package:analyzer/dart/analysis/results.dart';
3+
import 'package:analyzer/dart/ast/ast.dart';
34
import 'package:analyzer/dart/constant/value.dart';
45
import 'package:analyzer/dart/element/element.dart';
6+
import 'package:analyzer/dart/element/element2.dart';
57
import 'package:analyzer/dart/element/type.dart';
8+
import 'package:analyzer/src/dart/analysis/session_helper.dart';
9+
import 'package:analyzer/src/dart/ast/ast.dart';
610
import 'package:analyzer/src/dart/resolver/scope.dart';
711
import 'package:celest_cli/src/analyzer/analysis_error.dart';
812
import 'package:celest_cli/src/analyzer/resolver/project_resolver.dart';
@@ -53,6 +57,11 @@ mixin CelestAnalysisHelpers implements CelestErrorReporter {
5357
Set<InterfaceElement> get customExceptionTypes;
5458
Set<InterfaceElement> get customModelTypes;
5559

60+
static final Expando<AnalysisSessionHelper> _sessionHelpers = Expando();
61+
AnalysisSessionHelper get helper =>
62+
_sessionHelpers[context.currentSession] ??=
63+
AnalysisSessionHelper(context.currentSession);
64+
5665
final pendingEdits = <String, Set<SourceEdit>>{};
5766

5867
static final Logger _logger = Logger('CelestAnalyzer');
@@ -292,6 +301,84 @@ mixin CelestAnalysisHelpers implements CelestErrorReporter {
292301
);
293302
}
294303
}
304+
305+
/// Resolves the schema version of a Drift database class.
306+
Future<int> resolveSchemaVersion(ClassElement2 databaseClass) async {
307+
final schemaVersionMethod =
308+
databaseClass.getGetter2('schemaVersion')?.variable3;
309+
if (schemaVersionMethod == null) {
310+
reportError(
311+
'Invalid database class: No `schemaVersion` getter.',
312+
severity: AnalysisErrorSeverity.error,
313+
location: databaseClass.sourceLocation,
314+
);
315+
return -1;
316+
}
317+
final declaration = await helper.getElementDeclaration(
318+
schemaVersionMethod.isSynthetic
319+
? schemaVersionMethod.getter2!.firstFragment
320+
: schemaVersionMethod.firstFragment,
321+
);
322+
323+
int? resolveExpression(Expression? expression) {
324+
switch (expression) {
325+
// int get schemaVersion => 1;
326+
case IntegerLiteral(value: final version?):
327+
return version;
328+
329+
// int get schemaVersion => someConstVariable;
330+
case Identifier(
331+
staticElement: PropertyAccessorElement(:final variable2?)
332+
):
333+
if (variable2.computeConstantValue()?.toIntValue()
334+
case final version?) {
335+
return version;
336+
}
337+
}
338+
339+
return null;
340+
}
341+
342+
switch (declaration?.node) {
343+
case VariableDeclaration(:final initializer):
344+
if (resolveExpression(initializer) case final version?) {
345+
return version;
346+
}
347+
348+
// Could not determine schema version.
349+
reportError(
350+
'Invalid `schemaVersion` declaration: Must resolve to an integer.',
351+
severity: AnalysisErrorSeverity.error,
352+
location: schemaVersionMethod.sourceLocation,
353+
);
354+
return -1;
355+
356+
case MethodDeclaration(:final body):
357+
switch (body) {
358+
case ExpressionFunctionBody(:final expression):
359+
if (resolveExpression(expression) case final version?) {
360+
return version;
361+
}
362+
case BlockFunctionBody():
363+
case EmptyFunctionBody():
364+
case NativeFunctionBody():
365+
}
366+
367+
// Could not determine schema version.
368+
reportError(
369+
'Invalid `schemaVersion` declaration: Must use => syntax.',
370+
severity: AnalysisErrorSeverity.error,
371+
location: schemaVersionMethod.sourceLocation,
372+
);
373+
return -1;
374+
375+
case final unknown:
376+
throw StateError(
377+
'Failed to resolve method declaration for $schemaVersionMethod: '
378+
'Got $unknown (${unknown.runtimeType})',
379+
);
380+
}
381+
}
295382
}
296383

297384
extension TopLevelConstants on LibraryElement {

apps/cli/lib/src/utils/analyzer.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'dart:math';
44
import 'package:analyzer/dart/ast/ast.dart';
55
import 'package:analyzer/dart/constant/value.dart';
66
import 'package:analyzer/dart/element/element.dart';
7+
import 'package:analyzer/dart/element/element2.dart';
78
import 'package:analyzer/dart/element/nullability_suffix.dart';
89
import 'package:analyzer/dart/element/type.dart';
910
import 'package:analyzer/source/source.dart';
@@ -109,6 +110,12 @@ extension DartTypeHelper on DartType {
109110
bool get isCelestSecret =>
110111
element == typeHelper.coreTypes.celestSecretElement;
111112

113+
bool get isCloudAuthDatabaseMixin => switch (element) {
114+
MixinElement(:final name, :final library) =>
115+
name == 'CloudAuthDatabaseMixin' && library.isCelestSdk,
116+
_ => false,
117+
};
118+
112119
bool get isAuth => switch (element) {
113120
ClassElement(:final name, :final library) =>
114121
name == 'Auth' && library.isPackageCelest,
@@ -660,6 +667,21 @@ extension ElementSourceLocation on Element {
660667
};
661668
}
662669

670+
extension Element2SourceLocation on Element2 {
671+
FileSpan? get sourceLocation {
672+
final source = library2?.firstFragment.source;
673+
if (source == null || !source.exists()) {
674+
return null;
675+
}
676+
final nameOffset = firstFragment.nameOffset2 ?? -1;
677+
final nameLength = firstFragment.name2?.length ?? 0;
678+
if (nameOffset < 0) {
679+
return null;
680+
}
681+
return source.toSpan(nameOffset, nameOffset + nameLength);
682+
}
683+
}
684+
663685
extension ElementAnnotationSourceLocation on ElementAnnotation {
664686
FileSpan sourceLocation(Source source) {
665687
final impl = this as ElementAnnotationImpl;

packages/celest_ast/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## 0.1.6
1+
## 0.1.6-wip
22

3+
- chore: Add `version` field to `DatabaseSchema`
34
- chore: Update license
45

56
## 0.1.5

packages/celest_ast/lib/src/ast.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,9 @@ sealed class DatabaseSchema implements AstNode {
10651065
/// The type of database schema.
10661066
DatabaseSchemaType get type;
10671067

1068+
/// The version of the schema.
1069+
int get version;
1070+
10681071
/// The Dart type declaring the database schema.
10691072
TypeReference get declaration;
10701073
}
@@ -1088,10 +1091,12 @@ abstract class DriftDatabaseSchema
10881091
DatabaseSchema {
10891092
factory DriftDatabaseSchema({
10901093
required TypeReference declaration,
1094+
int version = 1,
10911095
required FileSpan location,
10921096
}) {
10931097
return _$DriftDatabaseSchema._(
10941098
declaration: declaration,
1099+
version: version,
10951100
location: location,
10961101
);
10971102
}

0 commit comments

Comments
 (0)