diff --git a/moor/example/example.g.dart b/moor/example/example.g.dart index 47da5f36..336d8d8b 100644 --- a/moor/example/example.g.dart +++ b/moor/example/example.g.dart @@ -7,7 +7,7 @@ part of 'example.dart'; // ************************************************************************** // ignore_for_file: unnecessary_brace_in_string_interps -class Category extends DataClass { +class Category extends DataClass implements Insertable { final int id; final String description; Category({this.id, this.description}); @@ -39,13 +39,13 @@ class Category extends DataClass { } @override - CategoriesCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return CategoriesCompanion( id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), description: description == null && nullToAbsent ? const Value.absent() : Value.use(description), - ); + ) as T; } Category copyWith({int id, String description}) => Category( @@ -69,7 +69,7 @@ class Category extends DataClass { (other is Category && other.id == id && other.description == description); } -class CategoriesCompanion implements UpdateCompanion { +class CategoriesCompanion extends UpdateCompanion { final Value id; final Value description; const CategoriesCompanion({ @@ -147,13 +147,13 @@ class $CategoriesTable extends Categories } @override - Map entityToSql(Category d, {bool includeNulls = false}) { + Map entityToSql(CategoriesCompanion d) { final map = {}; - if (d.id != null || includeNulls) { - map['id'] = Variable(d.id); + if (d.id.present) { + map['id'] = Variable(d.id.value); } - if (d.description != null || includeNulls) { - map['description'] = Variable(d.description); + if (d.description.present) { + map['description'] = Variable(d.description.value); } return map; } @@ -164,7 +164,7 @@ class $CategoriesTable extends Categories } } -class Recipe extends DataClass { +class Recipe extends DataClass implements Insertable { final int id; final String title; final String instructions; @@ -206,7 +206,7 @@ class Recipe extends DataClass { } @override - RecipesCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return RecipesCompanion( id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), title: title == null && nullToAbsent @@ -218,7 +218,7 @@ class Recipe extends DataClass { category: category == null && nullToAbsent ? const Value.absent() : Value.use(category), - ); + ) as T; } Recipe copyWith({int id, String title, String instructions, int category}) => @@ -254,7 +254,7 @@ class Recipe extends DataClass { other.category == category); } -class RecipesCompanion implements UpdateCompanion { +class RecipesCompanion extends UpdateCompanion { final Value id; final Value title; final Value instructions; @@ -369,19 +369,19 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> { } @override - Map entityToSql(Recipe d, {bool includeNulls = false}) { + Map entityToSql(RecipesCompanion d) { final map = {}; - if (d.id != null || includeNulls) { - map['id'] = Variable(d.id); + if (d.id.present) { + map['id'] = Variable(d.id.value); } - if (d.title != null || includeNulls) { - map['title'] = Variable(d.title); + if (d.title.present) { + map['title'] = Variable(d.title.value); } - if (d.instructions != null || includeNulls) { - map['instructions'] = Variable(d.instructions); + if (d.instructions.present) { + map['instructions'] = Variable(d.instructions.value); } - if (d.category != null || includeNulls) { - map['category'] = Variable(d.category); + if (d.category.present) { + map['category'] = Variable(d.category.value); } return map; } @@ -392,7 +392,7 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> { } } -class Ingredient extends DataClass { +class Ingredient extends DataClass implements Insertable { final int id; final String name; final int caloriesPer100g; @@ -428,7 +428,7 @@ class Ingredient extends DataClass { } @override - IngredientsCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return IngredientsCompanion( id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), name: @@ -436,7 +436,7 @@ class Ingredient extends DataClass { caloriesPer100g: caloriesPer100g == null && nullToAbsent ? const Value.absent() : Value.use(caloriesPer100g), - ); + ) as T; } Ingredient copyWith({int id, String name, int caloriesPer100g}) => Ingredient( @@ -466,7 +466,7 @@ class Ingredient extends DataClass { other.caloriesPer100g == caloriesPer100g); } -class IngredientsCompanion implements UpdateCompanion { +class IngredientsCompanion extends UpdateCompanion { final Value id; final Value name; final Value caloriesPer100g; @@ -566,16 +566,16 @@ class $IngredientsTable extends Ingredients } @override - Map entityToSql(Ingredient d, {bool includeNulls = false}) { + Map entityToSql(IngredientsCompanion d) { final map = {}; - if (d.id != null || includeNulls) { - map['id'] = Variable(d.id); + if (d.id.present) { + map['id'] = Variable(d.id.value); } - if (d.name != null || includeNulls) { - map['name'] = Variable(d.name); + if (d.name.present) { + map['name'] = Variable(d.name.value); } - if (d.caloriesPer100g != null || includeNulls) { - map['calories'] = Variable(d.caloriesPer100g); + if (d.caloriesPer100g.present) { + map['calories'] = Variable(d.caloriesPer100g.value); } return map; } @@ -586,7 +586,8 @@ class $IngredientsTable extends Ingredients } } -class IngredientInRecipe extends DataClass { +class IngredientInRecipe extends DataClass + implements Insertable { final int recipe; final int ingredient; final int amountInGrams; @@ -623,7 +624,8 @@ class IngredientInRecipe extends DataClass { } @override - IngredientInRecipesCompanion createCompanion(bool nullToAbsent) { + T createCompanion>( + bool nullToAbsent) { return IngredientInRecipesCompanion( recipe: recipe == null && nullToAbsent ? const Value.absent() @@ -634,7 +636,7 @@ class IngredientInRecipe extends DataClass { amountInGrams: amountInGrams == null && nullToAbsent ? const Value.absent() : Value.use(amountInGrams), - ); + ) as T; } IngredientInRecipe copyWith( @@ -667,8 +669,7 @@ class IngredientInRecipe extends DataClass { other.amountInGrams == amountInGrams); } -class IngredientInRecipesCompanion - implements UpdateCompanion { +class IngredientInRecipesCompanion extends UpdateCompanion { final Value recipe; final Value ingredient; final Value amountInGrams; @@ -773,17 +774,16 @@ class $IngredientInRecipesTable extends IngredientInRecipes } @override - Map entityToSql(IngredientInRecipe d, - {bool includeNulls = false}) { + Map entityToSql(IngredientInRecipesCompanion d) { final map = {}; - if (d.recipe != null || includeNulls) { - map['recipe'] = Variable(d.recipe); + if (d.recipe.present) { + map['recipe'] = Variable(d.recipe.value); } - if (d.ingredient != null || includeNulls) { - map['ingredient'] = Variable(d.ingredient); + if (d.ingredient.present) { + map['ingredient'] = Variable(d.ingredient.value); } - if (d.amountInGrams != null || includeNulls) { - map['amount'] = Variable(d.amountInGrams); + if (d.amountInGrams.present) { + map['amount'] = Variable(d.amountInGrams.value); } return map; } diff --git a/moor/lib/src/runtime/data_class.dart b/moor/lib/src/runtime/data_class.dart index 7f4c7976..884732e0 100644 --- a/moor/lib/src/runtime/data_class.dart +++ b/moor/lib/src/runtime/data_class.dart @@ -3,6 +3,14 @@ import 'dart:convert'; import 'package:meta/meta.dart'; import 'package:moor/moor.dart'; +/// Common interface for objects which can be inserted or updated into a +/// database. +@optionalTypeArgs +abstract class Insertable { + /// Used internally by moor. + T createCompanion>(bool nullToAbsent); +} + /// A common supertype for all data classes generated by moor. Data classes are /// immutable structures that represent a single row in a database table. abstract class DataClass { @@ -26,9 +34,6 @@ abstract class DataClass { static dynamic parseJson(String jsonString) { return json.decode(jsonString); } - - /// Used internally by moor. - UpdateCompanion createCompanion(bool nullToAbsent); } /// An update companion for a [DataClass] which is used to write data into a @@ -36,7 +41,9 @@ abstract class DataClass { /// /// See also: /// - https://github.com/simolus3/moor/issues/25 -abstract class UpdateCompanion { +abstract class UpdateCompanion implements Insertable { + const UpdateCompanion(); + /// Used internally by moor. /// /// Returns true if the column at the position [index] has been explicitly @@ -44,6 +51,11 @@ abstract class UpdateCompanion { // todo this doesn't need to exist anymore, remove before release and adapt // moor_generator bool isValuePresent(int index); + + @override + T createCompanion(bool nullToAbsent) { + return this as T; + } } /// A wrapper around arbitrary data [T] to indicate presence or absence diff --git a/moor/lib/src/runtime/statements/delete.dart b/moor/lib/src/runtime/statements/delete.dart index 19e1e7ef..f37d67e5 100644 --- a/moor/lib/src/runtime/statements/delete.dart +++ b/moor/lib/src/runtime/statements/delete.dart @@ -17,7 +17,7 @@ class DeleteStatement extends Query } /// Deletes just this entity. May not be used together with [where]. - Future delete(D entity) { + Future delete(Insertable entity) { assert( whereExpr == null, 'When deleting an entity, you may not use where(...)' diff --git a/moor/lib/src/runtime/statements/insert.dart b/moor/lib/src/runtime/statements/insert.dart index 793c26de..e8dbddda 100644 --- a/moor/lib/src/runtime/statements/insert.dart +++ b/moor/lib/src/runtime/statements/insert.dart @@ -26,7 +26,7 @@ class InsertStatement { /// /// If the table contains an auto-increment column, the generated value will /// be returned. - Future insert(D entity, {bool orReplace = false}) async { + Future insert(Insertable entity, {bool orReplace = false}) async { _validateIntegrity(entity); final ctx = _createContext(entity, orReplace); @@ -45,7 +45,8 @@ class InsertStatement { /// When a row with the same primary or unique key already exists in the /// database, the insert will fail. Use [orReplace] to replace rows that /// already exist. - Future insertAll(List rows, {bool orReplace = false}) async { + Future insertAll(List> rows, + {bool orReplace = false}) async { final statements = >{}; // Not every insert has the same sql, as fields which are set to null are @@ -78,12 +79,12 @@ class InsertStatement { /// /// However, if no such row exists, a new row will be written instead. @Deprecated('Use insert with orReplace: true instead') - Future insertOrReplace(D entity) async { + Future insertOrReplace(Insertable entity) async { return await insert(entity, orReplace: true); } - GenerationContext _createContext(D entry, bool replace) { - final map = table.entityToSql(entry) + GenerationContext _createContext(Insertable entry, bool replace) { + final map = table.entityToSql(entry.createCompanion(true)) ..removeWhere((_, value) => value == null); final ctx = GenerationContext.fromDb(database); @@ -111,13 +112,12 @@ class InsertStatement { return ctx; } - void _validateIntegrity(D d) { + void _validateIntegrity(Insertable d) { if (d == null) { throw InvalidDataException( 'Cannot writee null row into ${table.$tableName}'); } - // todo needs to use d as update companion here - table.validateIntegrity(null).throwIfInvalid(d); + table.validateIntegrity(d.createCompanion(true)).throwIfInvalid(d); } } diff --git a/moor/lib/src/runtime/statements/query.dart b/moor/lib/src/runtime/statements/query.dart index 0642d4b7..925633ff 100644 --- a/moor/lib/src/runtime/statements/query.dart +++ b/moor/lib/src/runtime/statements/query.dart @@ -120,7 +120,7 @@ mixin SingleTableQueryMixin /// Applies a [where] statement so that the row with the same primary key as /// [d] will be matched. - void whereSamePrimaryKey(D d) { + void whereSamePrimaryKey(Insertable d) { assert( table.$primaryKey != null && table.$primaryKey.isNotEmpty, 'When using Query.whereSamePrimaryKey, which is also called from ' @@ -136,7 +136,7 @@ mixin SingleTableQueryMixin final primaryKeys = table.$primaryKey.map((c) => c.$name); - final updatedFields = table.entityToSql(d, includeNulls: true); + final updatedFields = table.entityToSql(d.createCompanion(false)); // Extract values of the primary key as they are needed for the where clause final primaryKeyValues = Map.fromEntries(updatedFields.entries .where((entry) => primaryKeys.contains(entry.key))); diff --git a/moor/lib/src/runtime/statements/update.dart b/moor/lib/src/runtime/statements/update.dart index ffebf671..b085e498 100644 --- a/moor/lib/src/runtime/statements/update.dart +++ b/moor/lib/src/runtime/statements/update.dart @@ -55,11 +55,11 @@ class UpdateStatement extends Query /// /// See also: [replace], which does not require [where] statements and /// supports setting fields back to null. - Future write(D entity) async { + Future write(Insertable entity) async { // todo needs to use entity as update companion here table.validateIntegrity(null).throwIfInvalid(entity); - _updatedFields = table.entityToSql(entity) + _updatedFields = table.entityToSql(entity.createCompanion(true)) ..remove((_, value) => value == null); if (_updatedFields.isEmpty) { @@ -86,13 +86,11 @@ class UpdateStatement extends Query /// null values in the entity. /// - [InsertStatement.insert] with the `orReplace` parameter, which behaves /// similar to this method but creates a new row if none exists. - Future replace(D entity) async { - // We set isInserting to true here although we're in an update. This is - // because all the fields from the entity will be written (as opposed to a - // regular update, where only non-null fields will be written). If isInserted - // was false, the null fields would not be validated. - // todo needs to use entity as update companion here - table.validateIntegrity(null).throwIfInvalid(entity); + Future replace(Insertable entity) async { + // We don't turn nulls to absent values here (as opposed to a regular + // update, where only non-null fields will be written). + final companion = entity.createCompanion(false); + table.validateIntegrity(companion).throwIfInvalid(entity); assert( whereExpr == null, 'When using replace on an update statement, you may not use where(...)' @@ -100,7 +98,7 @@ class UpdateStatement extends Query whereSamePrimaryKey(entity); - _updatedFields = table.entityToSql(entity, includeNulls: true); + _updatedFields = table.entityToSql(companion); final primaryKeys = table.$primaryKey.map((c) => c.$name); // Don't update the primary key diff --git a/moor/lib/src/runtime/structure/table_info.dart b/moor/lib/src/runtime/structure/table_info.dart index 6494c21f..c916ac32 100644 --- a/moor/lib/src/runtime/structure/table_info.dart +++ b/moor/lib/src/runtime/structure/table_info.dart @@ -38,15 +38,11 @@ mixin TableInfo { /// that it respects all constraints (nullability, text length, etc.). VerificationContext validateIntegrity(covariant UpdateCompanion instance); - /// Maps the given data class to a [Map] that can be inserted into sql. The - /// keys should represent the column name in sql, the values the corresponding - /// values of the field. - /// - /// If [includeNulls] is true, fields of the [D] that are null will be - /// written as a [Variable] with a value of null. Otherwise, these fields will - /// not be written into the map at all. - // todo migrate to update companions - Map entityToSql(D instance, {bool includeNulls = false}); + /// Maps the given update companion to a [Map] that can be inserted into sql. + /// The keys should represent the column name in sql, the values the + /// corresponding values of the field. All fields of the [instance] which are + /// present will be written, absent fields will be omitted. + Map entityToSql(covariant UpdateCompanion instance); /// Maps the given row returned by the database into the fitting data class. D map(Map data, {String tablePrefix}); diff --git a/moor/test/data/tables/todos.g.dart b/moor/test/data/tables/todos.g.dart index 101601a1..de2368e1 100644 --- a/moor/test/data/tables/todos.g.dart +++ b/moor/test/data/tables/todos.g.dart @@ -7,7 +7,7 @@ part of 'todos.dart'; // ************************************************************************** // ignore_for_file: unnecessary_brace_in_string_interps -class TodoEntry extends DataClass { +class TodoEntry extends DataClass implements Insertable { final int id; final String title; final String content; @@ -56,7 +56,7 @@ class TodoEntry extends DataClass { } @override - TodosTableCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return TodosTableCompanion( id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), title: title == null && nullToAbsent @@ -71,7 +71,7 @@ class TodoEntry extends DataClass { category: category == null && nullToAbsent ? const Value.absent() : Value.use(category), - ); + ) as T; } TodoEntry copyWith( @@ -116,7 +116,7 @@ class TodoEntry extends DataClass { other.category == category); } -class TodosTableCompanion implements UpdateCompanion { +class TodosTableCompanion extends UpdateCompanion { final Value id; final Value title; final Value content; @@ -251,22 +251,22 @@ class $TodosTableTable extends TodosTable } @override - Map entityToSql(TodoEntry d, {bool includeNulls = false}) { + Map entityToSql(TodosTableCompanion d) { final map = {}; - if (d.id != null || includeNulls) { - map['id'] = Variable(d.id); + if (d.id.present) { + map['id'] = Variable(d.id.value); } - if (d.title != null || includeNulls) { - map['title'] = Variable(d.title); + if (d.title.present) { + map['title'] = Variable(d.title.value); } - if (d.content != null || includeNulls) { - map['content'] = Variable(d.content); + if (d.content.present) { + map['content'] = Variable(d.content.value); } - if (d.targetDate != null || includeNulls) { - map['target_date'] = Variable(d.targetDate); + if (d.targetDate.present) { + map['target_date'] = Variable(d.targetDate.value); } - if (d.category != null || includeNulls) { - map['category'] = Variable(d.category); + if (d.category.present) { + map['category'] = Variable(d.category.value); } return map; } @@ -277,7 +277,7 @@ class $TodosTableTable extends TodosTable } } -class Category extends DataClass { +class Category extends DataClass implements Insertable { final int id; final String description; Category({this.id, this.description}); @@ -309,13 +309,13 @@ class Category extends DataClass { } @override - CategoriesCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return CategoriesCompanion( id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), description: description == null && nullToAbsent ? const Value.absent() : Value.use(description), - ); + ) as T; } Category copyWith({int id, String description}) => Category( @@ -339,7 +339,7 @@ class Category extends DataClass { (other is Category && other.id == id && other.description == description); } -class CategoriesCompanion implements UpdateCompanion { +class CategoriesCompanion extends UpdateCompanion { final Value id; final Value description; const CategoriesCompanion({ @@ -414,13 +414,13 @@ class $CategoriesTable extends Categories } @override - Map entityToSql(Category d, {bool includeNulls = false}) { + Map entityToSql(CategoriesCompanion d) { final map = {}; - if (d.id != null || includeNulls) { - map['id'] = Variable(d.id); + if (d.id.present) { + map['id'] = Variable(d.id.value); } - if (d.description != null || includeNulls) { - map['desc'] = Variable(d.description); + if (d.description.present) { + map['desc'] = Variable(d.description.value); } return map; } @@ -431,7 +431,7 @@ class $CategoriesTable extends Categories } } -class User extends DataClass { +class User extends DataClass implements Insertable { final int id; final String name; final bool isAwesome; @@ -485,7 +485,7 @@ class User extends DataClass { } @override - UsersCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return UsersCompanion( id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), name: @@ -499,7 +499,7 @@ class User extends DataClass { creationTime: creationTime == null && nullToAbsent ? const Value.absent() : Value.use(creationTime), - ); + ) as T; } User copyWith( @@ -545,7 +545,7 @@ class User extends DataClass { other.creationTime == creationTime); } -class UsersCompanion implements UpdateCompanion { +class UsersCompanion extends UpdateCompanion { final Value id; final Value name; final Value isAwesome; @@ -680,22 +680,24 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> { } @override - Map entityToSql(User d, {bool includeNulls = false}) { + Map entityToSql(UsersCompanion d) { final map = {}; - if (d.id != null || includeNulls) { - map['id'] = Variable(d.id); + if (d.id.present) { + map['id'] = Variable(d.id.value); } - if (d.name != null || includeNulls) { - map['name'] = Variable(d.name); + if (d.name.present) { + map['name'] = Variable(d.name.value); } - if (d.isAwesome != null || includeNulls) { - map['is_awesome'] = Variable(d.isAwesome); + if (d.isAwesome.present) { + map['is_awesome'] = Variable(d.isAwesome.value); } - if (d.profilePicture != null || includeNulls) { - map['profile_picture'] = Variable(d.profilePicture); + if (d.profilePicture.present) { + map['profile_picture'] = + Variable(d.profilePicture.value); } - if (d.creationTime != null || includeNulls) { - map['creation_time'] = Variable(d.creationTime); + if (d.creationTime.present) { + map['creation_time'] = + Variable(d.creationTime.value); } return map; } @@ -706,7 +708,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> { } } -class SharedTodo extends DataClass { +class SharedTodo extends DataClass implements Insertable { final int todo; final int user; SharedTodo({this.todo, this.user}); @@ -736,13 +738,13 @@ class SharedTodo extends DataClass { } @override - SharedTodosCompanion createCompanion(bool nullToAbsent) { + T createCompanion>(bool nullToAbsent) { return SharedTodosCompanion( todo: todo == null && nullToAbsent ? const Value.absent() : Value.use(todo), user: user == null && nullToAbsent ? const Value.absent() : Value.use(user), - ); + ) as T; } SharedTodo copyWith({int todo, int user}) => SharedTodo( @@ -766,7 +768,7 @@ class SharedTodo extends DataClass { (other is SharedTodo && other.todo == todo && other.user == user); } -class SharedTodosCompanion implements UpdateCompanion { +class SharedTodosCompanion extends UpdateCompanion { final Value todo; final Value user; const SharedTodosCompanion({ @@ -847,13 +849,13 @@ class $SharedTodosTable extends SharedTodos } @override - Map entityToSql(SharedTodo d, {bool includeNulls = false}) { + Map entityToSql(SharedTodosCompanion d) { final map = {}; - if (d.todo != null || includeNulls) { - map['todo'] = Variable(d.todo); + if (d.todo.present) { + map['todo'] = Variable(d.todo.value); } - if (d.user != null || includeNulls) { - map['user'] = Variable(d.user); + if (d.user.present) { + map['user'] = Variable(d.user.value); } return map; } @@ -864,7 +866,8 @@ class $SharedTodosTable extends SharedTodos } } -class TableWithoutPKData extends DataClass { +class TableWithoutPKData extends DataClass + implements Insertable { final int notReallyAnId; final double someFloat; TableWithoutPKData({this.notReallyAnId, this.someFloat}); @@ -898,7 +901,8 @@ class TableWithoutPKData extends DataClass { } @override - TableWithoutPKCompanion createCompanion(bool nullToAbsent) { + T createCompanion>( + bool nullToAbsent) { return TableWithoutPKCompanion( notReallyAnId: notReallyAnId == null && nullToAbsent ? const Value.absent() @@ -906,7 +910,7 @@ class TableWithoutPKData extends DataClass { someFloat: someFloat == null && nullToAbsent ? const Value.absent() : Value.use(someFloat), - ); + ) as T; } TableWithoutPKData copyWith({int notReallyAnId, double someFloat}) => @@ -934,7 +938,7 @@ class TableWithoutPKData extends DataClass { other.someFloat == someFloat); } -class TableWithoutPKCompanion implements UpdateCompanion { +class TableWithoutPKCompanion extends UpdateCompanion { final Value notReallyAnId; final Value someFloat; const TableWithoutPKCompanion({ @@ -1019,14 +1023,13 @@ class $TableWithoutPKTable extends TableWithoutPK } @override - Map entityToSql(TableWithoutPKData d, - {bool includeNulls = false}) { + Map entityToSql(TableWithoutPKCompanion d) { final map = {}; - if (d.notReallyAnId != null || includeNulls) { - map['not_really_an_id'] = Variable(d.notReallyAnId); + if (d.notReallyAnId.present) { + map['not_really_an_id'] = Variable(d.notReallyAnId.value); } - if (d.someFloat != null || includeNulls) { - map['some_float'] = Variable(d.someFloat); + if (d.someFloat.present) { + map['some_float'] = Variable(d.someFloat.value); } return map; } diff --git a/moor_flutter/example/lib/database/database.g.dart b/moor_flutter/example/lib/database/database.g.dart index 699185bb..94076fe4 100644 --- a/moor_flutter/example/lib/database/database.g.dart +++ b/moor_flutter/example/lib/database/database.g.dart @@ -7,7 +7,7 @@ part of 'database.dart'; // ************************************************************************** // ignore_for_file: unnecessary_brace_in_string_interps -class TodoEntry extends DataClass { +class TodoEntry extends DataClass implements Insertable { final int id; final String content; final DateTime targetDate; @@ -49,6 +49,22 @@ class TodoEntry extends DataClass { }; } + @override + T createCompanion>(bool nullToAbsent) { + return TodosCompanion( + id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), + content: content == null && nullToAbsent + ? const Value.absent() + : Value.use(content), + targetDate: targetDate == null && nullToAbsent + ? const Value.absent() + : Value.use(targetDate), + category: category == null && nullToAbsent + ? const Value.absent() + : Value.use(category), + ) as T; + } + TodoEntry copyWith( {int id, String content, DateTime targetDate, int category}) => TodoEntry( @@ -83,6 +99,35 @@ class TodoEntry extends DataClass { other.category == category); } +class TodosCompanion extends UpdateCompanion { + final Value id; + final Value content; + final Value targetDate; + final Value category; + const TodosCompanion({ + this.id = const Value.absent(), + this.content = const Value.absent(), + this.targetDate = const Value.absent(), + this.category = const Value.absent(), + }); + @override + bool isValuePresent(int index) { + switch (index) { + case 0: + return id.present; + case 1: + return content.present; + case 2: + return targetDate.present; + case 3: + return category.present; + default: + throw ArgumentError( + 'Hit an invalid state while serializing data. Did you run the build step?'); + } + } +} + class $TodosTable extends Todos with TableInfo<$TodosTable, TodoEntry> { final GeneratedDatabase _db; final String _alias; @@ -138,22 +183,26 @@ class $TodosTable extends Todos with TableInfo<$TodosTable, TodoEntry> { @override final String actualTableName = 'todos'; @override - VerificationContext validateIntegrity(TodoEntry instance, bool isInserting) => - VerificationContext() - ..handle( - _idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta)) - ..handle( - _contentMeta, - content.isAcceptableValue( - instance.content, isInserting, _contentMeta)) - ..handle( - _targetDateMeta, - targetDate.isAcceptableValue( - instance.targetDate, isInserting, _targetDateMeta)) - ..handle( - _categoryMeta, - category.isAcceptableValue( - instance.category, isInserting, _categoryMeta)); + VerificationContext validateIntegrity(TodosCompanion d) { + final context = VerificationContext(); + if (d.isValuePresent(0)) { + context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta)); + } + if (d.isValuePresent(1)) { + context.handle(_contentMeta, + content.isAcceptableValue(d.content.value, _contentMeta)); + } + if (d.isValuePresent(2)) { + context.handle(_targetDateMeta, + targetDate.isAcceptableValue(d.targetDate.value, _targetDateMeta)); + } + if (d.isValuePresent(3)) { + context.handle(_categoryMeta, + category.isAcceptableValue(d.category.value, _categoryMeta)); + } + return context; + } + @override Set get $primaryKey => {id}; @override @@ -186,7 +235,7 @@ class $TodosTable extends Todos with TableInfo<$TodosTable, TodoEntry> { } } -class Category extends DataClass { +class Category extends DataClass implements Insertable { final int id; final String description; Category({this.id, this.description}); @@ -217,6 +266,16 @@ class Category extends DataClass { }; } + @override + T createCompanion>(bool nullToAbsent) { + return CategoriesCompanion( + id: id == null && nullToAbsent ? const Value.absent() : Value.use(id), + description: description == null && nullToAbsent + ? const Value.absent() + : Value.use(description), + ) as T; + } + Category copyWith({int id, String description}) => Category( id: id ?? this.id, description: description ?? this.description, @@ -238,6 +297,27 @@ class Category extends DataClass { (other is Category && other.id == id && other.description == description); } +class CategoriesCompanion extends UpdateCompanion { + final Value id; + final Value description; + const CategoriesCompanion({ + this.id = const Value.absent(), + this.description = const Value.absent(), + }); + @override + bool isValuePresent(int index) { + switch (index) { + case 0: + return id.present; + case 1: + return description.present; + default: + throw ArgumentError( + 'Hit an invalid state while serializing data. Did you run the build step?'); + } + } +} + class $CategoriesTable extends Categories with TableInfo<$CategoriesTable, Category> { final GeneratedDatabase _db; @@ -274,14 +354,18 @@ class $CategoriesTable extends Categories @override final String actualTableName = 'categories'; @override - VerificationContext validateIntegrity(Category instance, bool isInserting) => - VerificationContext() - ..handle( - _idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta)) - ..handle( - _descriptionMeta, - description.isAcceptableValue( - instance.description, isInserting, _descriptionMeta)); + VerificationContext validateIntegrity(CategoriesCompanion d) { + final context = VerificationContext(); + if (d.isValuePresent(0)) { + context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta)); + } + if (d.isValuePresent(1)) { + context.handle(_descriptionMeta, + description.isAcceptableValue(d.description.value, _descriptionMeta)); + } + return context; + } + @override Set get $primaryKey => {id}; @override diff --git a/moor_generator/lib/src/writer/data_class_writer.dart b/moor_generator/lib/src/writer/data_class_writer.dart index 05118312..c5a86dff 100644 --- a/moor_generator/lib/src/writer/data_class_writer.dart +++ b/moor_generator/lib/src/writer/data_class_writer.dart @@ -12,7 +12,8 @@ class DataClassWriter { DataClassWriter(this.table, this.options); void writeInto(StringBuffer buffer) { - buffer.write('class ${table.dartTypeName} extends DataClass {\n'); + buffer.write( + 'class ${table.dartTypeName} extends DataClass implements Insertable<${table.dartTypeName}> {\n'); // write individual fields for (var column in table.columns) { @@ -218,18 +219,19 @@ class DataClassWriter { } void _writeCompanionOverride(StringBuffer buffer) { - // UpdateCompanion createCompanion(bool nullToAbsent); + // T createCompanion(bool nullToAbsent) + final companionClass = table.updateCompanionName; - buffer.write('@override\n$companionClass ' - 'createCompanion(bool nullToAbsent) {\n' - 'return $companionClass('); + buffer.write('@override\nT createCompanion>(' + 'bool nullToAbsent) {\n return $companionClass('); for (var column in table.columns) { final getter = column.dartGetterName; buffer.write('$getter: $getter == null && nullToAbsent ? ' 'const Value.absent() : Value.use($getter),'); } - buffer.write(');}\n'); + buffer.write(') as T;}\n'); } /// Recursively creates the implementation for hashCode of the data class, diff --git a/moor_generator/lib/src/writer/table_writer.dart b/moor_generator/lib/src/writer/table_writer.dart index e042c87c..787318d7 100644 --- a/moor_generator/lib/src/writer/table_writer.dart +++ b/moor_generator/lib/src/writer/table_writer.dart @@ -79,16 +79,18 @@ class TableWriter { } void _writeReverseMappingMethod(StringBuffer buffer) { - // Map entityToSql(User d, {bool includeNulls = false) { + // Map entityToSql(covariant UpdateCompanion instance) buffer ..write('@override\nMap entityToSql(' - '${table.dartTypeName} d, {bool includeNulls = false}) {\n') + '${table.updateCompanionName} d) {\n') ..write('final map = {};'); for (var column in table.columns) { buffer.write(''' - if (d.${column.dartGetterName} != null || includeNulls) { - map['${column.name.name}'] = Variable<${column.dartTypeName}, ${column.sqlTypeName}>(d.${column.dartGetterName}); + if (d.${column.dartGetterName}.present) { + map['${column.name.name}'] = + Variable<${column.dartTypeName}, ${column.sqlTypeName}>( + d.${column.dartGetterName}.value); } '''); } diff --git a/moor_generator/lib/src/writer/update_companion_writer.dart b/moor_generator/lib/src/writer/update_companion_writer.dart index 348833f1..a6861bfd 100644 --- a/moor_generator/lib/src/writer/update_companion_writer.dart +++ b/moor_generator/lib/src/writer/update_companion_writer.dart @@ -9,7 +9,7 @@ class UpdateCompanionWriter { void writeInto(StringBuffer buffer) { buffer.write('class ${table.updateCompanionName} ' - 'implements UpdateCompanion<${table.dartTypeName}> {\n'); + 'extends UpdateCompanion<${table.dartTypeName}> {\n'); _writeFields(buffer); _writeConstructor(buffer); _writeIsPresentOverride(buffer);