@Tags(['analyzer']) import 'dart:convert'; import 'package:drift_dev/src/analysis/options.dart'; import 'package:drift_dev/src/analysis/results/file_results.dart'; import 'package:drift_dev/src/analysis/results/results.dart'; import 'package:drift_dev/src/services/schema/schema_files.dart'; import 'package:drift_dev/src/writer/database_writer.dart'; import 'package:drift_dev/src/writer/import_manager.dart'; import 'package:drift_dev/src/writer/writer.dart'; import 'package:test/test.dart'; import '../../analysis/test_utils.dart'; void main() { test('writer integration test', () async { final state = TestBackend.inTest({ 'a|lib/a.drift': ''' import 'main.dart'; CREATE TABLE "groups" ( id INT NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, UNIQUE(name) ); CREATE VIRTUAL TABLE email USING fts5(sender, title, body); CREATE TABLE group_members ( "group" INT NOT NULL REFERENCES "groups"(id), user INT NOT NULL REFERENCES users(id), is_admin BOOLEAN NOT NULL DEFAULT FALSE, PRIMARY KEY ("group", user) ON CONFLICT REPLACE ); CREATE TRIGGER delete_empty_groups AFTER DELETE ON group_members BEGIN DELETE FROM "groups" WHERE NOT EXISTS (SELECT * FROM group_members WHERE "group" = "groups".id); END; CREATE INDEX groups_name ON "groups"(name); CREATE VIEW my_view WITH MyViewRow AS SELECT id FROM "groups"; simple_query: SELECT * FROM my_view; -- not part of the schema ''', 'a|lib/main.dart': ''' import 'package:drift/drift.dart'; class Users extends Table { IntColumn get id => integer().autoIncrement()(); TextColumn get name => text()(); TextColumn get settings => text().named('setting').map(const SettingsConverter())(); @override List> get uniqueKeys => [{name, settings}]; } class Settings {} class SettingsConverter extends TypeConverter { const SettingsConverter(); String toSql(Settings s) => ''; Settings fromSql(String db) => Settings(); } class MyViewRow { final int id; MyViewRow(this.id); } @DriftDatabase(include: {'a.drift'}, tables: [Users]) class Database {} ''', }, options: const DriftOptions.defaults(modules: [SqlModule.fts5])); final file = await state.analyze('package:a/main.dart'); state.expectNoErrors(); final db = file.fileAnalysis!.resolvedDatabases.values.single; final schemaJson = SchemaWriter(db.availableElements).createSchemaJson(); expect(schemaJson, json.decode(expected)); final schemaWithOptions = SchemaWriter( db.availableElements, options: const DriftOptions.defaults(storeDateTimeValuesAsText: true), ).createSchemaJson(); expect( schemaWithOptions['options'], {'store_date_time_values_as_text': true}); }); test('can generate code from schema json', () { final serializedSchema = json.decode( // Column types used to be serialized under a different format, test // reading that as well. expected.replaceAll('"int"', '"ColumnType.integer"')) as Map; final reader = SchemaReader.readJson(serializedSchema); final writer = Writer( const DriftOptions.defaults(), generationOptions: GenerationOptions( forSchema: 1, writeCompanions: true, writeDataClasses: true, imports: ImportManagerForPartFiles(), ), ); final database = DriftDatabase( id: DriftElementId(SchemaReader.elementUri, 'database'), declaration: DriftDeclaration(SchemaReader.elementUri, 0, 'database'), declaredIncludes: const [], declaredQueries: const [], declaredTables: const [], declaredViews: const [], ); final resolved = ResolvedDatabaseAccessor(const {}, const [], reader.entities.toList()); final input = DatabaseGenerationInput(database, resolved, const {}, null); // Write the database. Not crashing is good enough for us here, we have // separate tests for verification DatabaseWriter(input, writer.child()).write(); }); } const expected = r''' { "_meta": { "description": "This file contains a serialized version of schema entities for drift.", "version": "1.0.0" }, "options": { "store_date_time_values_as_text": false }, "entities": [ { "id": 0, "references": [], "type": "table", "data": { "name": "groups", "was_declared_in_moor": true, "columns": [ { "name": "id", "getter_name": "id", "moor_type": "int", "nullable": false, "customConstraints": "NOT NULL PRIMARY KEY AUTOINCREMENT", "default_dart": null, "default_client_dart": null, "dsl_features": [ "auto-increment" ] }, { "name": "name", "getter_name": "name", "moor_type": "string", "nullable": false, "customConstraints": "NOT NULL", "default_dart": null, "default_client_dart": null, "dsl_features": [] } ], "is_virtual": false, "without_rowid": false, "constraints": [ "UNIQUE(name)" ], "unique_keys": [ [ "name" ] ] } }, { "id": 1, "references": [], "type": "table", "data": { "name": "email", "was_declared_in_moor": true, "columns": [ { "name": "sender", "getter_name": "sender", "moor_type": "string", "nullable": false, "customConstraints": "", "default_dart": null, "default_client_dart": null, "dsl_features": [] }, { "name": "title", "getter_name": "title", "moor_type": "string", "nullable": false, "customConstraints": "", "default_dart": null, "default_client_dart": null, "dsl_features": [] }, { "name": "body", "getter_name": "body", "moor_type": "string", "nullable": false, "customConstraints": "", "default_dart": null, "default_client_dart": null, "dsl_features": [] } ], "is_virtual": true, "create_virtual_stmt": "CREATE VIRTUAL TABLE \"email\" USING fts5(sender, title, body)", "without_rowid": false, "constraints": [] } }, { "id": 2, "references": [], "type": "table", "data": { "name": "users", "was_declared_in_moor": false, "columns": [ { "name": "id", "getter_name": "id", "moor_type": "int", "nullable": false, "customConstraints": null, "defaultConstraints": "PRIMARY KEY AUTOINCREMENT", "default_dart": null, "default_client_dart": null, "dsl_features": [ "auto-increment" ] }, { "name": "name", "getter_name": "name", "moor_type": "string", "nullable": false, "customConstraints": null, "default_dart": null, "default_client_dart": null, "dsl_features": [] }, { "name": "setting", "getter_name": "settings", "moor_type": "string", "nullable": false, "customConstraints": null, "default_dart": null, "default_client_dart": null, "dsl_features": [], "type_converter": { "dart_expr": "const SettingsConverter()", "dart_type_name": "Settings" } } ], "is_virtual": false, "without_rowid": false, "constraints": [], "unique_keys": [ [ "name", "setting" ] ] } }, { "id": 3, "references": [ 0, 2 ], "type": "table", "data": { "name": "group_members", "was_declared_in_moor": true, "columns": [ { "name": "group", "getter_name": "group", "moor_type": "int", "nullable": false, "customConstraints": "NOT NULL REFERENCES \"groups\"(id)", "default_dart": null, "default_client_dart": null, "dsl_features": [ "unknown" ] }, { "name": "user", "getter_name": "user", "moor_type": "int", "nullable": false, "customConstraints": "NOT NULL REFERENCES users(id)", "default_dart": null, "default_client_dart": null, "dsl_features": [ "unknown" ] }, { "name": "is_admin", "getter_name": "isAdmin", "moor_type": "bool", "nullable": false, "customConstraints": "NOT NULL DEFAULT FALSE", "default_dart": "const CustomExpression('FALSE')", "default_client_dart": null, "dsl_features": [] } ], "is_virtual": false, "without_rowid": false, "constraints": [ "PRIMARY KEY(\"group\", user)ON CONFLICT REPLACE" ], "explicit_pk": [ "group", "user" ] } }, { "id": 4, "references": [ 3, 0 ], "type": "trigger", "data": { "on": 3, "references_in_body": [ 3, 0 ], "name": "delete_empty_groups", "sql": "CREATE TRIGGER delete_empty_groups AFTER DELETE ON group_members BEGIN\n DELETE FROM \"groups\"\n WHERE NOT EXISTS (SELECT * FROM group_members WHERE \"group\" = \"groups\".id);\nEND;" } }, { "id": 5, "references": [ 0 ], "type": "index", "data": { "on": 0, "name": "groups_name", "sql": "CREATE INDEX groups_name ON \"groups\"(name);" } }, { "id": 6, "references": [ 0 ], "type": "view", "data": { "name": "my_view", "sql": "CREATE VIEW my_view AS SELECT id FROM \"groups\";", "dart_info_name": "MyView", "columns": [ { "name": "id", "getter_name": "id", "moor_type": "int", "nullable": false, "customConstraints": null, "default_dart": null, "default_client_dart": null, "dsl_features": [] } ] } } ] } ''';