mirror of https://github.com/AMT-Cheif/drift.git
Merge pull request #1473 from Ali1Ammar/develop
implements where for DoUpdate
This commit is contained in:
commit
853e80754d
|
@ -1,6 +1,7 @@
|
||||||
## 4.6.0-dev
|
## 4.6.0-dev
|
||||||
|
|
||||||
- Add `DoUpdate.withExcluded` to refer to the excluded row in an upsert clause.
|
- Add `DoUpdate.withExcluded` to refer to the excluded row in an upsert clause.
|
||||||
|
- Add optional `where` clause to `DoUpdate` constructors
|
||||||
|
|
||||||
## 4.5.0
|
## 4.5.0
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,13 @@ class InsertStatement<T extends Table, D> {
|
||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onConflict._where != null) {
|
||||||
|
ctx.writeWhitespace();
|
||||||
|
final where = onConflict._where!(
|
||||||
|
table.asDslTable, table.createAlias('excluded').asDslTable);
|
||||||
|
where.writeInto(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onConflict is DoUpdate<T, D>) {
|
if (onConflict is DoUpdate<T, D>) {
|
||||||
|
@ -301,6 +308,8 @@ abstract class UpsertClause<T extends Table, D> {}
|
||||||
/// For an example, see [InsertStatement.insert].
|
/// For an example, see [InsertStatement.insert].
|
||||||
class DoUpdate<T extends Table, D> extends UpsertClause<T, D> {
|
class DoUpdate<T extends Table, D> extends UpsertClause<T, D> {
|
||||||
final Insertable<D> Function(T old, T excluded) _creator;
|
final Insertable<D> Function(T old, T excluded) _creator;
|
||||||
|
final Where Function(T old, T excluded)? _where;
|
||||||
|
|
||||||
final bool _usesExcludedTable;
|
final bool _usesExcludedTable;
|
||||||
|
|
||||||
/// An optional list of columns to serve as an "conflict target", which
|
/// An optional list of columns to serve as an "conflict target", which
|
||||||
|
@ -316,9 +325,15 @@ class DoUpdate<T extends Table, D> extends UpsertClause<T, D> {
|
||||||
/// If you need to refer to both the old row and the row that would have
|
/// If you need to refer to both the old row and the row that would have
|
||||||
/// been inserted, use [DoUpdate.withExcluded].
|
/// been inserted, use [DoUpdate.withExcluded].
|
||||||
///
|
///
|
||||||
|
/// The optional [where] clause can be used to disable the update based on
|
||||||
|
/// the old value. If a [where] clause is set and it evaluates to false, a
|
||||||
|
/// conflict will keep the old row without applying the update.
|
||||||
|
///
|
||||||
/// For an example, see [InsertStatement.insert].
|
/// For an example, see [InsertStatement.insert].
|
||||||
DoUpdate(Insertable<D> Function(T old) update, {this.target})
|
DoUpdate(Insertable<D> Function(T old) update,
|
||||||
|
{this.target, Expression<bool?> Function(T old)? where})
|
||||||
: _creator = ((old, _) => update(old)),
|
: _creator = ((old, _) => update(old)),
|
||||||
|
_where = where == null ? null : ((old, _) => Where(where(old))),
|
||||||
_usesExcludedTable = false;
|
_usesExcludedTable = false;
|
||||||
|
|
||||||
/// Creates a `DO UPDATE` clause.
|
/// Creates a `DO UPDATE` clause.
|
||||||
|
@ -329,9 +344,17 @@ class DoUpdate<T extends Table, D> extends UpsertClause<T, D> {
|
||||||
/// to columns in the row that couldn't be inserted with the `excluded`
|
/// to columns in the row that couldn't be inserted with the `excluded`
|
||||||
/// parameter.
|
/// parameter.
|
||||||
///
|
///
|
||||||
|
/// The optional [where] clause can be used to disable the update based on
|
||||||
|
/// the old value. If a [where] clause is set and it evaluates to false, a
|
||||||
|
/// conflict will keep the old row without applying the update.
|
||||||
|
///
|
||||||
/// For an example, see [InsertStatement.insert].
|
/// For an example, see [InsertStatement.insert].
|
||||||
DoUpdate.withExcluded(this._creator, {this.target})
|
DoUpdate.withExcluded(this._creator,
|
||||||
: _usesExcludedTable = true;
|
{this.target, Expression<bool?> Function(T old, T excluded)? where})
|
||||||
|
: _usesExcludedTable = true,
|
||||||
|
_where = where == null
|
||||||
|
? null
|
||||||
|
: ((old, excluded) => Where(where(old, excluded)));
|
||||||
|
|
||||||
Insertable<D> _createInsertable(TableInfo<T, D> table) {
|
Insertable<D> _createInsertable(TableInfo<T, D> table) {
|
||||||
return _creator(table.asDslTable, table.createAlias('excluded').asDslTable);
|
return _creator(table.asDslTable, table.createAlias('excluded').asDslTable);
|
||||||
|
|
|
@ -205,6 +205,23 @@ void main() {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('can use an upsert clause with where', () async {
|
||||||
|
await db.into(db.todosTable).insert(
|
||||||
|
TodosTableCompanion.insert(content: 'my content'),
|
||||||
|
onConflict: DoUpdate((old) {
|
||||||
|
return TodosTableCompanion.custom(
|
||||||
|
content: const Variable('important: ') + old.content);
|
||||||
|
}, where: (old) => old.category.equals(1)),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(executor.runInsert(
|
||||||
|
'INSERT INTO todos (content) VALUES (?) '
|
||||||
|
'ON CONFLICT(id) DO UPDATE SET content = ? || content '
|
||||||
|
'WHERE category = ?',
|
||||||
|
argThat(equals(['my content', 'important: ', 1])),
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'can use multiple upsert targets',
|
'can use multiple upsert targets',
|
||||||
() async {
|
() async {
|
||||||
|
@ -236,6 +253,36 @@ void main() {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'can use multiple upsert targets with where',
|
||||||
|
() async {
|
||||||
|
await db
|
||||||
|
.into(db.todosTable)
|
||||||
|
.insert(TodosTableCompanion.insert(content: 'my content'),
|
||||||
|
onConflict: UpsertMultiple([
|
||||||
|
DoUpdate((old) {
|
||||||
|
return TodosTableCompanion.custom(
|
||||||
|
content: const Variable('important: ') + old.content);
|
||||||
|
}, where: (old) => old.category.equals(1)),
|
||||||
|
DoUpdate((old) {
|
||||||
|
return TodosTableCompanion.custom(
|
||||||
|
content: const Variable('second: ') + old.content);
|
||||||
|
},
|
||||||
|
target: [db.todosTable.content],
|
||||||
|
where: (old) => old.category.equals(1)),
|
||||||
|
]));
|
||||||
|
|
||||||
|
verify(executor.runInsert(
|
||||||
|
'INSERT INTO todos (content) VALUES (?) '
|
||||||
|
'ON CONFLICT(id) DO UPDATE SET content = ? || content '
|
||||||
|
'WHERE category = ? '
|
||||||
|
'ON CONFLICT(content) DO UPDATE SET content = ? || content '
|
||||||
|
'WHERE category = ?',
|
||||||
|
argThat(equals(['my content', 'important: ', 1, 'second: ', 1])),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test('can use a custom conflict clause', () async {
|
test('can use a custom conflict clause', () async {
|
||||||
await db.into(db.todosTable).insert(
|
await db.into(db.todosTable).insert(
|
||||||
TodosTableCompanion.insert(content: 'my content'),
|
TodosTableCompanion.insert(content: 'my content'),
|
||||||
|
@ -252,6 +299,23 @@ void main() {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('can use a custom conflict clause with where', () async {
|
||||||
|
await db.into(db.todosTable).insert(
|
||||||
|
TodosTableCompanion.insert(content: 'my content'),
|
||||||
|
onConflict: DoUpdate(
|
||||||
|
(old) => TodosTableCompanion.insert(content: 'changed'),
|
||||||
|
target: [db.todosTable.content],
|
||||||
|
where: (old) => old.content.equalsExp(old.title)),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(executor.runInsert(
|
||||||
|
'INSERT INTO todos (content) VALUES (?) '
|
||||||
|
'ON CONFLICT(content) DO UPDATE SET content = ? '
|
||||||
|
'WHERE content = title',
|
||||||
|
argThat(equals(['my content', 'changed'])),
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
test('insertOnConflictUpdate', () async {
|
test('insertOnConflictUpdate', () async {
|
||||||
when(executor.runInsert(any, any)).thenAnswer((_) => Future.value(3));
|
when(executor.runInsert(any, any)).thenAnswer((_) => Future.value(3));
|
||||||
|
|
||||||
|
@ -284,6 +348,25 @@ void main() {
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('can access excluded row in upsert with where', () async {
|
||||||
|
await db.into(db.todosTable).insert(
|
||||||
|
TodosTableCompanion.insert(content: 'content'),
|
||||||
|
onConflict: DoUpdate.withExcluded(
|
||||||
|
(old, excluded) => TodosTableCompanion.custom(
|
||||||
|
content: old.content + excluded.content,
|
||||||
|
),
|
||||||
|
where: (old, excluded) => old.title.equalsExp(excluded.title)),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(executor.runInsert(
|
||||||
|
'INSERT INTO todos (content) VALUES (?) '
|
||||||
|
'ON CONFLICT(id) DO UPDATE '
|
||||||
|
'SET content = todos.content || excluded.content '
|
||||||
|
'WHERE todos.title = excluded.title',
|
||||||
|
['content'],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
test('applies implicit type converter', () async {
|
test('applies implicit type converter', () async {
|
||||||
await db.into(db.categories).insert(CategoriesCompanion.insert(
|
await db.into(db.categories).insert(CategoriesCompanion.insert(
|
||||||
description: 'description',
|
description: 'description',
|
||||||
|
|
|
@ -47,6 +47,56 @@ void main() {
|
||||||
expect(row.description, 'original description new description');
|
expect(row.description, 'original description new description');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('insert with DoUpdate and excluded row and where statement true',
|
||||||
|
() async {
|
||||||
|
await db.into(db.categories).insert(
|
||||||
|
CategoriesCompanion.insert(description: 'original description'));
|
||||||
|
|
||||||
|
var row = await db.select(db.categories).getSingle();
|
||||||
|
|
||||||
|
await db.into(db.categories).insert(
|
||||||
|
CategoriesCompanion(
|
||||||
|
id: Value(row.id),
|
||||||
|
priority: const Value(CategoryPriority.medium),
|
||||||
|
description: const Value('new description'),
|
||||||
|
),
|
||||||
|
onConflict: DoUpdate.withExcluded(
|
||||||
|
(old, excluded) => CategoriesCompanion.custom(
|
||||||
|
description: old.description +
|
||||||
|
const Constant(' ') +
|
||||||
|
excluded.description),
|
||||||
|
where: (old, excluded) =>
|
||||||
|
old.priority.isBiggerOrEqual(excluded.priority)));
|
||||||
|
|
||||||
|
row = await db.select(db.categories).getSingle();
|
||||||
|
expect(row.description, 'original description');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('insert with DoUpdate and excluded row and where statement false',
|
||||||
|
() async {
|
||||||
|
await db.into(db.categories).insert(
|
||||||
|
CategoriesCompanion.insert(description: 'original description'));
|
||||||
|
|
||||||
|
var row = await db.select(db.categories).getSingle();
|
||||||
|
|
||||||
|
await db.into(db.categories).insert(
|
||||||
|
CategoriesCompanion(
|
||||||
|
id: Value(row.id),
|
||||||
|
priority: const Value(CategoryPriority.low),
|
||||||
|
description: const Value('new description'),
|
||||||
|
),
|
||||||
|
onConflict: DoUpdate.withExcluded(
|
||||||
|
(old, excluded) => CategoriesCompanion.custom(
|
||||||
|
description: old.description +
|
||||||
|
const Constant(' ') +
|
||||||
|
excluded.description),
|
||||||
|
where: (old, excluded) =>
|
||||||
|
old.priority.isBiggerOrEqual(excluded.priority)));
|
||||||
|
|
||||||
|
row = await db.select(db.categories).getSingle();
|
||||||
|
expect(row.description, 'original description new description');
|
||||||
|
});
|
||||||
|
|
||||||
test('returning', () async {
|
test('returning', () async {
|
||||||
final entry = await db.into(db.categories).insertReturning(
|
final entry = await db.into(db.categories).insertReturning(
|
||||||
CategoriesCompanion.insert(description: 'Description'));
|
CategoriesCompanion.insert(description: 'Description'));
|
||||||
|
|
Loading…
Reference in New Issue