From 5de1656e07dfcc94cd518333ae6ef344a0221d4f Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Sun, 10 Mar 2019 20:04:32 +0100 Subject: [PATCH] Memoized getters for generated classes --- .travis.yml | 1 + moor/example/example.g.dart | 49 +++++++++++------ moor/lib/src/dsl/columns.dart | 1 + moor/lib/src/types/sql_types.dart | 4 +- moor/lib/src/types/type_system.dart | 8 ++- moor/test/data/tables/todos.g.dart | 53 +++++++++++++------ moor_generator/CHANGELOG.md | 1 + .../lib/src/writer/database_writer.dart | 27 +++++----- .../lib/src/writer/table_writer.dart | 25 +++++---- moor_generator/lib/src/writer/utils.dart | 21 ++++++++ 10 files changed, 131 insertions(+), 59 deletions(-) create mode 100644 moor_generator/lib/src/writer/utils.dart diff --git a/.travis.yml b/.travis.yml index d61cd759..bd37457b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ script: ./tool/mono_repo_wrapper.sh branches: only: - master + - develop cache: directories: diff --git a/moor/example/example.g.dart b/moor/example/example.g.dart index 0187ce77..08b9c3a4 100644 --- a/moor/example/example.g.dart +++ b/moor/example/example.g.dart @@ -43,11 +43,13 @@ class $CategoriesTable extends Categories implements TableInfo { final GeneratedDatabase _db; $CategoriesTable(this._db); + GeneratedIntColumn _id; @override GeneratedIntColumn get id => - GeneratedIntColumn('id', false, hasAutoIncrement: true); + _id ??= GeneratedIntColumn('id', false, hasAutoIncrement: true); + GeneratedTextColumn _description; @override - GeneratedTextColumn get description => GeneratedTextColumn( + GeneratedTextColumn get description => _description ??= GeneratedTextColumn( 'description', true, ); @@ -133,19 +135,23 @@ class Recipe { class $RecipesTable extends Recipes implements TableInfo { final GeneratedDatabase _db; $RecipesTable(this._db); + GeneratedIntColumn _id; @override GeneratedIntColumn get id => - GeneratedIntColumn('id', false, hasAutoIncrement: true); + _id ??= GeneratedIntColumn('id', false, hasAutoIncrement: true); + GeneratedTextColumn _title; @override GeneratedTextColumn get title => - GeneratedTextColumn('title', false, maxTextLength: 16); + _title ??= GeneratedTextColumn('title', false, maxTextLength: 16); + GeneratedTextColumn _instructions; @override - GeneratedTextColumn get instructions => GeneratedTextColumn( + GeneratedTextColumn get instructions => _instructions ??= GeneratedTextColumn( 'instructions', false, ); + GeneratedIntColumn _category; @override - GeneratedIntColumn get category => GeneratedIntColumn( + GeneratedIntColumn get category => _category ??= GeneratedIntColumn( 'category', true, ); @@ -232,16 +238,20 @@ class $IngredientsTable extends Ingredients implements TableInfo { final GeneratedDatabase _db; $IngredientsTable(this._db); + GeneratedIntColumn _id; @override GeneratedIntColumn get id => - GeneratedIntColumn('id', false, hasAutoIncrement: true); + _id ??= GeneratedIntColumn('id', false, hasAutoIncrement: true); + GeneratedTextColumn _name; @override - GeneratedTextColumn get name => GeneratedTextColumn( + GeneratedTextColumn get name => _name ??= GeneratedTextColumn( 'name', false, ); + GeneratedIntColumn _caloriesPer100g; @override - GeneratedIntColumn get caloriesPer100g => GeneratedIntColumn( + GeneratedIntColumn get caloriesPer100g => + _caloriesPer100g ??= GeneratedIntColumn( 'calories', false, ); @@ -327,18 +337,21 @@ class $IngredientInRecipesTable extends IngredientInRecipes implements TableInfo { final GeneratedDatabase _db; $IngredientInRecipesTable(this._db); + GeneratedIntColumn _recipe; @override - GeneratedIntColumn get recipe => GeneratedIntColumn( + GeneratedIntColumn get recipe => _recipe ??= GeneratedIntColumn( 'recipe', false, ); + GeneratedIntColumn _ingredient; @override - GeneratedIntColumn get ingredient => GeneratedIntColumn( + GeneratedIntColumn get ingredient => _ingredient ??= GeneratedIntColumn( 'ingredient', false, ); + GeneratedIntColumn _amountInGrams; @override - GeneratedIntColumn get amountInGrams => GeneratedIntColumn( + GeneratedIntColumn get amountInGrams => _amountInGrams ??= GeneratedIntColumn( 'amount', false, ); @@ -379,11 +392,15 @@ class $IngredientInRecipesTable extends IngredientInRecipes abstract class _$Database extends GeneratedDatabase { _$Database(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e); - $CategoriesTable get categories => $CategoriesTable(this); - $RecipesTable get recipes => $RecipesTable(this); - $IngredientsTable get ingredients => $IngredientsTable(this); + $CategoriesTable _categories; + $CategoriesTable get categories => _categories ??= $CategoriesTable(this); + $RecipesTable _recipes; + $RecipesTable get recipes => _recipes ??= $RecipesTable(this); + $IngredientsTable _ingredients; + $IngredientsTable get ingredients => _ingredients ??= $IngredientsTable(this); + $IngredientInRecipesTable _ingredientInRecipes; $IngredientInRecipesTable get ingredientInRecipes => - $IngredientInRecipesTable(this); + _ingredientInRecipes ??= $IngredientInRecipesTable(this); @override List get allTables => [categories, recipes, ingredients, ingredientInRecipes]; diff --git a/moor/lib/src/dsl/columns.dart b/moor/lib/src/dsl/columns.dart index f453fcc2..caad33f9 100644 --- a/moor/lib/src/dsl/columns.dart +++ b/moor/lib/src/dsl/columns.dart @@ -60,6 +60,7 @@ class IntColumnBuilder extends ColumnBuilder { } class BoolColumnBuilder extends ColumnBuilder {} + class BlobColumnBuilder extends ColumnBuilder {} class TextColumnBuilder extends ColumnBuilder { diff --git a/moor/lib/src/types/sql_types.dart b/moor/lib/src/types/sql_types.dart index 729a88ca..86027b86 100644 --- a/moor/lib/src/types/sql_types.dart +++ b/moor/lib/src/types/sql_types.dart @@ -98,7 +98,6 @@ class DateTimeType extends SqlType { } class BlobType extends SqlType { - const BlobType(); @override @@ -111,5 +110,4 @@ class BlobType extends SqlType { @override mapToSqlVariable(content) => content; - -} \ No newline at end of file +} diff --git a/moor/lib/src/types/type_system.dart b/moor/lib/src/types/type_system.dart index 1bc4ca17..be7d3704 100644 --- a/moor/lib/src/types/type_system.dart +++ b/moor/lib/src/types/type_system.dart @@ -8,7 +8,13 @@ class SqlTypeSystem { const SqlTypeSystem(this.types); const SqlTypeSystem.withDefaults() - : this(const [BoolType(), StringType(), IntType(), DateTimeType(), BlobType()]); + : this(const [ + BoolType(), + StringType(), + IntType(), + DateTimeType(), + BlobType() + ]); /// Returns the appropriate sql type for the dart type provided as the /// generic parameter. diff --git a/moor/test/data/tables/todos.g.dart b/moor/test/data/tables/todos.g.dart index 498b1fed..37df5a68 100644 --- a/moor/test/data/tables/todos.g.dart +++ b/moor/test/data/tables/todos.g.dart @@ -72,24 +72,30 @@ class $TodosTableTable extends TodosTable implements TableInfo { final GeneratedDatabase _db; $TodosTableTable(this._db); + GeneratedIntColumn _id; @override GeneratedIntColumn get id => - GeneratedIntColumn('id', false, hasAutoIncrement: true); + _id ??= GeneratedIntColumn('id', false, hasAutoIncrement: true); + GeneratedTextColumn _title; @override - GeneratedTextColumn get title => + GeneratedTextColumn get title => _title ??= GeneratedTextColumn('title', true, minTextLength: 4, maxTextLength: 16); + GeneratedTextColumn _content; @override - GeneratedTextColumn get content => GeneratedTextColumn( + GeneratedTextColumn get content => _content ??= GeneratedTextColumn( 'content', false, ); + GeneratedDateTimeColumn _targetDate; @override - GeneratedDateTimeColumn get targetDate => GeneratedDateTimeColumn( + GeneratedDateTimeColumn get targetDate => + _targetDate ??= GeneratedDateTimeColumn( 'target_date', true, ); + GeneratedIntColumn _category; @override - GeneratedIntColumn get category => GeneratedIntColumn( + GeneratedIntColumn get category => _category ??= GeneratedIntColumn( 'category', true, ); @@ -173,11 +179,13 @@ class $CategoriesTable extends Categories implements TableInfo { final GeneratedDatabase _db; $CategoriesTable(this._db); + GeneratedIntColumn _id; @override GeneratedIntColumn get id => - GeneratedIntColumn('id', false, hasAutoIncrement: true); + _id ??= GeneratedIntColumn('id', false, hasAutoIncrement: true); + GeneratedTextColumn _description; @override - GeneratedTextColumn get description => GeneratedTextColumn( + GeneratedTextColumn get description => _description ??= GeneratedTextColumn( '`desc`', false, ); @@ -266,19 +274,24 @@ class User { class $UsersTable extends Users implements TableInfo { final GeneratedDatabase _db; $UsersTable(this._db); + GeneratedIntColumn _id; @override GeneratedIntColumn get id => - GeneratedIntColumn('id', false, hasAutoIncrement: true); + _id ??= GeneratedIntColumn('id', false, hasAutoIncrement: true); + GeneratedTextColumn _name; @override - GeneratedTextColumn get name => + GeneratedTextColumn get name => _name ??= GeneratedTextColumn('name', false, minTextLength: 6, maxTextLength: 32); + GeneratedBoolColumn _isAwesome; @override - GeneratedBoolColumn get isAwesome => GeneratedBoolColumn( + GeneratedBoolColumn get isAwesome => _isAwesome ??= GeneratedBoolColumn( 'is_awesome', false, ); + GeneratedBlobColumn _profilePicture; @override - GeneratedBlobColumn get profilePicture => GeneratedBlobColumn( + GeneratedBlobColumn get profilePicture => + _profilePicture ??= GeneratedBlobColumn( 'profile_picture', false, ); @@ -356,13 +369,15 @@ class $SharedTodosTable extends SharedTodos implements TableInfo { final GeneratedDatabase _db; $SharedTodosTable(this._db); + GeneratedIntColumn _todo; @override - GeneratedIntColumn get todo => GeneratedIntColumn( + GeneratedIntColumn get todo => _todo ??= GeneratedIntColumn( 'todo', false, ); + GeneratedIntColumn _user; @override - GeneratedIntColumn get user => GeneratedIntColumn( + GeneratedIntColumn get user => _user ??= GeneratedIntColumn( 'user', false, ); @@ -398,10 +413,14 @@ class $SharedTodosTable extends SharedTodos abstract class _$TodoDb extends GeneratedDatabase { _$TodoDb(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e); - $TodosTableTable get todosTable => $TodosTableTable(this); - $CategoriesTable get categories => $CategoriesTable(this); - $UsersTable get users => $UsersTable(this); - $SharedTodosTable get sharedTodos => $SharedTodosTable(this); + $TodosTableTable _todosTable; + $TodosTableTable get todosTable => _todosTable ??= $TodosTableTable(this); + $CategoriesTable _categories; + $CategoriesTable get categories => _categories ??= $CategoriesTable(this); + $UsersTable _users; + $UsersTable get users => _users ??= $UsersTable(this); + $SharedTodosTable _sharedTodos; + $SharedTodosTable get sharedTodos => _sharedTodos ??= $SharedTodosTable(this); @override List get allTables => [todosTable, categories, users, sharedTodos]; } diff --git a/moor_generator/CHANGELOG.md b/moor_generator/CHANGELOG.md index c8056dd0..6f4c2269 100644 --- a/moor_generator/CHANGELOG.md +++ b/moor_generator/CHANGELOG.md @@ -1,5 +1,6 @@ ## 1.2.0 - Blob data type +- Generated classes now use lazy getters instead of recalculating fields on each access ## 1.1.0 - The generated data classes now implement `toString()` diff --git a/moor_generator/lib/src/writer/database_writer.dart b/moor_generator/lib/src/writer/database_writer.dart index 5983f5d9..f786c724 100644 --- a/moor_generator/lib/src/writer/database_writer.dart +++ b/moor_generator/lib/src/writer/database_writer.dart @@ -1,6 +1,7 @@ import 'package:recase/recase.dart'; import 'package:moor_generator/src/model/specified_database.dart'; import 'package:moor_generator/src/writer/table_writer.dart'; +import 'utils.dart'; class DatabaseWriter { final SpecifiedDatabase db; @@ -25,26 +26,26 @@ class DatabaseWriter { tableGetters.add(tableFieldName); final tableClassName = table.tableInfoName; - buffer.write( - '$tableClassName get $tableFieldName => $tableClassName(this);'); + writeMemoizedGetter( + buffer: buffer, + getterName: tableFieldName, + returnType: tableClassName, + code: '$tableClassName(this)', + ); } - // Write fields to access an dao. We use a lazy getter: - /* - DaoType _daoName; - DaoType get daoName => _daoName ??= DaoType(this); - */ + // Write fields to access an dao. We use a lazy getter for that. for (var dao in db.daos) { final typeName = dao.displayName; final getterName = ReCase(typeName).camelCase; - final fieldName = '_$getterName'; - final databaseImplName = db.fromClass.name; - buffer - ..write('$typeName $fieldName;\n') - ..write('$typeName get $getterName => $fieldName ??= ' - '$typeName(this as $databaseImplName);'); + writeMemoizedGetter( + buffer: buffer, + getterName: getterName, + returnType: typeName, + code: '$typeName(this as $databaseImplName)', + ); } // Write List of tables, close bracket for class diff --git a/moor_generator/lib/src/writer/table_writer.dart b/moor_generator/lib/src/writer/table_writer.dart index 2c78490d..46904c4b 100644 --- a/moor_generator/lib/src/writer/table_writer.dart +++ b/moor_generator/lib/src/writer/table_writer.dart @@ -1,6 +1,7 @@ import 'package:moor_generator/src/model/specified_column.dart'; import 'package:moor_generator/src/model/specified_table.dart'; import 'package:moor_generator/src/writer/data_class_writer.dart'; +import 'package:moor_generator/src/writer/utils.dart'; class TableWriter { final SpecifiedTable table; @@ -97,25 +98,31 @@ class TableWriter { } } - // @override - // GeneratedIntColumn get id => GeneratedIntColumn('sql_name', isNullable); - buffer - ..write('@override \n') - ..write('${column.implColumnTypeName} get ${column.dartGetterName} => ' - '${column.implColumnTypeName}(\'${column.name.name}\', $isNullable, '); + // GeneratedIntColumn('sql_name', isNullable, additionalField: true) + final expressionBuffer = StringBuffer() + ..write(column.implColumnTypeName) + ..write('(\'${column.name.name}\', $isNullable, '); var first = true; additionalParams.forEach((name, value) { if (!first) { - buffer.write(', '); + expressionBuffer.write(', '); } else { first = false; } - buffer..write(name)..write(': ')..write(value); + expressionBuffer..write(name)..write(': ')..write(value); }); - buffer.write(');\n'); + expressionBuffer.write(')'); + + writeMemoizedGetter( + buffer: buffer, + getterName: column.dartGetterName, + returnType: column.implColumnTypeName, + code: expressionBuffer.toString(), + hasOverride: true, + ); } void _writeValidityCheckMethod(StringBuffer buffer) { diff --git a/moor_generator/lib/src/writer/utils.dart b/moor_generator/lib/src/writer/utils.dart new file mode 100644 index 00000000..0e3849e5 --- /dev/null +++ b/moor_generator/lib/src/writer/utils.dart @@ -0,0 +1,21 @@ +import 'package:meta/meta.dart'; + +/// Writes the following dart code into the [buffer]: +/// ``` +/// ReturnType _getterName; +/// ReturnType get getterName => _getterName ??= code; +/// ``` +/// This means that [code] should be an expression without any trailing +/// semicolon. +void writeMemoizedGetter( + {@required StringBuffer buffer, + @required String getterName, + @required String returnType, + @required String code, + bool hasOverride}) { + buffer.write('$returnType _$getterName;\n'); + if (hasOverride == true) { + buffer.write('@override\n'); + } + buffer.write('$returnType get $getterName => _$getterName ??= $code;'); +}