mirror of https://github.com/AMT-Cheif/drift.git
Implement replace API as a companion for updates
This commit is contained in:
parent
2e7c079e4d
commit
271e3bb569
|
@ -53,19 +53,19 @@ class $CategoriesTable extends Categories
|
|||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
description.isAcceptableValue(instance.description, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Category map(Map<String, dynamic> data) {
|
||||
return Category.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(Category d) {
|
||||
Map<String, Variable> entityToSql(Category d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.description != null) {
|
||||
if (d.description != null || includeNulls) {
|
||||
map['description'] = Variable<String, StringType>(d.description);
|
||||
}
|
||||
return map;
|
||||
|
@ -142,25 +142,25 @@ class $RecipesTable extends Recipes implements TableInfo<Recipes, Recipe> {
|
|||
instructions.isAcceptableValue(instance.instructions, isInserting) &&
|
||||
category.isAcceptableValue(instance.category, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Recipe map(Map<String, dynamic> data) {
|
||||
return Recipe.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(Recipe d) {
|
||||
Map<String, Variable> entityToSql(Recipe d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.title != null) {
|
||||
if (d.title != null || includeNulls) {
|
||||
map['title'] = Variable<String, StringType>(d.title);
|
||||
}
|
||||
if (d.instructions != null) {
|
||||
if (d.instructions != null || includeNulls) {
|
||||
map['instructions'] = Variable<String, StringType>(d.instructions);
|
||||
}
|
||||
if (d.category != null) {
|
||||
if (d.category != null || includeNulls) {
|
||||
map['category'] = Variable<int, IntType>(d.category);
|
||||
}
|
||||
return map;
|
||||
|
@ -227,22 +227,22 @@ class $IngredientsTable extends Ingredients
|
|||
name.isAcceptableValue(instance.name, isInserting) &&
|
||||
caloriesPer100g.isAcceptableValue(instance.caloriesPer100g, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Ingredient map(Map<String, dynamic> data) {
|
||||
return Ingredient.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(Ingredient d) {
|
||||
Map<String, Variable> entityToSql(Ingredient d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.name != null) {
|
||||
if (d.name != null || includeNulls) {
|
||||
map['name'] = Variable<String, StringType>(d.name);
|
||||
}
|
||||
if (d.caloriesPer100g != null) {
|
||||
if (d.caloriesPer100g != null || includeNulls) {
|
||||
map['calories'] = Variable<int, IntType>(d.caloriesPer100g);
|
||||
}
|
||||
return map;
|
||||
|
@ -321,15 +321,16 @@ class $IngredientInRecipesTable extends IngredientInRecipes
|
|||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(IngredientInRecipe d) {
|
||||
Map<String, Variable> entityToSql(IngredientInRecipe d,
|
||||
{bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.recipe != null) {
|
||||
if (d.recipe != null || includeNulls) {
|
||||
map['recipe'] = Variable<int, IntType>(d.recipe);
|
||||
}
|
||||
if (d.ingredient != null) {
|
||||
if (d.ingredient != null || includeNulls) {
|
||||
map['ingredient'] = Variable<int, IntType>(d.ingredient);
|
||||
}
|
||||
if (d.amountInGrams != null) {
|
||||
if (d.amountInGrams != null || includeNulls) {
|
||||
map['amount'] = Variable<int, IntType>(d.amountInGrams);
|
||||
}
|
||||
return map;
|
||||
|
|
|
@ -3,4 +3,11 @@ class InvalidDataException implements Exception {
|
|||
final String message;
|
||||
|
||||
InvalidDataException(this.message);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'InvalidDataException: $message';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import 'package:sally/sally.dart';
|
||||
import 'package:sally/src/runtime/components/component.dart';
|
||||
import 'package:sally/src/runtime/expressions/expression.dart';
|
||||
|
||||
class CustomExpression<D, S extends SqlType<D>> extends Expression<D, S> {
|
||||
|
||||
final String content;
|
||||
|
||||
CustomExpression(this.content);
|
||||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
context.buffer.write(content);
|
||||
}
|
||||
|
||||
}
|
|
@ -39,8 +39,12 @@ class Variable<T, S extends SqlType<T>> extends Expression<T, S> {
|
|||
|
||||
@override
|
||||
void writeInto(GenerationContext context) {
|
||||
context.buffer.write('?');
|
||||
context.introduceVariable(mapToSimpleValue(context));
|
||||
if (value != null) {
|
||||
context.buffer.write('?');
|
||||
context.introduceVariable(mapToSimpleValue(context));
|
||||
} else {
|
||||
context.buffer.write('NULL');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,21 +55,23 @@ class Migrator {
|
|||
Future<void> createTable(TableInfo table) async {
|
||||
final sql = StringBuffer();
|
||||
|
||||
// todo write primary key
|
||||
|
||||
// ignore: cascade_invocations
|
||||
sql.write('CREATE TABLE IF NOT EXISTS ${table.$tableName} (');
|
||||
|
||||
var hasAutoIncrement = false;
|
||||
for (var i = 0; i < table.$columns.length; i++) {
|
||||
final column = table.$columns[i];
|
||||
|
||||
if (column is GeneratedIntColumn && column.hasAutoIncrement)
|
||||
hasAutoIncrement = true;
|
||||
|
||||
// ignore: cascade_invocations
|
||||
column.writeColumnDefinition(sql);
|
||||
|
||||
if (i < table.$columns.length - 1) sql.write(', ');
|
||||
}
|
||||
|
||||
if (table.$primaryKey != null) {
|
||||
if (table.$primaryKey != null && !hasAutoIncrement) {
|
||||
sql.write(', PRIMARY KEY (');
|
||||
final pkList = table.$primaryKey.toList(growable: false);
|
||||
for (var i = 0; i < pkList.length; i++) {
|
||||
|
|
|
@ -2,12 +2,15 @@ import 'dart:async';
|
|||
|
||||
import 'package:sally/sally.dart';
|
||||
import 'package:sally/src/runtime/components/component.dart';
|
||||
import 'package:sally/src/runtime/components/where.dart';
|
||||
import 'package:sally/src/runtime/expressions/custom.dart';
|
||||
import 'package:sally/src/runtime/expressions/expression.dart';
|
||||
|
||||
class UpdateStatement<T, D> extends Query<T, D> {
|
||||
UpdateStatement(QueryEngine database, TableInfo<T, D> table)
|
||||
: super(database, table);
|
||||
|
||||
Map<String, dynamic> _updatedFields;
|
||||
Map<String, Variable> _updatedFields;
|
||||
|
||||
@override
|
||||
void writeStartPart(GenerationContext ctx) {
|
||||
|
@ -29,10 +32,31 @@ class UpdateStatement<T, D> extends Query<T, D> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<int> _performQuery() async {
|
||||
final ctx = constructQuery();
|
||||
final rows = await ctx.database.executor.doWhenOpened((e) async {
|
||||
return await e.runUpdate(ctx.sql, ctx.boundVariables);
|
||||
});
|
||||
|
||||
if (rows > 0) {
|
||||
database.markTableUpdated(table.$tableName);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// Writes all non-null fields from [entity] into the columns of all rows
|
||||
/// that match the set [where] and limit constraints. Warning: That also
|
||||
/// means that, when you're not setting a where or limit expression
|
||||
/// explicitly, this method will update all rows in the specific table.
|
||||
///
|
||||
/// The fields that are null on the [entity] object will not be changed by
|
||||
/// this operation.
|
||||
///
|
||||
/// Returns the amount of rows that have been affected by this operation.
|
||||
///
|
||||
/// See also: [replace], which does not require [where] statements and
|
||||
/// supports setting fields to null.
|
||||
Future<int> write(D entity) async {
|
||||
if (!table.validateIntegrity(entity, false)) {
|
||||
throw InvalidDataException(
|
||||
|
@ -47,15 +71,59 @@ class UpdateStatement<T, D> extends Query<T, D> {
|
|||
return Future.value(0);
|
||||
}
|
||||
|
||||
final ctx = constructQuery();
|
||||
final rows = await ctx.database.executor.doWhenOpened((e) async {
|
||||
return await e.runUpdate(ctx.sql, ctx.boundVariables);
|
||||
});
|
||||
return await _performQuery();
|
||||
}
|
||||
|
||||
if (rows > 0) {
|
||||
database.markTableUpdated(table.$tableName);
|
||||
/// Replaces the old version of [entity] that is stored in the database with
|
||||
/// the fields of the [entity] provided here. This implicitly applies a
|
||||
/// [where] clause to rows with the same primary key as [entity], so that only
|
||||
/// the row representing outdated data will be replaced.
|
||||
///
|
||||
/// If [entity] has fields with null as value, data in the row will be set
|
||||
/// back to null. This behavior is different to that of [write], which ignores
|
||||
/// null fields.
|
||||
///
|
||||
/// Returns true if a row was affected by this operation.
|
||||
Future<bool> 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.
|
||||
if (!table.validateIntegrity(entity, true))
|
||||
throw InvalidDataException('Invalid data: $entity cannot be used to '
|
||||
'replace another row as some required fields are null or invalid.');
|
||||
|
||||
assert(
|
||||
whereExpr == null,
|
||||
'When using replace on an update statement, you may not use where(...)'
|
||||
'as well. The where clause will be determined automatically');
|
||||
|
||||
_updatedFields = table.entityToSql(entity, includeNulls: true);
|
||||
final primaryKeys = table.$primaryKey.map((c) => c.$name);
|
||||
|
||||
// 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)));
|
||||
|
||||
// But remove them from the map of columns that should be changed.
|
||||
_updatedFields.removeWhere((key, _) => primaryKeys.contains(key));
|
||||
|
||||
Expression<bool, BoolType> predicate;
|
||||
for (var entry in primaryKeyValues.entries) {
|
||||
// custom expression that references the column
|
||||
final columnExpression = CustomExpression(entry.key);
|
||||
final comparison = Comparison(columnExpression, ComparisonOperator.equal, entry.value);
|
||||
|
||||
if (predicate == null) {
|
||||
predicate = comparison;
|
||||
} else {
|
||||
predicate = and(predicate, comparison);
|
||||
}
|
||||
}
|
||||
|
||||
return rows;
|
||||
whereExpr = Where(predicate);
|
||||
|
||||
final updatedRows = await _performQuery();
|
||||
return updatedRows != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,14 @@ abstract class TableInfo<TableDsl, DataClass> {
|
|||
/// auto-incrementing are allowed to be null as they will be set by sqlite.
|
||||
bool validateIntegrity(DataClass instance, bool isInserting);
|
||||
|
||||
/// Maps the given data class into 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
|
||||
/// values of the field.
|
||||
Map<String, Variable> entityToSql(DataClass instance);
|
||||
///
|
||||
/// If [includeNulls] is true, fields of the [DataClass] 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.
|
||||
Map<String, Variable> entityToSql(DataClass instance, {bool includeNulls = false});
|
||||
|
||||
/// Maps the given row returned by the database into the fitting data class.
|
||||
DataClass map(Map<String, dynamic> data);
|
||||
|
|
|
@ -96,28 +96,28 @@ class $TodosTableTable extends TodosTable
|
|||
targetDate.isAcceptableValue(instance.targetDate, isInserting) &&
|
||||
category.isAcceptableValue(instance.category, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
TodoEntry map(Map<String, dynamic> data) {
|
||||
return TodoEntry.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(TodoEntry d) {
|
||||
Map<String, Variable> entityToSql(TodoEntry d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.title != null) {
|
||||
if (d.title != null || includeNulls) {
|
||||
map['title'] = Variable<String, StringType>(d.title);
|
||||
}
|
||||
if (d.content != null) {
|
||||
if (d.content != null || includeNulls) {
|
||||
map['content'] = Variable<String, StringType>(d.content);
|
||||
}
|
||||
if (d.targetDate != null) {
|
||||
if (d.targetDate != null || includeNulls) {
|
||||
map['target_date'] = Variable<DateTime, DateTimeType>(d.targetDate);
|
||||
}
|
||||
if (d.category != null) {
|
||||
if (d.category != null || includeNulls) {
|
||||
map['category'] = Variable<int, IntType>(d.category);
|
||||
}
|
||||
return map;
|
||||
|
@ -171,19 +171,19 @@ class $CategoriesTable extends Categories
|
|||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
description.isAcceptableValue(instance.description, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Category map(Map<String, dynamic> data) {
|
||||
return Category.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(Category d) {
|
||||
Map<String, Variable> entityToSql(Category d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.description != null) {
|
||||
if (d.description != null || includeNulls) {
|
||||
map['`desc`'] = Variable<String, StringType>(d.description);
|
||||
}
|
||||
return map;
|
||||
|
@ -248,22 +248,22 @@ class $UsersTable extends Users implements TableInfo<Users, User> {
|
|||
name.isAcceptableValue(instance.name, isInserting) &&
|
||||
isAwesome.isAcceptableValue(instance.isAwesome, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
User map(Map<String, dynamic> data) {
|
||||
return User.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(User d) {
|
||||
Map<String, Variable> entityToSql(User d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.name != null) {
|
||||
if (d.name != null || includeNulls) {
|
||||
map['name'] = Variable<String, StringType>(d.name);
|
||||
}
|
||||
if (d.isAwesome != null) {
|
||||
if (d.isAwesome != null || includeNulls) {
|
||||
map['is_awesome'] = Variable<bool, BoolType>(d.isAwesome);
|
||||
}
|
||||
return map;
|
||||
|
@ -325,12 +325,12 @@ class $SharedTodosTable extends SharedTodos
|
|||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(SharedTodo d) {
|
||||
Map<String, Variable> entityToSql(SharedTodo d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.todo != null) {
|
||||
if (d.todo != null || includeNulls) {
|
||||
map['todo'] = Variable<int, IntType>(d.todo);
|
||||
}
|
||||
if (d.user != null) {
|
||||
if (d.user != null || includeNulls) {
|
||||
map['user'] = Variable<int, IntType>(d.user);
|
||||
}
|
||||
return map;
|
||||
|
|
|
@ -15,4 +15,14 @@ void main() {
|
|||
expect('?', ctx.sql);
|
||||
expect(ctx.boundVariables, [1551297563]);
|
||||
});
|
||||
|
||||
test('writes null directly for null values', () {
|
||||
final variable = Variable.withString(null);
|
||||
final ctx = GenerationContext(TodoDb(null));
|
||||
|
||||
variable.writeInto(ctx);
|
||||
|
||||
expect('NULL', ctx.sql);
|
||||
expect(ctx.boundVariables, isEmpty);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -37,6 +37,20 @@ void main() {
|
|||
});
|
||||
});
|
||||
|
||||
test('generates replace statements', () async {
|
||||
await db.update(db.todosTable).replace(TodoEntry(
|
||||
id: 3,
|
||||
title: 'Title',
|
||||
content: 'Updated content',
|
||||
// category and targetDate are null
|
||||
));
|
||||
|
||||
verify(executor.runUpdate(
|
||||
'UPDATE todos SET title = ?, content = ?, '
|
||||
'target_date = NULL, category = NULL WHERE id = ?;',
|
||||
['Title', 'Updated content', 3]));
|
||||
});
|
||||
|
||||
test('does not update with invalid data', () {
|
||||
// The length of a title must be between 4 and 16 chars
|
||||
|
||||
|
@ -45,7 +59,7 @@ void main() {
|
|||
}, throwsA(const TypeMatcher<InvalidDataException>()));
|
||||
});
|
||||
|
||||
group('Table updates for delete statements', () {
|
||||
group('Table updates for update statements', () {
|
||||
test('are issued when data was changed', () async {
|
||||
when(executor.runUpdate(any, any)).thenAnswer((_) => Future.value(3));
|
||||
|
||||
|
|
|
@ -80,25 +80,25 @@ class $TodosTable extends Todos implements TableInfo<Todos, TodoEntry> {
|
|||
targetDate.isAcceptableValue(instance.targetDate, isInserting) &&
|
||||
category.isAcceptableValue(instance.category, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
@override
|
||||
TodoEntry map(Map<String, dynamic> data) {
|
||||
return TodoEntry.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(TodoEntry d) {
|
||||
Map<String, Variable> entityToSql(TodoEntry d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.content != null) {
|
||||
if (d.content != null || includeNulls) {
|
||||
map['content'] = Variable<String, StringType>(d.content);
|
||||
}
|
||||
if (d.targetDate != null) {
|
||||
if (d.targetDate != null || includeNulls) {
|
||||
map['target_date'] = Variable<DateTime, DateTimeType>(d.targetDate);
|
||||
}
|
||||
if (d.category != null) {
|
||||
if (d.category != null || includeNulls) {
|
||||
map['category'] = Variable<int, IntType>(d.category);
|
||||
}
|
||||
return map;
|
||||
|
@ -152,19 +152,19 @@ class $CategoriesTable extends Categories
|
|||
id.isAcceptableValue(instance.id, isInserting) &&
|
||||
description.isAcceptableValue(instance.description, isInserting);
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => <GeneratedColumn>{};
|
||||
Set<GeneratedColumn> get $primaryKey => null;
|
||||
@override
|
||||
Category map(Map<String, dynamic> data) {
|
||||
return Category.fromData(data, _db);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, Variable> entityToSql(Category d) {
|
||||
Map<String, Variable> entityToSql(Category d, {bool includeNulls = false}) {
|
||||
final map = <String, Variable>{};
|
||||
if (d.id != null) {
|
||||
if (d.id != null || includeNulls) {
|
||||
map['id'] = Variable<int, IntType>(d.id);
|
||||
}
|
||||
if (d.description != null) {
|
||||
if (d.description != null || includeNulls) {
|
||||
map['`desc`'] = Variable<String, StringType>(d.description);
|
||||
}
|
||||
return map;
|
||||
|
|
|
@ -63,15 +63,16 @@ class TableWriter {
|
|||
}
|
||||
|
||||
void _writeReverseMappingMethod(StringBuffer buffer) {
|
||||
// Map<String, Variable> entityToSql(User d) {
|
||||
// Map<String, Variable> entityToSql(User d, {bool includeNulls = false) {
|
||||
buffer
|
||||
..write(
|
||||
'@override\nMap<String, Variable> entityToSql(${table.dartTypeName} d) {\n')
|
||||
'@override\nMap<String, Variable> entityToSql('
|
||||
'${table.dartTypeName} d, {bool includeNulls = false}) {\n')
|
||||
..write('final map = <String, Variable> {};');
|
||||
|
||||
for (var column in table.columns) {
|
||||
buffer.write('''
|
||||
if (d.${column.dartGetterName} != null) {
|
||||
if (d.${column.dartGetterName} != null || includeNulls) {
|
||||
map['${column.name.name}'] = Variable<${column.dartTypeName}, ${column.sqlTypeName}>(d.${column.dartGetterName});
|
||||
}
|
||||
''');
|
||||
|
@ -138,13 +139,20 @@ class TableWriter {
|
|||
|
||||
void _writePrimaryKeyOverride(StringBuffer buffer) {
|
||||
buffer.write('@override\nSet<GeneratedColumn> get \$primaryKey => ');
|
||||
if (table.primaryKey == null) {
|
||||
var primaryKey = table.primaryKey;
|
||||
|
||||
// If there is an auto increment column, that forms the primary key. The
|
||||
// PK returned by table.primaryKey only contains column that have been
|
||||
// explicitly defined as PK, but with AI this happens implicitly.
|
||||
primaryKey ??= table.columns.where((c) => c.hasAI).toSet();
|
||||
|
||||
if (primaryKey == null) {
|
||||
buffer.write('null;');
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.write('{');
|
||||
final pkList = table.primaryKey.toList();
|
||||
final pkList = primaryKey.toList();
|
||||
for (var i = 0; i < pkList.length; i++) {
|
||||
final pk = pkList[i];
|
||||
|
||||
|
|
Loading…
Reference in New Issue