Name schema exports automatically (#1721)

This commit is contained in:
Simon Binder 2022-03-02 17:23:11 +01:00
parent 9c80fb047b
commit 61dc1f17b8
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
7 changed files with 134 additions and 13 deletions

View File

@ -271,21 +271,29 @@ To begin, let's create the first schema representation:
``` ```
$ mkdir drift_schemas $ mkdir drift_schemas
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/drift_schema_v1.json $ dart run drift_dev schema dump lib/database/database.dart drift_schemas/
``` ```
This instructs the generator to look at the database defined in `lib/database/database.dart` and extract This instructs the generator to look at the database defined in `lib/database/database.dart` and extract
its schema into the new folder. its schema into the new folder.
After making a change to your database schema, you can run the command again. For instance, let's say we After making a change to your database schema, you can run the command again. For instance, let's say we
made a change to our tables and increased the `schemaVersion` to `2`. We would then run: made a change to our tables and increased the `schemaVersion` to `2`. To dump the new schema, just run the
command again:
``` ```
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/drift_schema_v2.json $ dart run drift_dev schema dump lib/database/database.dart drift_schemas/
``` ```
You'll need to run this command every time you change the schema of your database and increment the `schemaVersion`. You'll need to run this command every time you change the schema of your database and increment the `schemaVersion`.
Remember to name the files `drift_schema_vX.json`, where `X` is the current `schemaVersion` of your database.
Drift will name the files in the folder `drift_schema_vX.json`, where `X` is the current `schemaVersion` of your
database.
If drift is unable to extract the version from your `schemaVersion` getter, provide the full path explicitly:
```
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/drift_schema_v3.json
```
#### Generating test code #### Generating test code

View File

@ -55,16 +55,20 @@ class MoorDartParser {
} }
@visibleForTesting @visibleForTesting
Expression? returnExpressionOfMethod(MethodDeclaration method) { Expression? returnExpressionOfMethod(MethodDeclaration method,
{bool reportErrorOnFailure = true}) {
final body = method.body; final body = method.body;
if (body is! ExpressionFunctionBody) { if (body is! ExpressionFunctionBody) {
step.reportError(ErrorInDartCode( if (reportErrorOnFailure) {
affectedElement: method.declaredElement, step.reportError(ErrorInDartCode(
severity: Severity.criticalError, affectedElement: method.declaredElement,
message: 'This method must have an expression body ' severity: Severity.criticalError,
'(use => instead of {return ...})', message: 'This method must have an expression body '
)); '(use => instead of {return ...})',
));
}
return null; return null;
} }

View File

@ -52,6 +52,7 @@ class UseMoorParser {
daos: daoTypes, daos: daoTypes,
declaredIncludes: includes, declaredIncludes: includes,
declaredQueries: parsedQueries, declaredQueries: parsedQueries,
schemaVersion: await _readSchemaVersion(element),
); );
} }
@ -63,4 +64,30 @@ class UseMoorParser {
.toList() ?? .toList() ??
[]; [];
} }
Future<int?> _readSchemaVersion(ClassElement dbClass) async {
final element = dbClass.thisType.getGetter('schemaVersion')?.variable;
if (element == null) return null;
final helper = MoorDartParser(step);
if (element.isSynthetic) {
// Getter, read from `=>` body if possible.
final expr = helper.returnExpressionOfMethod(
await helper.loadElementDeclaration(element.getter!)
as MethodDeclaration,
reportErrorOnFailure: false);
if (expr is IntegerLiteral) {
return expr.value;
}
} else {
final astField =
await helper.loadElementDeclaration(element) as VariableDeclaration;
if (astField.initializer is IntegerLiteral) {
return (astField.initializer as IntegerLiteral).value;
}
}
return null;
}
} }

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:drift_dev/src/analyzer/runner/results.dart'; import 'package:drift_dev/src/analyzer/runner/results.dart';
import 'package:drift_dev/src/services/schema/schema_files.dart'; import 'package:drift_dev/src/services/schema/schema_files.dart';
import 'package:path/path.dart';
import '../../cli.dart'; import '../../cli.dart';
@ -51,6 +52,33 @@ class DumpSchemaCommand extends Command {
final db = result.declaredDatabases.single; final db = result.declaredDatabases.single;
final writer = SchemaWriter(db); final writer = SchemaWriter(db);
await File(rest[1]).writeAsString(json.encode(writer.createSchemaJson())); var target = rest[1];
// This command is most commonly used to write into
// `<dir>/drift_schema_vx.json`. When we get a directory as a second arg,
// try to infer the file name.
if (await FileSystemEntity.isDirectory(target) ||
!target.endsWith('.json')) {
final version = db.schemaVersion;
if (version == null) {
// Couldn't read schema from database, so fail.
usageException(
'Target is a directory and the schema version could not be read from '
'the database class. Please use a full filename (e.g. '
'`$target/drift_schema_v3.json`)',
);
}
target = join(target, 'drift_schema_v$version.json');
}
final file = File(target);
final parent = file.parent;
if (!await parent.exists()) {
await parent.create(recursive: true);
}
await File(target).writeAsString(json.encode(writer.createSchemaJson()));
print('Wrote to $target');
} }
} }

View File

@ -59,8 +59,16 @@ abstract class BaseMoorAccessor implements HasDeclaration {
class Database extends BaseMoorAccessor { class Database extends BaseMoorAccessor {
final List<DartType> daos; final List<DartType> daos;
/// If the source database class overrides `schemaVersion` and returns a
/// simple integer literal, stores that version.
///
/// This is optionally used by the migration tooling to store the schema in a
/// versioned file.
int? schemaVersion;
Database({ Database({
this.daos = const [], this.daos = const [],
this.schemaVersion,
DatabaseOrDaoDeclaration? declaration, DatabaseOrDaoDeclaration? declaration,
List<MoorTable> declaredTables = const [], List<MoorTable> declaredTables = const [],
List<MoorView> declaredViews = const [], List<MoorView> declaredViews = const [],

View File

@ -0,0 +1,46 @@
import 'package:drift_dev/src/analyzer/runner/results.dart';
import 'package:test/test.dart';
import '../utils.dart';
void main() {
test('parses schema version getter', () async {
final state = TestState.withContent({
'a|lib/main.dart': r'''
import 'package:drift/drift.dart';
@DriftDatabase()
class MyDatabase extends _$MyDatabase {
@override
int get schemaVersion => 13;
}
''',
});
addTearDown(state.close);
final file = (await state.analyze('package:a/main.dart')).currentResult!;
final db = (file as ParsedDartFile).declaredDatabases.single;
expect(db.schemaVersion, 13);
});
test('parses schema version field', () async {
final state = TestState.withContent({
'a|lib/main.dart': r'''
import 'package:drift/drift.dart';
@DriftDatabase()
class MyDatabase extends _$MyDatabase {
@override
final int schemaVersion = 23;
}
''',
});
addTearDown(state.close);
final file = (await state.analyze('package:a/main.dart')).currentResult!;
final db = (file as ParsedDartFile).declaredDatabases.single;
expect(db.schemaVersion, 23);
});
}

View File

@ -9,7 +9,7 @@ See `test/migration_test.dart` on how to use the generated verification code.
After adapting a schema and incrementing the `schemaVersion` in the database, run After adapting a schema and incrementing the `schemaVersion` in the database, run
``` ```
dart run drift_dev schema dump lib/database.dart moor_migrations/moor_schema_v2.json dart run drift_dev schema dump lib/database.dart drift_migrations/
``` ```
Replace `_v2` with the current `schemaVersion`. Replace `_v2` with the current `schemaVersion`.