From e4913219e49fb9a5be5697d2c7e6654643289e04 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sat, 9 Feb 2019 13:13:08 +0100 Subject: [PATCH] Generate database classes --- example/lib/example.dart | 2 - example/lib/example.g.dart | 27 ++++++---- example/lib/example.g.dart.custom | 50 ------------------- .../lib/src/model/specified_database.dart | 11 ++++ .../lib/src/parser/table_parser.dart | 6 +-- sally_generator/lib/src/sally_generator.dart | 15 ++++-- sally_generator/lib/src/utils/names.dart | 16 ++++++ .../lib/src/writer/database_writer.dart | 30 +++++++++++ .../lib/src/writer/table_writer.dart | 6 +-- 9 files changed, 89 insertions(+), 74 deletions(-) delete mode 100644 example/lib/example.g.dart.custom create mode 100644 sally_generator/lib/src/model/specified_database.dart create mode 100644 sally_generator/lib/src/utils/names.dart create mode 100644 sally_generator/lib/src/writer/database_writer.dart diff --git a/example/lib/example.dart b/example/lib/example.dart index d7f967ac..cd15159a 100644 --- a/example/lib/example.dart +++ b/example/lib/example.dart @@ -1,6 +1,5 @@ import 'package:sally/sally.dart'; -part 'example.g.dart.custom'; part 'example.g.dart'; class Products extends Table { @@ -19,7 +18,6 @@ class Users extends Table { @UseSally(tables: [Products, Users]) class ShopDb extends _$ShopDb { - ShopDb(SqlTypeSystem typeSystem, QueryExecutor executor) : super(typeSystem, executor); Future> allUsers() => select(users).get(); Future> userByName(String name) => (select(users)..where((u) => u.name.equalsVal(name))).get(); diff --git a/example/lib/example.g.dart b/example/lib/example.g.dart index 347c0a46..6a369e65 100644 --- a/example/lib/example.g.dart +++ b/example/lib/example.g.dart @@ -6,14 +6,13 @@ part of 'example.dart'; // SallyGenerator // ************************************************************************** -class ProductsData { +class Product { final int id; final String name; - ProductsData({this.id, this.name}); + Product({this.id, this.name}); } -class _$ProductsTable extends Products - implements TableInfo { +class _$ProductsTable extends Products implements TableInfo { final GeneratedDatabase db; _$ProductsTable(this.db); @override @@ -29,23 +28,23 @@ class _$ProductsTable extends Products @override Set get $primaryKey => Set(); @override - ProductsData map(Map data) { + Product map(Map data) { final intType = db.typeSystem.forDartType(); final stringType = db.typeSystem.forDartType(); - return ProductsData( + return Product( id: intType.mapFromDatabaseResponse(data['products_id']), name: stringType.mapFromDatabaseResponse(data['name']), ); } } -class UsersData { +class User { final int id; final String name; - UsersData({this.id, this.name}); + User({this.id, this.name}); } -class _$UsersTable extends Users implements TableInfo { +class _$UsersTable extends Users implements TableInfo { final GeneratedDatabase db; _$UsersTable(this.db); @override @@ -61,12 +60,18 @@ class _$UsersTable extends Users implements TableInfo { @override Set get $primaryKey => Set(); @override - UsersData map(Map data) { + User map(Map data) { final intType = db.typeSystem.forDartType(); final stringType = db.typeSystem.forDartType(); - return UsersData( + return User( id: intType.mapFromDatabaseResponse(data['id']), name: stringType.mapFromDatabaseResponse(data['name']), ); } } + +abstract class _$ShopDb extends GeneratedDatabase { + _$ShopDb() : super(const SqlTypeSystem.withDefaults(), null); + _$ProductsTable get products => _$ProductsTable(this); + _$UsersTable get users => _$UsersTable(this); +} diff --git a/example/lib/example.g.dart.custom b/example/lib/example.g.dart.custom deleted file mode 100644 index 389a476f..00000000 --- a/example/lib/example.g.dart.custom +++ /dev/null @@ -1,50 +0,0 @@ -part of 'example.dart'; - -abstract class _$ShopDb extends GeneratedDatabase { - - _$ShopDb(SqlTypeSystem typeSystem, QueryExecutor executor) : super(typeSystem, executor); - - UsersTable get users => null; -} - -class User { - - final int id; - final String name; - - User(this.id, this.name); - -} - -class UsersTable extends Users implements TableInfo { - - final GeneratedDatabase db; - - UsersTable(this.db); - - @override - List get $columns => [id, name]; - - @override - String get $tableName => "users"; - - @override - IntColumn get id => GeneratedIntColumn("id", true); - - @override - TextColumn get name => GeneratedTextColumn("name", false); - - @override - Users get asDslTable => this; - - @override - User map(Map data) { - final intType = db.typeSystem.forDartType(); - final stringType = db.typeSystem.forDartType(); - - return User(intType.mapFromDatabaseResponse(data["id"]), stringType.mapFromDatabaseResponse(data["name"])); - } - @override - Set get $primaryKey => Set()..add(id); - -} diff --git a/sally_generator/lib/src/model/specified_database.dart b/sally_generator/lib/src/model/specified_database.dart new file mode 100644 index 00000000..209f85e7 --- /dev/null +++ b/sally_generator/lib/src/model/specified_database.dart @@ -0,0 +1,11 @@ +import 'package:analyzer/dart/element/element.dart'; +import 'package:sally_generator/src/model/specified_table.dart'; + +class SpecifiedDatabase { + + final ClassElement fromClass; + final List tables; + + SpecifiedDatabase(this.fromClass, this.tables); + +} diff --git a/sally_generator/lib/src/parser/table_parser.dart b/sally_generator/lib/src/parser/table_parser.dart index dab071b8..bafd24a5 100644 --- a/sally_generator/lib/src/parser/table_parser.dart +++ b/sally_generator/lib/src/parser/table_parser.dart @@ -4,6 +4,7 @@ import 'package:sally_generator/src/errors.dart'; import 'package:sally_generator/src/model/specified_column.dart'; import 'package:sally_generator/src/model/specified_table.dart'; import 'package:sally_generator/src/parser/parser.dart'; +import 'package:sally_generator/src/utils/names.dart'; import 'package:sally_generator/src/utils/type_utils.dart'; import 'package:sally_generator/src/sally_generator.dart'; // ignore: implementation_imports import 'package:recase/recase.dart'; @@ -18,9 +19,8 @@ class TableParser extends ParserBase { fromClass: element, columns: _parseColumns(element), sqlName: sqlName, - dartTypeName: - '${element.name}Data' // TODO better name for generated data classes - ); + dartTypeName: dataClassNameForClassName(element.name) + ); } String _parseTableName(ClassElement element) { diff --git a/sally_generator/lib/src/sally_generator.dart b/sally_generator/lib/src/sally_generator.dart index ba6f0deb..b8db3219 100644 --- a/sally_generator/lib/src/sally_generator.dart +++ b/sally_generator/lib/src/sally_generator.dart @@ -5,10 +5,11 @@ import 'package:analyzer/src/dart/analysis/results.dart'; // ignore: implementat import 'package:analyzer/dart/element/element.dart'; import 'package:build/build.dart'; import 'package:sally_generator/src/errors.dart'; +import 'package:sally_generator/src/model/specified_database.dart'; import 'package:sally_generator/src/model/specified_table.dart'; import 'package:sally_generator/src/parser/column_parser.dart'; import 'package:sally_generator/src/parser/table_parser.dart'; -import 'package:sally_generator/src/writer/table_writer.dart'; +import 'package:sally_generator/src/writer/database_writer.dart'; import 'package:source_gen/source_gen.dart'; class SallyGenerator extends GeneratorForAnnotation { @@ -40,6 +41,8 @@ class SallyGenerator extends GeneratorForAnnotation { tableParser ??= TableParser(this); columnParser ??= ColumnParser(this); + final tablesForThisDb = []; + for (var table in types) { if (!tableTypeChecker.isAssignableFrom(table.element)) { errors.add(SallyError( @@ -47,17 +50,19 @@ class SallyGenerator extends GeneratorForAnnotation { message: 'The type $table is not a sally table', affectedElement: element)); } else { - _foundTables[table] = tableParser.parse(table.element as ClassElement); + final specifiedTable = tableParser.parse(table.element as ClassElement); + _foundTables[table] = specifiedTable; + tablesForThisDb.add(specifiedTable); } } if (_foundTables.isEmpty) return ''; + final specifiedDb = SpecifiedDatabase(element as ClassElement, tablesForThisDb); + final buffer = StringBuffer(); - for (var tbl in _foundTables.values) { - TableWriter(tbl).writeInto(buffer); - } + DatabaseWriter(specifiedDb).write(buffer); return buffer.toString(); } diff --git a/sally_generator/lib/src/utils/names.dart b/sally_generator/lib/src/utils/names.dart new file mode 100644 index 00000000..3dd7e7ad --- /dev/null +++ b/sally_generator/lib/src/utils/names.dart @@ -0,0 +1,16 @@ +String dataClassNameForClassName(String tableName) { + // This implementation is very primitive at the moment. The basic idea is + // that, very often, table names are formed from the plural of the entity + // they're storing (users, products, ...). We try to find the singular word + // from the table name. + + // todo we might want to implement some edge cases according to + // https://en.wikipedia.org/wiki/English_plurals + + if (tableName.endsWith('s')) { + return tableName.substring(0, tableName.length - 1); + } + + // Default behavior if the table name is not a valid plural. + return '${tableName}Data'; +} \ No newline at end of file diff --git a/sally_generator/lib/src/writer/database_writer.dart b/sally_generator/lib/src/writer/database_writer.dart new file mode 100644 index 00000000..2729f737 --- /dev/null +++ b/sally_generator/lib/src/writer/database_writer.dart @@ -0,0 +1,30 @@ +import 'package:recase/recase.dart'; +import 'package:sally_generator/src/model/specified_database.dart'; +import 'package:sally_generator/src/writer/table_writer.dart'; + +class DatabaseWriter { + + final SpecifiedDatabase db; + + DatabaseWriter(this.db); + + void write(StringBuffer buffer) { + for (final table in db.tables) { + TableWriter(table).writeInto(buffer); + } + + // Write the database class + final className = '_\$${db.fromClass.name}'; + buffer.write('abstract class $className extends GeneratedDatabase {\n' + '$className() : super(const SqlTypeSystem.withDefaults(), null); \n'); + + for (var table in db.tables) { + final tableFieldName = ReCase(table.fromClass.name).camelCase; + final tableClassName = table.tableInfoName; + + buffer.write('$tableClassName get $tableFieldName => $tableClassName(this);'); + } + + buffer.write('}'); + } +} \ No newline at end of file diff --git a/sally_generator/lib/src/writer/table_writer.dart b/sally_generator/lib/src/writer/table_writer.dart index 9d9dd9ec..b8ff173d 100644 --- a/sally_generator/lib/src/writer/table_writer.dart +++ b/sally_generator/lib/src/writer/table_writer.dart @@ -44,14 +44,14 @@ class TableWriter { // Generate the columns for (var column in table.columns) { - final isPrimaryKey = table.primaryKey.contains(column); // todo + final isNullable = false; // @override - // IntColumn get id => GeneratedIntColumn('sql_name', isPrimaryKey); + // IntColumn get id => GeneratedIntColumn('sql_name', isNullable); buffer ..write('@override \n') ..write('${column.dslColumnTypeName} get ${column.dartGetterName} => ' - '${column.implColumnTypeName}(\'${column.name.name}\', $isPrimaryKey);\n'); + '${column.implColumnTypeName}(\'${column.name.name}\', $isNullable);\n'); } // Generate $columns, $tableName, asDslTable getters