mirror of https://github.com/AMT-Cheif/drift.git
Validate data integrity before inserts and updates
This commit is contained in:
parent
81b0bac19b
commit
c9aab2e824
|
@ -24,14 +24,21 @@ class User {
|
|||
}
|
||||
|
||||
class _$UsersTable extends Users implements TableInfo<Users, User> {
|
||||
final GeneratedDatabase db;
|
||||
_$UsersTable(this.db);
|
||||
final GeneratedDatabase _db;
|
||||
_$UsersTable(this._db);
|
||||
@override
|
||||
GeneratedIntColumn get id => GeneratedIntColumn('id', false);
|
||||
GeneratedIntColumn get id =>
|
||||
GeneratedIntColumn('id', false, hasAutoIncrement: true);
|
||||
@override
|
||||
GeneratedTextColumn get userName => GeneratedTextColumn('name', false);
|
||||
GeneratedTextColumn get userName => GeneratedTextColumn(
|
||||
'name',
|
||||
false,
|
||||
);
|
||||
@override
|
||||
GeneratedTextColumn get bio => GeneratedTextColumn('bio', false);
|
||||
GeneratedTextColumn get bio => GeneratedTextColumn(
|
||||
'bio',
|
||||
false,
|
||||
);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, userName, bio];
|
||||
@override
|
||||
|
@ -39,13 +46,16 @@ class _$UsersTable extends Users implements TableInfo<Users, User> {
|
|||
@override
|
||||
String get $tableName => 'users';
|
||||
@override
|
||||
void validateIntegrity(User instance, bool isInserting) => null;
|
||||
void validateIntegrity(User instance, bool isInserting) =>
|
||||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
userName.isAcceptableValue(instance.userName, isInserting) &&
|
||||
bio.isAcceptableValue(instance.bio, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => Set();
|
||||
@override
|
||||
User map(Map<String, dynamic> data) {
|
||||
final intType = db.typeSystem.forDartType<int>();
|
||||
final stringType = db.typeSystem.forDartType<String>();
|
||||
final intType = _db.typeSystem.forDartType<int>();
|
||||
final stringType = _db.typeSystem.forDartType<String>();
|
||||
return User(
|
||||
id: intType.mapFromDatabaseResponse(data['id']),
|
||||
userName: stringType.mapFromDatabaseResponse(data['name']),
|
||||
|
|
|
@ -80,7 +80,7 @@ class MyDatabase extends _$MyDatabase {
|
|||
MigrationStrategy get migration => MigrationStrategy();
|
||||
}
|
||||
```
|
||||
You can ignore these two getters there at the moment, the imporant part is that you can
|
||||
You can ignore these two getters there at the moment, the important part is that you can
|
||||
now run your queries with fluent Dart code:
|
||||
```dart
|
||||
class MyDatabase extends _$MyDatabase {
|
||||
|
@ -114,6 +114,7 @@ supporting floating / fixed point numbers as well would be awesome
|
|||
- DSL API
|
||||
- Support in generator
|
||||
- Use in queries (`IS NOT NULL`)
|
||||
- Setting fields to null during updates
|
||||
- Verify constraints (text length, nullability, etc.) before inserting or
|
||||
deleting data.
|
||||
- Support Dart VM apps
|
||||
|
|
|
@ -39,6 +39,17 @@ abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> {
|
|||
|
||||
@override
|
||||
Expression<BoolType> equals(T compare) => equalsExp(Variable<T, S>(compare));
|
||||
|
||||
/// Checks whether the given value fits into this column. The default
|
||||
/// implementation checks whether the value is not null, as null values are
|
||||
/// only allowed for updates or if the column is nullable.
|
||||
/// If [duringInsert] is true, the method should check whether the value is
|
||||
/// suitable for a new row that is being inserted. If it's false, we the
|
||||
/// 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
|
||||
/// not be replaced.
|
||||
bool isAcceptableValue(T value, bool duringInsert) =>
|
||||
($nullable || !duringInsert) || value != null;
|
||||
}
|
||||
|
||||
class GeneratedTextColumn extends GeneratedColumn<String, StringType>
|
||||
|
@ -91,4 +102,8 @@ class GeneratedIntColumn extends GeneratedColumn<int, IntType>
|
|||
@override
|
||||
Expression<BoolType> isSmallerThan(int i) =>
|
||||
Comparison(this, ComparisonOperator.less, Variable<int, IntType>(i));
|
||||
|
||||
@override
|
||||
bool isAcceptableValue(int value, bool duringInsert) =>
|
||||
hasAutoIncrement || super.isAcceptableValue(value, duringInsert);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:recase/recase.dart';
|
||||
import 'package:sally_generator/src/model/specified_column.dart';
|
||||
import 'package:sally_generator/src/model/specified_table.dart';
|
||||
import 'package:sally_generator/src/writer/data_class_writer.dart';
|
||||
|
||||
|
@ -25,19 +26,12 @@ class TableWriter {
|
|||
..write('class ${table.tableInfoName} extends $tableDslName '
|
||||
'implements TableInfo<$tableDslName, $dataClass> {\n')
|
||||
// should have a GeneratedDatabase reference that is set in the constructor
|
||||
..write('final GeneratedDatabase db;\n')
|
||||
..write('${table.tableInfoName}(this.db);\n');
|
||||
..write('final GeneratedDatabase _db;\n')
|
||||
..write('${table.tableInfoName}(this._db);\n');
|
||||
|
||||
// Generate the columns
|
||||
for (var column in table.columns) {
|
||||
final isNullable = false;
|
||||
|
||||
// @override
|
||||
// GeneratedIntColumn get id => GeneratedIntColumn('sql_name', isNullable);
|
||||
buffer
|
||||
..write('@override \n')
|
||||
..write('${column.implColumnTypeName} get ${column.dartGetterName} => '
|
||||
'${column.implColumnTypeName}(\'${column.name.name}\', $isNullable);\n');
|
||||
_writeColumnGetter(buffer, column);
|
||||
}
|
||||
|
||||
// Generate $columns, $tableName, asDslTable getters
|
||||
|
@ -48,9 +42,9 @@ class TableWriter {
|
|||
..write(
|
||||
'@override\nList<GeneratedColumn> get \$columns => [$columnsWithGetters];\n')
|
||||
..write('@override\n$tableDslName get asDslTable => this;\n')
|
||||
..write('@override\nString get \$tableName => \'${table.sqlName}\';\n')
|
||||
..write(
|
||||
'@override\nvoid validateIntegrity($dataClass instance, bool isInserting) => null;');
|
||||
..write('@override\nString get \$tableName => \'${table.sqlName}\';\n');
|
||||
|
||||
_writeValidityCheckMethod(buffer);
|
||||
|
||||
// todo replace set syntax with literal once dart supports it
|
||||
// write primary key getter: Set<Column> get $primaryKey => Set().add(id);
|
||||
|
@ -83,7 +77,7 @@ class TableWriter {
|
|||
dartTypeToResolver[usedType] = resolver;
|
||||
|
||||
buffer
|
||||
.write('final $resolver = db.typeSystem.forDartType<$usedType>();\n');
|
||||
.write('final $resolver = _db.typeSystem.forDartType<$usedType>();\n');
|
||||
}
|
||||
|
||||
// finally, the mighty constructor invocation:
|
||||
|
@ -119,4 +113,50 @@ class TableWriter {
|
|||
|
||||
buffer.write('return map; \n}\n');
|
||||
}
|
||||
|
||||
void _writeColumnGetter(StringBuffer buffer, SpecifiedColumn column) {
|
||||
final isNullable = false; // todo nullability for columns
|
||||
final additionalParams = <String, String>{};
|
||||
|
||||
if (column.hasAI) {
|
||||
additionalParams['hasAutoIncrement'] = 'true';
|
||||
}
|
||||
|
||||
// @override
|
||||
// GeneratedIntColumn get id => GeneratedIntColumn('sql_name', isNullable);
|
||||
buffer
|
||||
..write('@override \n')
|
||||
..write('${column.implColumnTypeName} get ${column.dartGetterName} => '
|
||||
'${column.implColumnTypeName}(\'${column.name.name}\', $isNullable, ');
|
||||
|
||||
var first = true;
|
||||
additionalParams.forEach((name, value) {
|
||||
if (!first) {
|
||||
buffer.write(', ');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
buffer..write(name)..write(': ')..write(value);
|
||||
});
|
||||
|
||||
buffer.write(');\n');
|
||||
}
|
||||
|
||||
void _writeValidityCheckMethod(StringBuffer buffer) {
|
||||
final dataClass = table.dartTypeName;
|
||||
|
||||
buffer.write('@override\nvoid validateIntegrity($dataClass instance, bool isInserting) => ');
|
||||
|
||||
final validationCode = table.columns.map((column) {
|
||||
final getterName = column.dartGetterName;
|
||||
|
||||
// generated columns have a isAcceptableValue(T value, bool duringInsert)
|
||||
// method
|
||||
|
||||
return '$getterName.isAcceptableValue(instance.$getterName, isInserting)';
|
||||
}).join('&&');
|
||||
|
||||
buffer..write(validationCode)..write(';\n');
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue