mirror of https://github.com/AMT-Cheif/drift.git
Add example with upsert conflict target to docs
This commit is contained in:
parent
2ac81ddb99
commit
407a40fae1
|
@ -0,0 +1,54 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/internal/modular.dart';
|
||||
|
||||
import 'upserts.drift.dart';
|
||||
|
||||
// #docregion words-table
|
||||
class Words extends Table {
|
||||
TextColumn get word => text()();
|
||||
IntColumn get usages => integer().withDefault(const Constant(1))();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {word};
|
||||
}
|
||||
// #enddocregion words-table
|
||||
|
||||
// #docregion upsert-target
|
||||
class MatchResults extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
TextColumn get teamA => text()();
|
||||
TextColumn get teamB => text()();
|
||||
BoolColumn get teamAWon => boolean()();
|
||||
|
||||
@override
|
||||
List<Set<Column<Object>>>? get uniqueKeys => [
|
||||
{teamA, teamB}
|
||||
];
|
||||
}
|
||||
// #enddocregion upsert-target
|
||||
|
||||
extension DocumentationSnippets on ModularAccessor {
|
||||
$WordsTable get words => throw 'stub';
|
||||
$MatchResultsTable get matches => throw 'stub';
|
||||
|
||||
// #docregion track-word
|
||||
Future<void> trackWord(String word) {
|
||||
return into(words).insert(
|
||||
WordsCompanion.insert(word: word),
|
||||
onConflict: DoUpdate(
|
||||
(old) => WordsCompanion.custom(usages: old.usages + Constant(1))),
|
||||
);
|
||||
}
|
||||
// #enddocregion track-word
|
||||
|
||||
// #docregion upsert-target
|
||||
Future<void> insertMatch(String teamA, String teamB, bool teamAWon) {
|
||||
final data = MatchResultsCompanion.insert(
|
||||
teamA: teamA, teamB: teamB, teamAWon: teamAWon);
|
||||
|
||||
return into(matches).insert(data,
|
||||
onConflict:
|
||||
DoUpdate((old) => data, target: [matches.teamA, matches.teamB]));
|
||||
}
|
||||
// #enddocregion upsert-target
|
||||
}
|
|
@ -0,0 +1,446 @@
|
|||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:drift_docs/snippets/modular/upserts.drift.dart' as i1;
|
||||
import 'package:drift_docs/snippets/modular/upserts.dart' as i2;
|
||||
import 'package:drift/src/runtime/query_builder/query_builder.dart' as i3;
|
||||
|
||||
class $WordsTable extends i2.Words with i0.TableInfo<$WordsTable, i1.Word> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$WordsTable(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _wordMeta =
|
||||
const i0.VerificationMeta('word');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> word = i0.GeneratedColumn<String>(
|
||||
'word', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const i0.VerificationMeta _usagesMeta =
|
||||
const i0.VerificationMeta('usages');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> usages = i0.GeneratedColumn<int>(
|
||||
'usages', aliasedName, false,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const i3.Constant(1));
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [word, usages];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'words';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(i0.Insertable<i1.Word> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = i0.VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('word')) {
|
||||
context.handle(
|
||||
_wordMeta, word.isAcceptableOrUnknown(data['word']!, _wordMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_wordMeta);
|
||||
}
|
||||
if (data.containsKey('usages')) {
|
||||
context.handle(_usagesMeta,
|
||||
usages.isAcceptableOrUnknown(data['usages']!, _usagesMeta));
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {word};
|
||||
@override
|
||||
i1.Word map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.Word(
|
||||
word: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}word'])!,
|
||||
usages: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}usages'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$WordsTable createAlias(String alias) {
|
||||
return $WordsTable(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Word extends i0.DataClass implements i0.Insertable<i1.Word> {
|
||||
final String word;
|
||||
final int usages;
|
||||
const Word({required this.word, required this.usages});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['word'] = i0.Variable<String>(word);
|
||||
map['usages'] = i0.Variable<int>(usages);
|
||||
return map;
|
||||
}
|
||||
|
||||
i1.WordsCompanion toCompanion(bool nullToAbsent) {
|
||||
return i1.WordsCompanion(
|
||||
word: i0.Value(word),
|
||||
usages: i0.Value(usages),
|
||||
);
|
||||
}
|
||||
|
||||
factory Word.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return Word(
|
||||
word: serializer.fromJson<String>(json['word']),
|
||||
usages: serializer.fromJson<int>(json['usages']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'word': serializer.toJson<String>(word),
|
||||
'usages': serializer.toJson<int>(usages),
|
||||
};
|
||||
}
|
||||
|
||||
i1.Word copyWith({String? word, int? usages}) => i1.Word(
|
||||
word: word ?? this.word,
|
||||
usages: usages ?? this.usages,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('Word(')
|
||||
..write('word: $word, ')
|
||||
..write('usages: $usages')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(word, usages);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.Word &&
|
||||
other.word == this.word &&
|
||||
other.usages == this.usages);
|
||||
}
|
||||
|
||||
class WordsCompanion extends i0.UpdateCompanion<i1.Word> {
|
||||
final i0.Value<String> word;
|
||||
final i0.Value<int> usages;
|
||||
final i0.Value<int> rowid;
|
||||
const WordsCompanion({
|
||||
this.word = const i0.Value.absent(),
|
||||
this.usages = const i0.Value.absent(),
|
||||
this.rowid = const i0.Value.absent(),
|
||||
});
|
||||
WordsCompanion.insert({
|
||||
required String word,
|
||||
this.usages = const i0.Value.absent(),
|
||||
this.rowid = const i0.Value.absent(),
|
||||
}) : word = i0.Value(word);
|
||||
static i0.Insertable<i1.Word> custom({
|
||||
i0.Expression<String>? word,
|
||||
i0.Expression<int>? usages,
|
||||
i0.Expression<int>? rowid,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (word != null) 'word': word,
|
||||
if (usages != null) 'usages': usages,
|
||||
if (rowid != null) 'rowid': rowid,
|
||||
});
|
||||
}
|
||||
|
||||
i1.WordsCompanion copyWith(
|
||||
{i0.Value<String>? word, i0.Value<int>? usages, i0.Value<int>? rowid}) {
|
||||
return i1.WordsCompanion(
|
||||
word: word ?? this.word,
|
||||
usages: usages ?? this.usages,
|
||||
rowid: rowid ?? this.rowid,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (word.present) {
|
||||
map['word'] = i0.Variable<String>(word.value);
|
||||
}
|
||||
if (usages.present) {
|
||||
map['usages'] = i0.Variable<int>(usages.value);
|
||||
}
|
||||
if (rowid.present) {
|
||||
map['rowid'] = i0.Variable<int>(rowid.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('WordsCompanion(')
|
||||
..write('word: $word, ')
|
||||
..write('usages: $usages, ')
|
||||
..write('rowid: $rowid')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class $MatchResultsTable extends i2.MatchResults
|
||||
with i0.TableInfo<$MatchResultsTable, i1.MatchResult> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$MatchResultsTable(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> id = i0.GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
i0.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
static const i0.VerificationMeta _teamAMeta =
|
||||
const i0.VerificationMeta('teamA');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> teamA = i0.GeneratedColumn<String>(
|
||||
'team_a', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const i0.VerificationMeta _teamBMeta =
|
||||
const i0.VerificationMeta('teamB');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> teamB = i0.GeneratedColumn<String>(
|
||||
'team_b', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
static const i0.VerificationMeta _teamAWonMeta =
|
||||
const i0.VerificationMeta('teamAWon');
|
||||
@override
|
||||
late final i0.GeneratedColumn<bool> teamAWon = i0.GeneratedColumn<bool>(
|
||||
'team_a_won', aliasedName, false,
|
||||
type: i0.DriftSqlType.bool,
|
||||
requiredDuringInsert: true,
|
||||
defaultConstraints: i0.GeneratedColumn.constraintIsAlways(
|
||||
'CHECK ("team_a_won" IN (0, 1))'));
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [id, teamA, teamB, teamAWon];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'match_results';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.MatchResult> instance,
|
||||
{bool isInserting = false}) {
|
||||
final context = i0.VerificationContext();
|
||||
final data = instance.toColumns(true);
|
||||
if (data.containsKey('id')) {
|
||||
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||
}
|
||||
if (data.containsKey('team_a')) {
|
||||
context.handle(
|
||||
_teamAMeta, teamA.isAcceptableOrUnknown(data['team_a']!, _teamAMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_teamAMeta);
|
||||
}
|
||||
if (data.containsKey('team_b')) {
|
||||
context.handle(
|
||||
_teamBMeta, teamB.isAcceptableOrUnknown(data['team_b']!, _teamBMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_teamBMeta);
|
||||
}
|
||||
if (data.containsKey('team_a_won')) {
|
||||
context.handle(_teamAWonMeta,
|
||||
teamAWon.isAcceptableOrUnknown(data['team_a_won']!, _teamAWonMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_teamAWonMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
List<Set<i0.GeneratedColumn>> get uniqueKeys => [
|
||||
{teamA, teamB},
|
||||
];
|
||||
@override
|
||||
i1.MatchResult map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.MatchResult(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!,
|
||||
teamA: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}team_a'])!,
|
||||
teamB: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}team_b'])!,
|
||||
teamAWon: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.bool, data['${effectivePrefix}team_a_won'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$MatchResultsTable createAlias(String alias) {
|
||||
return $MatchResultsTable(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class MatchResult extends i0.DataClass
|
||||
implements i0.Insertable<i1.MatchResult> {
|
||||
final int id;
|
||||
final String teamA;
|
||||
final String teamB;
|
||||
final bool teamAWon;
|
||||
const MatchResult(
|
||||
{required this.id,
|
||||
required this.teamA,
|
||||
required this.teamB,
|
||||
required this.teamAWon});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<int>(id);
|
||||
map['team_a'] = i0.Variable<String>(teamA);
|
||||
map['team_b'] = i0.Variable<String>(teamB);
|
||||
map['team_a_won'] = i0.Variable<bool>(teamAWon);
|
||||
return map;
|
||||
}
|
||||
|
||||
i1.MatchResultsCompanion toCompanion(bool nullToAbsent) {
|
||||
return i1.MatchResultsCompanion(
|
||||
id: i0.Value(id),
|
||||
teamA: i0.Value(teamA),
|
||||
teamB: i0.Value(teamB),
|
||||
teamAWon: i0.Value(teamAWon),
|
||||
);
|
||||
}
|
||||
|
||||
factory MatchResult.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return MatchResult(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
teamA: serializer.fromJson<String>(json['teamA']),
|
||||
teamB: serializer.fromJson<String>(json['teamB']),
|
||||
teamAWon: serializer.fromJson<bool>(json['teamAWon']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'teamA': serializer.toJson<String>(teamA),
|
||||
'teamB': serializer.toJson<String>(teamB),
|
||||
'teamAWon': serializer.toJson<bool>(teamAWon),
|
||||
};
|
||||
}
|
||||
|
||||
i1.MatchResult copyWith(
|
||||
{int? id, String? teamA, String? teamB, bool? teamAWon}) =>
|
||||
i1.MatchResult(
|
||||
id: id ?? this.id,
|
||||
teamA: teamA ?? this.teamA,
|
||||
teamB: teamB ?? this.teamB,
|
||||
teamAWon: teamAWon ?? this.teamAWon,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('MatchResult(')
|
||||
..write('id: $id, ')
|
||||
..write('teamA: $teamA, ')
|
||||
..write('teamB: $teamB, ')
|
||||
..write('teamAWon: $teamAWon')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, teamA, teamB, teamAWon);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.MatchResult &&
|
||||
other.id == this.id &&
|
||||
other.teamA == this.teamA &&
|
||||
other.teamB == this.teamB &&
|
||||
other.teamAWon == this.teamAWon);
|
||||
}
|
||||
|
||||
class MatchResultsCompanion extends i0.UpdateCompanion<i1.MatchResult> {
|
||||
final i0.Value<int> id;
|
||||
final i0.Value<String> teamA;
|
||||
final i0.Value<String> teamB;
|
||||
final i0.Value<bool> teamAWon;
|
||||
const MatchResultsCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.teamA = const i0.Value.absent(),
|
||||
this.teamB = const i0.Value.absent(),
|
||||
this.teamAWon = const i0.Value.absent(),
|
||||
});
|
||||
MatchResultsCompanion.insert({
|
||||
this.id = const i0.Value.absent(),
|
||||
required String teamA,
|
||||
required String teamB,
|
||||
required bool teamAWon,
|
||||
}) : teamA = i0.Value(teamA),
|
||||
teamB = i0.Value(teamB),
|
||||
teamAWon = i0.Value(teamAWon);
|
||||
static i0.Insertable<i1.MatchResult> custom({
|
||||
i0.Expression<int>? id,
|
||||
i0.Expression<String>? teamA,
|
||||
i0.Expression<String>? teamB,
|
||||
i0.Expression<bool>? teamAWon,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (teamA != null) 'team_a': teamA,
|
||||
if (teamB != null) 'team_b': teamB,
|
||||
if (teamAWon != null) 'team_a_won': teamAWon,
|
||||
});
|
||||
}
|
||||
|
||||
i1.MatchResultsCompanion copyWith(
|
||||
{i0.Value<int>? id,
|
||||
i0.Value<String>? teamA,
|
||||
i0.Value<String>? teamB,
|
||||
i0.Value<bool>? teamAWon}) {
|
||||
return i1.MatchResultsCompanion(
|
||||
id: id ?? this.id,
|
||||
teamA: teamA ?? this.teamA,
|
||||
teamB: teamB ?? this.teamB,
|
||||
teamAWon: teamAWon ?? this.teamAWon,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<int>(id.value);
|
||||
}
|
||||
if (teamA.present) {
|
||||
map['team_a'] = i0.Variable<String>(teamA.value);
|
||||
}
|
||||
if (teamB.present) {
|
||||
map['team_b'] = i0.Variable<String>(teamB.value);
|
||||
}
|
||||
if (teamAWon.present) {
|
||||
map['team_a_won'] = i0.Variable<bool>(teamAWon.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('MatchResultsCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('teamA: $teamA, ')
|
||||
..write('teamB: $teamB, ')
|
||||
..write('teamAWon: $teamAWon')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -109,7 +109,9 @@ This makes them suitable for bulk insert or update operations.
|
|||
|
||||
### Upserts
|
||||
|
||||
Upserts are a feature from newer sqlite3 versions that allows an insert to
|
||||
{% assign upserts = "package:drift_docs/snippets/modular/upserts.dart.excerpt.json" | readString | json_decode %}
|
||||
|
||||
Upserts are a feature from newer sqlite3 versions that allows an insert to
|
||||
behave like an update if a conflicting row already exists.
|
||||
|
||||
This allows us to create or override an existing row when its primary key is
|
||||
|
@ -129,35 +131,20 @@ Future<int> createOrUpdateUser(User user) {
|
|||
}
|
||||
```
|
||||
|
||||
When calling `createOrUpdateUser()` with an email address that already exists,
|
||||
When calling `createOrUpdateUser()` with an email address that already exists,
|
||||
that user's name will be updated. Otherwise, a new user will be inserted into
|
||||
the database.
|
||||
|
||||
Inserts can also be used with more advanced queries. For instance, let's say
|
||||
we're building a dictionary and want to keep track of how many times we
|
||||
Inserts can also be used with more advanced queries. For instance, let's say
|
||||
we're building a dictionary and want to keep track of how many times we
|
||||
encountered a word. A table for that might look like
|
||||
|
||||
```dart
|
||||
class Words extends Table {
|
||||
TextColumn get word => text()();
|
||||
IntColumn get usages => integer().withDefault(const Constant(1))();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {word};
|
||||
}
|
||||
```
|
||||
{% include "blocks/snippet" snippets = upserts name = "words-table" %}
|
||||
|
||||
By using a custom upserts, we can insert a new word or increment its `usages`
|
||||
counter if it already exists:
|
||||
|
||||
```dart
|
||||
Future<void> trackWord(String word) {
|
||||
return into(words).insert(
|
||||
WordsCompanion.insert(word: word),
|
||||
onConflict: DoUpdate((old) => WordsCompanion.custom(usages: old.usages + Constant(1))),
|
||||
);
|
||||
}
|
||||
```
|
||||
{% include "blocks/snippet" snippets = upserts name = "track-word" %}
|
||||
|
||||
{% block "blocks/alert" title="Unique constraints and conflict targets" %}
|
||||
Both `insertOnConflictUpdate` and `onConflict: DoUpdate` use an `DO UPDATE`
|
||||
|
@ -165,7 +152,10 @@ upsert in sql. This requires us to provide a so-called "conflict target", a
|
|||
set of columns to check for uniqueness violations. By default, drift will use
|
||||
the table's primary key as conflict target. That works in most cases, but if
|
||||
you have custom `UNIQUE` constraints on some columns, you'll need to use
|
||||
the `target` parameter on `DoUpdate` in Dart to include those columns.
|
||||
the `target` parameter on `DoUpdate` in Dart to include those columns:
|
||||
|
||||
{% include "blocks/snippet" snippets = upserts name = "upsert-target" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
Note that this requires a fairly recent sqlite3 version (3.24.0) that might not
|
||||
|
|
Loading…
Reference in New Issue