Merge branch 'develop' into delightful-queries

This commit is contained in:
Simon Binder 2019-06-16 14:52:49 +02:00
commit 2a5ede1c04
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
11 changed files with 302 additions and 68 deletions

View File

@ -27,7 +27,7 @@ part 'filename.g.dart';
// be represented by a class called "Todo". // be represented by a class called "Todo".
class Todos extends Table { class Todos extends Table {
IntColumn get id => integer().autoIncrement()(); IntColumn get id => integer().autoIncrement()();
TextColumn get title => text().withLength(min: 6, max: 10)(); TextColumn get title => text().withLength(min: 6, max: 32)();
TextColumn get content => text().named('body')(); TextColumn get content => text().named('body')();
IntColumn get category => integer().nullable()(); IntColumn get category => integer().nullable()();
} }

View File

@ -64,6 +64,7 @@ class $CategoriesTable extends Categories
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$CategoriesTable(this._db, [this._alias]); $CategoriesTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id; GeneratedIntColumn _id;
@override @override
GeneratedIntColumn get id => _id ??= _constructId(); GeneratedIntColumn get id => _id ??= _constructId();
@ -71,6 +72,8 @@ class $CategoriesTable extends Categories
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true); return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
} }
final VerificationMeta _descriptionMeta =
const VerificationMeta('description');
GeneratedTextColumn _description; GeneratedTextColumn _description;
@override @override
GeneratedTextColumn get description => GeneratedTextColumn get description =>
@ -92,9 +95,14 @@ class $CategoriesTable extends Categories
@override @override
final String actualTableName = 'categories'; final String actualTableName = 'categories';
@override @override
bool validateIntegrity(Category instance, bool isInserting) => VerificationContext validateIntegrity(Category instance, bool isInserting) =>
id.isAcceptableValue(instance.id, isInserting) && VerificationContext()
description.isAcceptableValue(instance.description, isInserting); ..handle(
_idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta))
..handle(
_descriptionMeta,
description.isAcceptableValue(
instance.description, isInserting, _descriptionMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {id}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
@ -199,6 +207,7 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$RecipesTable(this._db, [this._alias]); $RecipesTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id; GeneratedIntColumn _id;
@override @override
GeneratedIntColumn get id => _id ??= _constructId(); GeneratedIntColumn get id => _id ??= _constructId();
@ -206,6 +215,7 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true); return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
} }
final VerificationMeta _titleMeta = const VerificationMeta('title');
GeneratedTextColumn _title; GeneratedTextColumn _title;
@override @override
GeneratedTextColumn get title => _title ??= _constructTitle(); GeneratedTextColumn get title => _title ??= _constructTitle();
@ -213,6 +223,8 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
return GeneratedTextColumn('title', $tableName, false, maxTextLength: 16); return GeneratedTextColumn('title', $tableName, false, maxTextLength: 16);
} }
final VerificationMeta _instructionsMeta =
const VerificationMeta('instructions');
GeneratedTextColumn _instructions; GeneratedTextColumn _instructions;
@override @override
GeneratedTextColumn get instructions => GeneratedTextColumn get instructions =>
@ -225,6 +237,7 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
); );
} }
final VerificationMeta _categoryMeta = const VerificationMeta('category');
GeneratedIntColumn _category; GeneratedIntColumn _category;
@override @override
GeneratedIntColumn get category => _category ??= _constructCategory(); GeneratedIntColumn get category => _category ??= _constructCategory();
@ -245,11 +258,20 @@ class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
@override @override
final String actualTableName = 'recipes'; final String actualTableName = 'recipes';
@override @override
bool validateIntegrity(Recipe instance, bool isInserting) => VerificationContext validateIntegrity(Recipe instance, bool isInserting) =>
id.isAcceptableValue(instance.id, isInserting) && VerificationContext()
title.isAcceptableValue(instance.title, isInserting) && ..handle(
instructions.isAcceptableValue(instance.instructions, isInserting) && _idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta))
category.isAcceptableValue(instance.category, isInserting); ..handle(_titleMeta,
title.isAcceptableValue(instance.title, isInserting, _titleMeta))
..handle(
_instructionsMeta,
instructions.isAcceptableValue(
instance.instructions, isInserting, _instructionsMeta))
..handle(
_categoryMeta,
category.isAcceptableValue(
instance.category, isInserting, _categoryMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {id}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
@ -349,6 +371,7 @@ class $IngredientsTable extends Ingredients
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$IngredientsTable(this._db, [this._alias]); $IngredientsTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id; GeneratedIntColumn _id;
@override @override
GeneratedIntColumn get id => _id ??= _constructId(); GeneratedIntColumn get id => _id ??= _constructId();
@ -356,6 +379,7 @@ class $IngredientsTable extends Ingredients
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true); return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
} }
final VerificationMeta _nameMeta = const VerificationMeta('name');
GeneratedTextColumn _name; GeneratedTextColumn _name;
@override @override
GeneratedTextColumn get name => _name ??= _constructName(); GeneratedTextColumn get name => _name ??= _constructName();
@ -367,6 +391,8 @@ class $IngredientsTable extends Ingredients
); );
} }
final VerificationMeta _caloriesPer100gMeta =
const VerificationMeta('caloriesPer100g');
GeneratedIntColumn _caloriesPer100g; GeneratedIntColumn _caloriesPer100g;
@override @override
GeneratedIntColumn get caloriesPer100g => GeneratedIntColumn get caloriesPer100g =>
@ -388,10 +414,17 @@ class $IngredientsTable extends Ingredients
@override @override
final String actualTableName = 'ingredients'; final String actualTableName = 'ingredients';
@override @override
bool validateIntegrity(Ingredient instance, bool isInserting) => VerificationContext validateIntegrity(
id.isAcceptableValue(instance.id, isInserting) && Ingredient instance, bool isInserting) =>
name.isAcceptableValue(instance.name, isInserting) && VerificationContext()
caloriesPer100g.isAcceptableValue(instance.caloriesPer100g, isInserting); ..handle(
_idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta))
..handle(_nameMeta,
name.isAcceptableValue(instance.name, isInserting, _nameMeta))
..handle(
_caloriesPer100gMeta,
caloriesPer100g.isAcceptableValue(
instance.caloriesPer100g, isInserting, _caloriesPer100gMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {id}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
@ -492,6 +525,7 @@ class $IngredientInRecipesTable extends IngredientInRecipes
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$IngredientInRecipesTable(this._db, [this._alias]); $IngredientInRecipesTable(this._db, [this._alias]);
final VerificationMeta _recipeMeta = const VerificationMeta('recipe');
GeneratedIntColumn _recipe; GeneratedIntColumn _recipe;
@override @override
GeneratedIntColumn get recipe => _recipe ??= _constructRecipe(); GeneratedIntColumn get recipe => _recipe ??= _constructRecipe();
@ -503,6 +537,7 @@ class $IngredientInRecipesTable extends IngredientInRecipes
); );
} }
final VerificationMeta _ingredientMeta = const VerificationMeta('ingredient');
GeneratedIntColumn _ingredient; GeneratedIntColumn _ingredient;
@override @override
GeneratedIntColumn get ingredient => _ingredient ??= _constructIngredient(); GeneratedIntColumn get ingredient => _ingredient ??= _constructIngredient();
@ -514,6 +549,8 @@ class $IngredientInRecipesTable extends IngredientInRecipes
); );
} }
final VerificationMeta _amountInGramsMeta =
const VerificationMeta('amountInGrams');
GeneratedIntColumn _amountInGrams; GeneratedIntColumn _amountInGrams;
@override @override
GeneratedIntColumn get amountInGrams => GeneratedIntColumn get amountInGrams =>
@ -535,10 +572,19 @@ class $IngredientInRecipesTable extends IngredientInRecipes
@override @override
final String actualTableName = 'recipe_ingredients'; final String actualTableName = 'recipe_ingredients';
@override @override
bool validateIntegrity(IngredientInRecipe instance, bool isInserting) => VerificationContext validateIntegrity(
recipe.isAcceptableValue(instance.recipe, isInserting) && IngredientInRecipe instance, bool isInserting) =>
ingredient.isAcceptableValue(instance.ingredient, isInserting) && VerificationContext()
amountInGrams.isAcceptableValue(instance.amountInGrams, isInserting); ..handle(_recipeMeta,
recipe.isAcceptableValue(instance.recipe, isInserting, _recipeMeta))
..handle(
_ingredientMeta,
ingredient.isAcceptableValue(
instance.ingredient, isInserting, _ingredientMeta))
..handle(
_amountInGramsMeta,
amountInGrams.isAcceptableValue(
instance.amountInGrams, isInserting, _amountInGramsMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {recipe, ingredient}; Set<GeneratedColumn> get $primaryKey => {recipe, ingredient};
@override @override

View File

@ -21,6 +21,7 @@ export 'package:moor/src/runtime/statements/select.dart';
export 'package:moor/src/runtime/statements/insert.dart'; export 'package:moor/src/runtime/statements/insert.dart';
export 'package:moor/src/runtime/statements/delete.dart'; export 'package:moor/src/runtime/statements/delete.dart';
export 'package:moor/src/runtime/structure/columns.dart'; export 'package:moor/src/runtime/structure/columns.dart';
export 'package:moor/src/runtime/structure/error_handling.dart';
export 'package:moor/src/runtime/structure/table_info.dart'; export 'package:moor/src/runtime/structure/table_info.dart';
export 'package:moor/src/runtime/data_class.dart'; export 'package:moor/src/runtime/data_class.dart';
export 'package:moor/src/runtime/database.dart'; export 'package:moor/src/runtime/database.dart';

View File

@ -116,9 +116,7 @@ class InsertStatement<DataClass> {
throw InvalidDataException( throw InvalidDataException(
'Cannot writee null row into ${table.$tableName}'); 'Cannot writee null row into ${table.$tableName}');
} }
if (!table.validateIntegrity(d, true)) {
throw InvalidDataException( table.validateIntegrity(d, true).throwIfInvalid(d);
'Invalid data: $d cannot be written into ${table.$tableName}');
}
} }
} }

View File

@ -56,10 +56,7 @@ class UpdateStatement<T extends Table, D> extends Query<T, D>
/// See also: [replace], which does not require [where] statements and /// See also: [replace], which does not require [where] statements and
/// supports setting fields back to null. /// supports setting fields back to null.
Future<int> write(D entity) async { Future<int> write(D entity) async {
if (!table.validateIntegrity(entity, false)) { table.validateIntegrity(entity, false).throwIfInvalid(entity);
throw InvalidDataException(
'Invalid data: $entity cannot be written into ${table.$tableName}');
}
_updatedFields = table.entityToSql(entity) _updatedFields = table.entityToSql(entity)
..remove((_, value) => value == null); ..remove((_, value) => value == null);
@ -93,10 +90,7 @@ class UpdateStatement<T extends Table, D> extends Query<T, D>
// because all the fields from the entity will be written (as opposed to a // 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 // regular update, where only non-null fields will be written). If isInserted
// was false, the null fields would not be validated. // was false, the null fields would not be validated.
if (!table.validateIntegrity(entity, true)) { table.validateIntegrity(entity, true).throwIfInvalid(entity);
throw InvalidDataException('Invalid data: $entity cannot be used to '
'replace another row as some required fields are null or invalid.');
}
assert( assert(
whereExpr == null, whereExpr == null,
'When using replace on an update statement, you may not use where(...)' 'When using replace on an update statement, you may not use where(...)'

View File

@ -9,6 +9,12 @@ import 'package:moor/src/runtime/expressions/variables.dart';
import 'package:moor/src/types/sql_types.dart'; import 'package:moor/src/types/sql_types.dart';
import 'package:moor/sqlite_keywords.dart'; import 'package:moor/sqlite_keywords.dart';
import 'error_handling.dart';
const VerificationResult _invalidNull = VerificationResult.failure(
"This column is not nullable and doesn't have a default value. "
"Null fields thus can't be inserted.");
/// Base class for the implementation of [Column]. /// Base class for the implementation of [Column].
abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> { abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> {
/// The sql name of this column. /// The sql name of this column.
@ -84,9 +90,14 @@ abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> {
/// method should check whether the value is valid for an update. Null values /// method should check whether the value is valid for an update. Null values
/// should always be accepted for updates, as the describe a value that should /// should always be accepted for updates, as the describe a value that should
/// not be replaced. /// not be replaced.
bool isAcceptableValue(T value, bool duringInsert) { VerificationResult isAcceptableValue(
T value, bool duringInsert, VerificationMeta meta) {
final nullOk = !duringInsert || $nullable || defaultValue != null; final nullOk = !duringInsert || $nullable || defaultValue != null;
return nullOk || value != null; if (!nullOk && value == null) {
return _invalidNull;
} else {
return const VerificationResult.success();
}
} }
} }
@ -114,15 +125,22 @@ class GeneratedTextColumn extends GeneratedColumn<String, StringType>
final String typeName = 'VARCHAR'; final String typeName = 'VARCHAR';
@override @override
bool isAcceptableValue(String value, bool duringInsert) { VerificationResult isAcceptableValue(
String value, bool duringInsert, VerificationMeta meta) {
// handle nullability check in common column // handle nullability check in common column
if (value == null) return super.isAcceptableValue(null, duringInsert); if (value == null) return super.isAcceptableValue(null, duringInsert, meta);
final length = value.length; final length = value.length;
if (minTextLength != null && minTextLength > length) return false; if (minTextLength != null && minTextLength > length) {
if (maxTextLength != null && maxTextLength < length) return false; return VerificationResult.failure(
'Must at least be $minTextLength characters long.');
}
if (maxTextLength != null && maxTextLength < length) {
return VerificationResult.failure(
'Must at most be $maxTextLength characters long.');
}
return true; return const VerificationResult.success();
} }
} }
@ -171,8 +189,13 @@ class GeneratedIntColumn extends GeneratedColumn<int, IntType>
} }
@override @override
bool isAcceptableValue(int value, bool duringInsert) => VerificationResult isAcceptableValue(
hasAutoIncrement || super.isAcceptableValue(value, duringInsert); int value, bool duringInsert, VerificationMeta meta) {
if (hasAutoIncrement) {
return const VerificationResult.success();
}
return super.isAcceptableValue(value, duringInsert, meta);
}
} }
class GeneratedDateTimeColumn extends GeneratedColumn<DateTime, DateTimeType> class GeneratedDateTimeColumn extends GeneratedColumn<DateTime, DateTimeType>

View File

@ -0,0 +1,48 @@
import 'package:moor/moor.dart';
/// Additional information that is passed to [GeneratedColumn]s when verifying
/// data to provide more helpful error messages.
class VerificationMeta {
/// The dart getter name of the property being validated.
final String dartGetterName;
const VerificationMeta(this.dartGetterName);
}
/// Returned by [GeneratedColumn.isAcceptableValue] to provide a description
/// when a valid is invalid.
class VerificationResult {
final bool success;
final String message;
const VerificationResult(this.success, this.message);
const VerificationResult.success()
: success = true,
message = null;
const VerificationResult.failure(this.message) : success = false;
}
class VerificationContext {
final Map<VerificationMeta, VerificationResult> _errors = {};
bool get dataValid => _errors.isEmpty;
void handle(VerificationMeta meta, VerificationResult result) {
if (!result.success) {
_errors[meta] = result;
}
}
void throwIfInvalid(dynamic dataObject) {
if (dataValid) return;
final messageBuilder =
StringBuffer('Sorry, $dataObject cannot be used for that because: \n');
_errors.forEach((meta, result) {
messageBuilder.write('${meta.dartGetterName}: ${result.message}\n');
});
throw InvalidDataException(messageBuilder.toString());
}
}

View File

@ -38,7 +38,7 @@ mixin TableInfo<TableDsl extends Table, DataClass> {
/// that it respects all constraints (nullability, text length, etc.). /// that it respects all constraints (nullability, text length, etc.).
/// During insertion mode, fields that have a default value or are /// During insertion mode, fields that have a default value or are
/// auto-incrementing are allowed to be null as they will be set by sqlite. /// auto-incrementing are allowed to be null as they will be set by sqlite.
bool validateIntegrity(DataClass instance, bool isInserting); VerificationContext validateIntegrity(DataClass instance, bool isInserting);
/// Maps the given data class to a [Map] that can be inserted into sql. The /// 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 /// keys should represent the column name in sql, the values the corresponding

View File

@ -102,6 +102,7 @@ class $TodosTableTable extends TodosTable
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$TodosTableTable(this._db, [this._alias]); $TodosTableTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id; GeneratedIntColumn _id;
@override @override
GeneratedIntColumn get id => _id ??= _constructId(); GeneratedIntColumn get id => _id ??= _constructId();
@ -109,6 +110,7 @@ class $TodosTableTable extends TodosTable
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true); return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
} }
final VerificationMeta _titleMeta = const VerificationMeta('title');
GeneratedTextColumn _title; GeneratedTextColumn _title;
@override @override
GeneratedTextColumn get title => _title ??= _constructTitle(); GeneratedTextColumn get title => _title ??= _constructTitle();
@ -117,6 +119,7 @@ class $TodosTableTable extends TodosTable
minTextLength: 4, maxTextLength: 16); minTextLength: 4, maxTextLength: 16);
} }
final VerificationMeta _contentMeta = const VerificationMeta('content');
GeneratedTextColumn _content; GeneratedTextColumn _content;
@override @override
GeneratedTextColumn get content => _content ??= _constructContent(); GeneratedTextColumn get content => _content ??= _constructContent();
@ -128,6 +131,7 @@ class $TodosTableTable extends TodosTable
); );
} }
final VerificationMeta _targetDateMeta = const VerificationMeta('targetDate');
GeneratedDateTimeColumn _targetDate; GeneratedDateTimeColumn _targetDate;
@override @override
GeneratedDateTimeColumn get targetDate => GeneratedDateTimeColumn get targetDate =>
@ -140,6 +144,7 @@ class $TodosTableTable extends TodosTable
); );
} }
final VerificationMeta _categoryMeta = const VerificationMeta('category');
GeneratedIntColumn _category; GeneratedIntColumn _category;
@override @override
GeneratedIntColumn get category => _category ??= _constructCategory(); GeneratedIntColumn get category => _category ??= _constructCategory();
@ -161,12 +166,24 @@ class $TodosTableTable extends TodosTable
@override @override
final String actualTableName = 'todos'; final String actualTableName = 'todos';
@override @override
bool validateIntegrity(TodoEntry instance, bool isInserting) => VerificationContext validateIntegrity(TodoEntry instance, bool isInserting) =>
id.isAcceptableValue(instance.id, isInserting) && VerificationContext()
title.isAcceptableValue(instance.title, isInserting) && ..handle(
content.isAcceptableValue(instance.content, isInserting) && _idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta))
targetDate.isAcceptableValue(instance.targetDate, isInserting) && ..handle(_titleMeta,
category.isAcceptableValue(instance.category, isInserting); title.isAcceptableValue(instance.title, isInserting, _titleMeta))
..handle(
_contentMeta,
content.isAcceptableValue(
instance.content, isInserting, _contentMeta))
..handle(
_targetDateMeta,
targetDate.isAcceptableValue(
instance.targetDate, isInserting, _targetDateMeta))
..handle(
_categoryMeta,
category.isAcceptableValue(
instance.category, isInserting, _categoryMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {id}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
@ -259,6 +276,7 @@ class $CategoriesTable extends Categories
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$CategoriesTable(this._db, [this._alias]); $CategoriesTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id; GeneratedIntColumn _id;
@override @override
GeneratedIntColumn get id => _id ??= _constructId(); GeneratedIntColumn get id => _id ??= _constructId();
@ -266,6 +284,8 @@ class $CategoriesTable extends Categories
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true); return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
} }
final VerificationMeta _descriptionMeta =
const VerificationMeta('description');
GeneratedTextColumn _description; GeneratedTextColumn _description;
@override @override
GeneratedTextColumn get description => GeneratedTextColumn get description =>
@ -284,9 +304,14 @@ class $CategoriesTable extends Categories
@override @override
final String actualTableName = 'categories'; final String actualTableName = 'categories';
@override @override
bool validateIntegrity(Category instance, bool isInserting) => VerificationContext validateIntegrity(Category instance, bool isInserting) =>
id.isAcceptableValue(instance.id, isInserting) && VerificationContext()
description.isAcceptableValue(instance.description, isInserting); ..handle(
_idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta))
..handle(
_descriptionMeta,
description.isAcceptableValue(
instance.description, isInserting, _descriptionMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {id}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
@ -413,6 +438,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$UsersTable(this._db, [this._alias]); $UsersTable(this._db, [this._alias]);
final VerificationMeta _idMeta = const VerificationMeta('id');
GeneratedIntColumn _id; GeneratedIntColumn _id;
@override @override
GeneratedIntColumn get id => _id ??= _constructId(); GeneratedIntColumn get id => _id ??= _constructId();
@ -420,6 +446,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true); return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
} }
final VerificationMeta _nameMeta = const VerificationMeta('name');
GeneratedTextColumn _name; GeneratedTextColumn _name;
@override @override
GeneratedTextColumn get name => _name ??= _constructName(); GeneratedTextColumn get name => _name ??= _constructName();
@ -428,6 +455,7 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
minTextLength: 6, maxTextLength: 32); minTextLength: 6, maxTextLength: 32);
} }
final VerificationMeta _isAwesomeMeta = const VerificationMeta('isAwesome');
GeneratedBoolColumn _isAwesome; GeneratedBoolColumn _isAwesome;
@override @override
GeneratedBoolColumn get isAwesome => _isAwesome ??= _constructIsAwesome(); GeneratedBoolColumn get isAwesome => _isAwesome ??= _constructIsAwesome();
@ -436,6 +464,8 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
defaultValue: const Constant(true)); defaultValue: const Constant(true));
} }
final VerificationMeta _profilePictureMeta =
const VerificationMeta('profilePicture');
GeneratedBlobColumn _profilePicture; GeneratedBlobColumn _profilePicture;
@override @override
GeneratedBlobColumn get profilePicture => GeneratedBlobColumn get profilePicture =>
@ -448,6 +478,8 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
); );
} }
final VerificationMeta _creationTimeMeta =
const VerificationMeta('creationTime');
GeneratedDateTimeColumn _creationTime; GeneratedDateTimeColumn _creationTime;
@override @override
GeneratedDateTimeColumn get creationTime => GeneratedDateTimeColumn get creationTime =>
@ -467,12 +499,24 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> {
@override @override
final String actualTableName = 'users'; final String actualTableName = 'users';
@override @override
bool validateIntegrity(User instance, bool isInserting) => VerificationContext validateIntegrity(User instance, bool isInserting) =>
id.isAcceptableValue(instance.id, isInserting) && VerificationContext()
name.isAcceptableValue(instance.name, isInserting) && ..handle(
isAwesome.isAcceptableValue(instance.isAwesome, isInserting) && _idMeta, id.isAcceptableValue(instance.id, isInserting, _idMeta))
profilePicture.isAcceptableValue(instance.profilePicture, isInserting) && ..handle(_nameMeta,
creationTime.isAcceptableValue(instance.creationTime, isInserting); name.isAcceptableValue(instance.name, isInserting, _nameMeta))
..handle(
_isAwesomeMeta,
isAwesome.isAcceptableValue(
instance.isAwesome, isInserting, _isAwesomeMeta))
..handle(
_profilePictureMeta,
profilePicture.isAcceptableValue(
instance.profilePicture, isInserting, _profilePictureMeta))
..handle(
_creationTimeMeta,
creationTime.isAcceptableValue(
instance.creationTime, isInserting, _creationTimeMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {id}; Set<GeneratedColumn> get $primaryKey => {id};
@override @override
@ -563,6 +607,7 @@ class $SharedTodosTable extends SharedTodos
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$SharedTodosTable(this._db, [this._alias]); $SharedTodosTable(this._db, [this._alias]);
final VerificationMeta _todoMeta = const VerificationMeta('todo');
GeneratedIntColumn _todo; GeneratedIntColumn _todo;
@override @override
GeneratedIntColumn get todo => _todo ??= _constructTodo(); GeneratedIntColumn get todo => _todo ??= _constructTodo();
@ -574,6 +619,7 @@ class $SharedTodosTable extends SharedTodos
); );
} }
final VerificationMeta _userMeta = const VerificationMeta('user');
GeneratedIntColumn _user; GeneratedIntColumn _user;
@override @override
GeneratedIntColumn get user => _user ??= _constructUser(); GeneratedIntColumn get user => _user ??= _constructUser();
@ -594,9 +640,13 @@ class $SharedTodosTable extends SharedTodos
@override @override
final String actualTableName = 'shared_todos'; final String actualTableName = 'shared_todos';
@override @override
bool validateIntegrity(SharedTodo instance, bool isInserting) => VerificationContext validateIntegrity(
todo.isAcceptableValue(instance.todo, isInserting) && SharedTodo instance, bool isInserting) =>
user.isAcceptableValue(instance.user, isInserting); VerificationContext()
..handle(_todoMeta,
todo.isAcceptableValue(instance.todo, isInserting, _todoMeta))
..handle(_userMeta,
user.isAcceptableValue(instance.user, isInserting, _userMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => {todo, user}; Set<GeneratedColumn> get $primaryKey => {todo, user};
@override @override
@ -686,6 +736,8 @@ class $TableWithoutPKTable extends TableWithoutPK
final GeneratedDatabase _db; final GeneratedDatabase _db;
final String _alias; final String _alias;
$TableWithoutPKTable(this._db, [this._alias]); $TableWithoutPKTable(this._db, [this._alias]);
final VerificationMeta _notReallyAnIdMeta =
const VerificationMeta('notReallyAnId');
GeneratedIntColumn _notReallyAnId; GeneratedIntColumn _notReallyAnId;
@override @override
GeneratedIntColumn get notReallyAnId => GeneratedIntColumn get notReallyAnId =>
@ -698,6 +750,7 @@ class $TableWithoutPKTable extends TableWithoutPK
); );
} }
final VerificationMeta _someFloatMeta = const VerificationMeta('someFloat');
GeneratedRealColumn _someFloat; GeneratedRealColumn _someFloat;
@override @override
GeneratedRealColumn get someFloat => _someFloat ??= _constructSomeFloat(); GeneratedRealColumn get someFloat => _someFloat ??= _constructSomeFloat();
@ -718,9 +771,17 @@ class $TableWithoutPKTable extends TableWithoutPK
@override @override
final String actualTableName = 'table_without_p_k'; final String actualTableName = 'table_without_p_k';
@override @override
bool validateIntegrity(TableWithoutPKData instance, bool isInserting) => VerificationContext validateIntegrity(
notReallyAnId.isAcceptableValue(instance.notReallyAnId, isInserting) && TableWithoutPKData instance, bool isInserting) =>
someFloat.isAcceptableValue(instance.someFloat, isInserting); VerificationContext()
..handle(
_notReallyAnIdMeta,
notReallyAnId.isAcceptableValue(
instance.notReallyAnId, isInserting, _notReallyAnIdMeta))
..handle(
_someFloatMeta,
someFloat.isAcceptableValue(
instance.someFloat, isInserting, _someFloatMeta));
@override @override
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{}; Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
@override @override

View File

@ -0,0 +1,42 @@
import 'package:moor/moor.dart';
import 'package:test_api/test_api.dart';
import 'data/tables/todos.dart';
import 'data/utils/mocks.dart';
// the content is set to non-null and the title must be between 4 and 16 chars
// long
final nullContent = TodoEntry(title: 'Test', content: null);
final shortTitle = TodoEntry(title: 'A', content: 'content');
final longTitle = TodoEntry(title: 'A ${'very' * 5} long title', content: 'hi');
final valid = TodoEntry(title: 'Test', content: 'Some content');
void main() {
TodoDb db;
MockExecutor executor;
setUp(() {
executor = MockExecutor();
db = TodoDb(executor);
});
test('detects errors on insert', () {
expect(
() => db.into(db.todosTable).insert(nullContent),
throwsA(predicate<InvalidDataException>(
(e) => e.message.contains('not nullable'))),
);
expect(
() => db.into(db.todosTable).insert(shortTitle),
throwsA(predicate<InvalidDataException>(
(e) => e.message.contains('Must at least be'))),
);
expect(
() => db.into(db.todosTable).insert(longTitle),
throwsA(predicate<InvalidDataException>(
(e) => e.message.contains('Must at most be'))),
);
expect(db.into(db.todosTable).insert(valid), completes);
});
}

View File

@ -34,6 +34,7 @@ class TableWriter {
// Generate the columns // Generate the columns
for (var column in table.columns) { for (var column in table.columns) {
_writeColumnVerificationMeta(buffer, column);
_writeColumnGetter(buffer, column); _writeColumnGetter(buffer, column);
} }
@ -147,22 +148,42 @@ class TableWriter {
); );
} }
void _writeColumnVerificationMeta(
StringBuffer buffer, SpecifiedColumn column) {
// final VerificationMeta _targetDateMeta = const VerificationMeta('targetDate');
buffer
..write('final VerificationMeta ${_fieldNameForColumnMeta(column)} = ')
..write("const VerificationMeta('${column.dartGetterName}');\n");
}
void _writeValidityCheckMethod(StringBuffer buffer) { void _writeValidityCheckMethod(StringBuffer buffer) {
final dataClass = table.dartTypeName; final dataClass = table.dartTypeName;
buffer.write( buffer.write('@override\nVerificationContext validateIntegrity'
'@override\nbool validateIntegrity($dataClass instance, bool isInserting) => '); '($dataClass instance, bool isInserting) => VerificationContext()');
final validationCode = table.columns.map((column) { /*
return VerificationContext()
..handle(
_categoryMeta,
category.isAcceptableValue(
instance.category, isInserting, _categoryMeta));
*/
for (var column in table.columns) {
final getterName = column.dartGetterName; final getterName = column.dartGetterName;
final metaName = _fieldNameForColumnMeta(column);
// generated columns have a isAcceptableValue(T value, bool duringInsert) // ..handle(_meta, c.isAcceptableValue(instance.c, insert, _meta))
// method buffer.write('..handle($metaName, $getterName.isAcceptableValue('
'instance.$getterName, isInserting, $metaName))');
}
return '$getterName.isAcceptableValue(instance.$getterName, isInserting)'; buffer.write(';\n');
}).join('&&'); }
buffer..write(validationCode)..write(';\n'); String _fieldNameForColumnMeta(SpecifiedColumn column) {
return '_${column.dartGetterName}Meta';
} }
void _writePrimaryKeyOverride(StringBuffer buffer) { void _writePrimaryKeyOverride(StringBuffer buffer) {