feat(todo): the sync engine and Todo's first models (ADR 0033, D5, D6)
Todo's server syncs with serverpod_offline_sync as Learn's and Train's do, and holds two synced tables, every payload sealed on the devices: content_key (the person's data key, sealed to the account) and project (the Inbox or one of the person's own, changed when edited). A person's space goes with them, with everything in it. The migration only adds: the two tables, each indexed on spaceId and cascading with its space (ON DELETE CASCADE to offline_sync_spaces), the sync engine's own tables (crdt_*, offline_sync_*) with their foreign keys, the gen_random_uuid_v7() function their ids default to, and the modules' version rows. Nothing is dropped or changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
492c657980
commit
3876e30681
1 changed files with 28530 additions and 5 deletions
|
|
@ -0,0 +1,647 @@
|
|||
/* AUTOMATICALLY GENERATED CODE DO NOT MODIFY */
|
||||
/* To generate run: "serverpod generate" */
|
||||
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: library_private_types_in_public_api
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
// ignore_for_file: public_member_api_docs
|
||||
// ignore_for_file: type_literal_in_constant_pattern
|
||||
// ignore_for_file: use_super_parameters
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:typed_data' as _idt;
|
||||
import 'package:serverpod_client/serverpod_client.dart' as _isc;
|
||||
import 'package:serverpod_database/serverpod_database.dart' as _isd;
|
||||
|
||||
/// A data key of the person's (ADR 0033, D5, as Train's ADR 0030, D15): the
|
||||
/// one their projects, tasks and labels are sealed with. Sealed on a device
|
||||
/// to the account's X25519 key and signed by it (halkyon_keys'
|
||||
/// `sealDataKey`), under an ID that says what it is for, so only the
|
||||
/// person's devices open it and the instance can't relabel it; the instance
|
||||
/// keeps it as it is. Synced, so the key arrives with the data, works offline
|
||||
/// and goes with the space. Never updated.
|
||||
abstract class ContentKey
|
||||
implements _isd.TableRow<_isc.UuidValue?>, _isc.ProtocolSerialization {
|
||||
ContentKey._({
|
||||
this.id,
|
||||
this.spaceId,
|
||||
required this.dataKeyId,
|
||||
required this.sealedKey,
|
||||
});
|
||||
|
||||
factory ContentKey({
|
||||
_isc.UuidValue? id,
|
||||
int? spaceId,
|
||||
required String dataKeyId,
|
||||
required _idt.ByteData sealedKey,
|
||||
}) = _ContentKeyImpl;
|
||||
|
||||
factory ContentKey.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return ContentKey(
|
||||
id: jsonSerialization['id'] == null
|
||||
? null
|
||||
: _isc.UuidValueJsonExtension.fromJson(jsonSerialization['id']),
|
||||
spaceId: jsonSerialization['spaceId'] as int?,
|
||||
dataKeyId: jsonSerialization['dataKeyId'] as String,
|
||||
sealedKey: _isc.ByteDataJsonExtension.fromJson(
|
||||
jsonSerialization['sealedKey'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static final t = ContentKeyTable();
|
||||
|
||||
static const db = ContentKeyRepository._();
|
||||
|
||||
@override
|
||||
_isc.UuidValue? id;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
int? spaceId;
|
||||
|
||||
/// The key's ID, which the rows it seals name in their `keyId`; sealed
|
||||
/// with the key too, so the column is never trusted.
|
||||
String dataKeyId;
|
||||
|
||||
/// The sealed key: the sealer's Ed25519 signature, then the sealed box.
|
||||
_idt.ByteData sealedKey;
|
||||
|
||||
@override
|
||||
_isd.Table<_isc.UuidValue?> get table => t;
|
||||
|
||||
/// Returns a shallow copy of this [ContentKey]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
ContentKey copyWith({
|
||||
_isc.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? dataKeyId,
|
||||
_idt.ByteData? sealedKey,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'ContentKey',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
'dataKeyId': dataKeyId,
|
||||
'sealedKey': sealedKey.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'ContentKey',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
'dataKeyId': dataKeyId,
|
||||
'sealedKey': sealedKey.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
static ContentKeyInclude include() {
|
||||
return ContentKeyInclude._();
|
||||
}
|
||||
|
||||
static ContentKeyIncludeList includeList({
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<ContentKeyTable>? orderBy,
|
||||
_isd.OrderByListBuilder<ContentKeyTable>? orderByList,
|
||||
ContentKeyInclude? include,
|
||||
}) {
|
||||
return ContentKeyIncludeList._(
|
||||
where: where,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(ContentKey.t),
|
||||
orderByList: orderByList?.call(ContentKey.t),
|
||||
include: include,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _isc.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _ContentKeyImpl extends ContentKey {
|
||||
_ContentKeyImpl({
|
||||
_isc.UuidValue? id,
|
||||
int? spaceId,
|
||||
required String dataKeyId,
|
||||
required _idt.ByteData sealedKey,
|
||||
}) : super._(
|
||||
id: id,
|
||||
spaceId: spaceId,
|
||||
dataKeyId: dataKeyId,
|
||||
sealedKey: sealedKey,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [ContentKey]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_isc.useResult
|
||||
@override
|
||||
ContentKey copyWith({
|
||||
Object? id = _Undefined,
|
||||
Object? spaceId = _Undefined,
|
||||
String? dataKeyId,
|
||||
_idt.ByteData? sealedKey,
|
||||
}) {
|
||||
return ContentKey(
|
||||
id: id is _isc.UuidValue? ? id : this.id,
|
||||
spaceId: spaceId is int? ? spaceId : this.spaceId,
|
||||
dataKeyId: dataKeyId ?? this.dataKeyId,
|
||||
sealedKey: sealedKey ?? this.sealedKey.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ContentKeyUpdateTable extends _isd.UpdateTable<ContentKeyTable> {
|
||||
ContentKeyUpdateTable(super.table);
|
||||
|
||||
_isd.ColumnValue<int, int> spaceId(int? value) => _isd.ColumnValue(
|
||||
table.spaceId,
|
||||
value,
|
||||
);
|
||||
|
||||
_isd.ColumnValue<String, String> dataKeyId(String value) => _isd.ColumnValue(
|
||||
table.dataKeyId,
|
||||
value,
|
||||
);
|
||||
|
||||
_isd.ColumnValue<_idt.ByteData, _idt.ByteData> sealedKey(
|
||||
_idt.ByteData value,
|
||||
) => _isd.ColumnValue(
|
||||
table.sealedKey,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
class ContentKeyTable extends _isd.Table<_isc.UuidValue?> {
|
||||
ContentKeyTable({super.tableRelation}) : super(tableName: 'content_key') {
|
||||
updateTable = ContentKeyUpdateTable(this);
|
||||
spaceId = _isd.ColumnInt(
|
||||
'spaceId',
|
||||
this,
|
||||
);
|
||||
dataKeyId = _isd.ColumnString(
|
||||
'dataKeyId',
|
||||
this,
|
||||
);
|
||||
sealedKey = _isd.ColumnByteData(
|
||||
'sealedKey',
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
late final ContentKeyUpdateTable updateTable;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
late final _isd.ColumnInt spaceId;
|
||||
|
||||
/// The key's ID, which the rows it seals name in their `keyId`; sealed
|
||||
/// with the key too, so the column is never trusted.
|
||||
late final _isd.ColumnString dataKeyId;
|
||||
|
||||
/// The sealed key: the sealer's Ed25519 signature, then the sealed box.
|
||||
late final _isd.ColumnByteData sealedKey;
|
||||
|
||||
@override
|
||||
List<_isd.Column> get columns => [
|
||||
id,
|
||||
spaceId,
|
||||
dataKeyId,
|
||||
sealedKey,
|
||||
];
|
||||
}
|
||||
|
||||
class ContentKeyInclude extends _isd.IncludeObject {
|
||||
ContentKeyInclude._();
|
||||
|
||||
@override
|
||||
Map<String, _isd.Include?> get includes => {};
|
||||
|
||||
@override
|
||||
_isd.Table<_isc.UuidValue?> get table => ContentKey.t;
|
||||
}
|
||||
|
||||
class ContentKeyIncludeList extends _isd.IncludeList {
|
||||
ContentKeyIncludeList._({
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? where,
|
||||
super.limit,
|
||||
super.offset,
|
||||
super.orderBy,
|
||||
super.orderByList,
|
||||
super.include,
|
||||
}) {
|
||||
super.where = where?.call(ContentKey.t);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, _isd.Include?> get includes => include?.includes ?? {};
|
||||
|
||||
@override
|
||||
_isd.Table<_isc.UuidValue?> get table => ContentKey.t;
|
||||
}
|
||||
|
||||
class ContentKeyRepository {
|
||||
const ContentKeyRepository._();
|
||||
|
||||
/// Returns a list of [ContentKey]s matching the given query parameters.
|
||||
///
|
||||
/// Use [where] to specify which items to include in the return value.
|
||||
/// If none is specified, all items will be returned.
|
||||
///
|
||||
/// To specify the order of the items use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// The maximum number of items can be set by [limit]. If no limit is set,
|
||||
/// all items matching the query will be returned.
|
||||
///
|
||||
/// [offset] defines how many items to skip, after which [limit] (or all)
|
||||
/// items are read from the database.
|
||||
///
|
||||
/// ```dart
|
||||
/// var persons = await Persons.db.find(
|
||||
/// session,
|
||||
/// where: (t) => t.lastName.equals('Jones'),
|
||||
/// orderBy: (t) => t.firstName,
|
||||
/// limit: 100,
|
||||
/// );
|
||||
/// ```
|
||||
Future<List<ContentKey>> find(
|
||||
_isd.DatabaseSession session, {
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<ContentKeyTable>? orderBy,
|
||||
_isd.OrderByListBuilder<ContentKeyTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
_isd.LockMode? lockMode,
|
||||
_isd.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.find<ContentKey>(
|
||||
where: where?.call(ContentKey.t),
|
||||
orderBy: orderBy?.call(ContentKey.t),
|
||||
orderByList: orderByList?.call(ContentKey.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the first matching [ContentKey] matching the given query parameters.
|
||||
///
|
||||
/// Use [where] to specify which items to include in the return value.
|
||||
/// If none is specified, all items will be returned.
|
||||
///
|
||||
/// To specify the order use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// [offset] defines how many items to skip, after which the next one will be picked.
|
||||
///
|
||||
/// ```dart
|
||||
/// var youngestPerson = await Persons.db.findFirstRow(
|
||||
/// session,
|
||||
/// where: (t) => t.lastName.equals('Jones'),
|
||||
/// orderBy: (t) => t.age,
|
||||
/// );
|
||||
/// ```
|
||||
Future<ContentKey?> findFirstRow(
|
||||
_isd.DatabaseSession session, {
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? where,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<ContentKeyTable>? orderBy,
|
||||
_isd.OrderByListBuilder<ContentKeyTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
_isd.LockMode? lockMode,
|
||||
_isd.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findFirstRow<ContentKey>(
|
||||
where: where?.call(ContentKey.t),
|
||||
orderBy: orderBy?.call(ContentKey.t),
|
||||
orderByList: orderByList?.call(ContentKey.t),
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Finds a single [ContentKey] by its [id] or null if no such row exists.
|
||||
Future<ContentKey?> findById(
|
||||
_isd.DatabaseSession session,
|
||||
_isc.UuidValue id, {
|
||||
_isd.Transaction? transaction,
|
||||
_isd.LockMode? lockMode,
|
||||
_isd.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findById<ContentKey>(
|
||||
id,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts all [ContentKey]s in the list and returns the inserted rows.
|
||||
///
|
||||
/// The returned [ContentKey]s will have their `id` fields set.
|
||||
///
|
||||
/// This is an atomic operation, meaning that if one of the rows fails to
|
||||
/// insert, none of the rows will be inserted.
|
||||
///
|
||||
/// If [ignoreConflicts] is set to `true`, rows that conflict with existing
|
||||
/// rows are silently skipped, and only the successfully inserted rows are
|
||||
/// returned.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the inserted rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<ContentKey>> insert(
|
||||
_isd.DatabaseSession session,
|
||||
List<ContentKey> rows, {
|
||||
_isd.Transaction? transaction,
|
||||
bool ignoreConflicts = false,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.insert<ContentKey>(
|
||||
rows,
|
||||
transaction: transaction,
|
||||
ignoreConflicts: ignoreConflicts,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts a single [ContentKey] and returns the inserted row.
|
||||
///
|
||||
/// The returned [ContentKey] will have its `id` field set.
|
||||
Future<ContentKey> insertRow(
|
||||
_isd.DatabaseSession session,
|
||||
ContentKey row, {
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.insertRow<ContentKey>(
|
||||
row,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts all [ContentKey]s in the list and returns the resulting rows.
|
||||
///
|
||||
/// If a row conflicts on the given [conflictColumns], the existing row is
|
||||
/// updated with the new values. Otherwise, a new row is inserted.
|
||||
///
|
||||
/// If [updateColumns] is provided, only those columns will be updated on
|
||||
/// conflict. If null, all non-conflict, non-id columns are updated.
|
||||
///
|
||||
/// If [updateWhere] is provided, the update only applies to rows matching the
|
||||
/// given expression. Conflicting rows that don't match are skipped and not
|
||||
/// returned, so the resulting list may be shorter than [rows].
|
||||
///
|
||||
/// The returned [ContentKey]s will have their `id` fields set.
|
||||
///
|
||||
/// This is an atomic operation, meaning that if one of the rows fails,
|
||||
/// none of the rows will be affected.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the resulting rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<ContentKey>> upsert(
|
||||
_isd.DatabaseSession session,
|
||||
List<ContentKey> rows, {
|
||||
required _isd.ColumnSelections<ContentKeyTable> conflictColumns,
|
||||
_isd.ColumnSelections<ContentKeyTable>? updateColumns,
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? updateWhere,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.upsert<ContentKey>(
|
||||
rows,
|
||||
conflictColumns: conflictColumns(ContentKey.t),
|
||||
updateColumns: updateColumns?.call(ContentKey.t),
|
||||
updateWhere: updateWhere?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts a single [ContentKey] and returns the resulting row.
|
||||
///
|
||||
/// If the row conflicts on the given [conflictColumns], the existing row is
|
||||
/// updated. Otherwise, a new row is inserted.
|
||||
///
|
||||
/// If [updateColumns] is provided, only those columns will be updated on
|
||||
/// conflict. If null, all non-conflict, non-id columns are updated.
|
||||
///
|
||||
/// If [updateWhere] is provided, the update only applies when the existing
|
||||
/// row matches the expression. Returns `null` if no row was affected — for
|
||||
/// example when [updateWhere] does not match the conflicting row.
|
||||
///
|
||||
/// The returned [ContentKey] will have its `id` field set.
|
||||
Future<ContentKey?> upsertRow(
|
||||
_isd.DatabaseSession session,
|
||||
ContentKey row, {
|
||||
required _isd.ColumnSelections<ContentKeyTable> conflictColumns,
|
||||
_isd.ColumnSelections<ContentKeyTable>? updateColumns,
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? updateWhere,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.upsertRow<ContentKey>(
|
||||
row,
|
||||
conflictColumns: conflictColumns(ContentKey.t),
|
||||
updateColumns: updateColumns?.call(ContentKey.t),
|
||||
updateWhere: updateWhere?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [ContentKey]s in the list and returns the updated rows. If
|
||||
/// [columns] is provided, only those columns will be updated. Defaults to
|
||||
/// all columns.
|
||||
/// This is an atomic operation, meaning that if one of the rows fails to
|
||||
/// update, none of the rows will be updated.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the updated rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<ContentKey>> update(
|
||||
_isd.DatabaseSession session,
|
||||
List<ContentKey> rows, {
|
||||
_isd.ColumnSelections<ContentKeyTable>? columns,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.update<ContentKey>(
|
||||
rows,
|
||||
columns: columns?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [ContentKey]. The row needs to have its id set.
|
||||
/// Optionally, a list of [columns] can be provided to only update those
|
||||
/// columns. Defaults to all columns.
|
||||
Future<ContentKey> updateRow(
|
||||
_isd.DatabaseSession session,
|
||||
ContentKey row, {
|
||||
_isd.ColumnSelections<ContentKeyTable>? columns,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateRow<ContentKey>(
|
||||
row,
|
||||
columns: columns?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [ContentKey] by its [id] with the specified [columnValues].
|
||||
/// Returns the updated row or null if no row with the given id exists.
|
||||
Future<ContentKey?> updateById(
|
||||
_isd.DatabaseSession session,
|
||||
_isc.UuidValue id, {
|
||||
required _isd.ColumnValueListBuilder<ContentKeyUpdateTable> columnValues,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateById<ContentKey>(
|
||||
id,
|
||||
columnValues: columnValues(ContentKey.t.updateTable),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [ContentKey]s matching the [where] expression with the specified [columnValues].
|
||||
/// Returns the list of updated rows.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the updated rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<ContentKey>> updateWhere(
|
||||
_isd.DatabaseSession session, {
|
||||
required _isd.ColumnValueListBuilder<ContentKeyUpdateTable> columnValues,
|
||||
required _isd.WhereExpressionBuilder<ContentKeyTable> where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_isd.OrderByBuilder<ContentKeyTable>? orderBy,
|
||||
_isd.OrderByListBuilder<ContentKeyTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.updateWhere<ContentKey>(
|
||||
columnValues: columnValues(ContentKey.t.updateTable),
|
||||
where: where(ContentKey.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(ContentKey.t),
|
||||
orderByList: orderByList?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all [ContentKey]s in the list and returns the deleted rows.
|
||||
///
|
||||
/// To specify the order of the returned rows use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// This is an atomic operation, meaning that if one of the rows fail to
|
||||
/// be deleted, none of the rows will be deleted.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the deleted rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<ContentKey>> delete(
|
||||
_isd.DatabaseSession session,
|
||||
List<ContentKey> rows, {
|
||||
_isd.OrderByBuilder<ContentKeyTable>? orderBy,
|
||||
_isd.OrderByListBuilder<ContentKeyTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.delete<ContentKey>(
|
||||
rows,
|
||||
orderBy: orderBy?.call(ContentKey.t),
|
||||
orderByList: orderByList?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes a single [ContentKey].
|
||||
Future<ContentKey> deleteRow(
|
||||
_isd.DatabaseSession session,
|
||||
ContentKey row, {
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.deleteRow<ContentKey>(
|
||||
row,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all rows matching the [where] expression.
|
||||
///
|
||||
/// To specify the order of the returned rows use [orderBy] or [orderByList]
|
||||
/// when sorting by multiple columns.
|
||||
///
|
||||
/// If [noReturn] is set to `true`, the deleted rows are not read back from
|
||||
/// the database and an empty list is returned. This avoids the overhead of
|
||||
/// transferring and deserializing the rows when the result is not needed.
|
||||
Future<List<ContentKey>> deleteWhere(
|
||||
_isd.DatabaseSession session, {
|
||||
required _isd.WhereExpressionBuilder<ContentKeyTable> where,
|
||||
_isd.OrderByBuilder<ContentKeyTable>? orderBy,
|
||||
_isd.OrderByListBuilder<ContentKeyTable>? orderByList,
|
||||
_isd.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.deleteWhere<ContentKey>(
|
||||
where: where(ContentKey.t),
|
||||
orderBy: orderBy?.call(ContentKey.t),
|
||||
orderByList: orderByList?.call(ContentKey.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Counts the number of rows matching the [where] expression. If omitted,
|
||||
/// will return the count of all rows in the table.
|
||||
Future<int> count(
|
||||
_isd.DatabaseSession session, {
|
||||
_isd.WhereExpressionBuilder<ContentKeyTable>? where,
|
||||
int? limit,
|
||||
_isd.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.count<ContentKey>(
|
||||
where: where?.call(ContentKey.t),
|
||||
limit: limit,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Acquires row-level locks on [ContentKey] rows matching the [where] expression.
|
||||
Future<void> lockRows(
|
||||
_isd.DatabaseSession session, {
|
||||
required _isd.WhereExpressionBuilder<ContentKeyTable> where,
|
||||
required _isd.LockMode lockMode,
|
||||
required _isd.Transaction transaction,
|
||||
_isd.LockBehavior lockBehavior = _isd.LockBehavior.wait,
|
||||
}) async {
|
||||
return session.db.lockRows<ContentKey>(
|
||||
where: where(ContentKey.t),
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue