feat(learn): conversations with assistants, kept sealed (ADR 0021, step 3)
The first part of step 3, decided as D47 to D52 in ADR 0021: where a conversation shows (a sheet over the screen), where kept ones are found (the field), the scope's chip and that it starts with only what is ticked, how conversations are kept, and what a device that can't seal does. Two synced tables: assistant_conversation (its title, assistant and scope) and assistant_turn (one question and everything up to its answer, never changed once written, ADR 0001, rule 2), so two devices continuing a conversation offline lose nothing. SyncConversationGateway seals every row with the person's key, a turn bound to its conversation, and reads no row that isn't sealed: a device that can't seal keeps nothing (D52, ConversationNotKept). Deleting one blanks it and its turns first (ADR 0002, rule 2). A turn keeps every message a follow-up sends back (tool calls and results, the providers' own blocks), but no image, only that one was sent. The instance's privacy page says conversations are kept, encrypted, and what the instance sees of them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
36899cdc3b
commit
b965e05fdb
13 changed files with 36798 additions and 4 deletions
|
|
@ -0,0 +1,20 @@
|
|||
### A conversation with an assistant (ADR 0021, D13, D51): which assistant, what
|
||||
### it is about and its title, in the payload, sealed with the person's key; its
|
||||
### turns are AssistantTurn rows. Only ever written sealed: a device that can't
|
||||
### seal keeps no conversation (D52), and one that reaches it readable is never
|
||||
### shown. Synced; its space owns it.
|
||||
class: AssistantConversation
|
||||
table: assistant_conversation
|
||||
database: sync
|
||||
fields:
|
||||
### The key it is sealed with: the person's personal key.
|
||||
keyId: String?
|
||||
### The content as UTF-8 JSON: {"schemaVersion", "title", "assistant",
|
||||
### "scope"}.
|
||||
payload: ByteData
|
||||
### The encryption nonce.
|
||||
nonce: ByteData?
|
||||
indexes:
|
||||
# Deleting a space finds its rows through this index (see studyset.spy.yaml).
|
||||
assistant_conversation_space_idx:
|
||||
fields: spaceId
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
### One turn of a conversation with an assistant: a question and everything up
|
||||
### to its answer (the lookups' calls and results too), never changed once
|
||||
### written (ADR 0001, rule 2; ADR 0021, D51), so two devices continuing a
|
||||
### conversation offline lose nothing. Sealed with the person's key, bound to its
|
||||
### conversation. Turns are read in the order of their UUID v7 ids (ADR 0001,
|
||||
### rule 7). Deleting a conversation blanks every turn's payload first (ADR 0002,
|
||||
### rule 2).
|
||||
class: AssistantTurn
|
||||
table: assistant_turn
|
||||
database: sync
|
||||
fields:
|
||||
### The conversation it is a turn of; its turns go with it.
|
||||
conversation: AssistantConversation?, relation(onDelete=Cascade, deferred)
|
||||
### The key it is sealed with: the person's personal key.
|
||||
keyId: String?
|
||||
### The content as UTF-8 JSON: {"schemaVersion", "messages", "usage"}.
|
||||
payload: ByteData
|
||||
### The encryption nonce.
|
||||
nonce: ByteData?
|
||||
indexes:
|
||||
# Deleting a space finds its rows through this index (see studyset.spy.yaml).
|
||||
assistant_turn_space_idx:
|
||||
fields: spaceId
|
||||
# A conversation's turns.
|
||||
assistant_turn_conversation_idx:
|
||||
fields: conversationId
|
||||
|
|
@ -54,7 +54,8 @@ HoldsRegister learnAccounts([Map<String, String>? environment]) =>
|
|||
|
||||
/// What the instance's privacy page says of Learn's data (ADR 0019, point 4,
|
||||
/// and ADR 0021, D39): what a private studyset shows the instance, what is
|
||||
/// published, what goes to it to be answered, and the learner count.
|
||||
/// published, what goes to it to be answered, conversations with
|
||||
/// assistants (D13, D52), and the learner count.
|
||||
const List<PrivacyPagePoint> _privacyPagePoints = [
|
||||
(
|
||||
english:
|
||||
|
|
@ -78,6 +79,19 @@ const List<PrivacyPagePoint> _privacyPagePoints = [
|
|||
'Ergebnisse von Pfadantworten, Dateigrößen). Eines, das nicht privat '
|
||||
'ist, kann die Instanz lesen.',
|
||||
),
|
||||
(
|
||||
english:
|
||||
'Your conversations with assistants are kept to sync them between '
|
||||
'your devices, encrypted on them with your key: the instance sees how '
|
||||
'many there are, how long and when they were written, never what was '
|
||||
'said. A device that can’t encrypt keeps none.',
|
||||
german:
|
||||
'Deine Gespräche mit Assistenten werden aufbewahrt, um sie zwischen '
|
||||
'deinen Geräten abzugleichen, auf ihnen mit deinem Schlüssel '
|
||||
'verschlüsselt: Die Instanz sieht, wie viele es sind, wie lang und '
|
||||
'wann sie geschrieben wurden, nie, was gesagt wurde. Ein Gerät, das '
|
||||
'nicht verschlüsseln kann, bewahrt keine auf.',
|
||||
),
|
||||
(
|
||||
english:
|
||||
'A studyset you publish, and what you write on others’ (feedback, '
|
||||
|
|
|
|||
|
|
@ -0,0 +1,676 @@
|
|||
/* 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/serverpod.dart' as _is;
|
||||
|
||||
/// A conversation with an assistant (ADR 0021, D13, D51): which assistant, what
|
||||
/// it is about and its title, in the payload, sealed with the person's key; its
|
||||
/// turns are AssistantTurn rows. Only ever written sealed: a device that can't
|
||||
/// seal keeps no conversation (D52), and one that reaches it readable is never
|
||||
/// shown. Synced; its space owns it.
|
||||
abstract class AssistantConversation
|
||||
implements _is.TableRow<_is.UuidValue?>, _is.ProtocolSerialization {
|
||||
AssistantConversation._({
|
||||
this.id,
|
||||
this.spaceId,
|
||||
this.keyId,
|
||||
required this.payload,
|
||||
this.nonce,
|
||||
});
|
||||
|
||||
factory AssistantConversation({
|
||||
_is.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? keyId,
|
||||
required _idt.ByteData payload,
|
||||
_idt.ByteData? nonce,
|
||||
}) = _AssistantConversationImpl;
|
||||
|
||||
factory AssistantConversation.fromJson(
|
||||
Map<String, dynamic> jsonSerialization,
|
||||
) {
|
||||
return AssistantConversation(
|
||||
id: jsonSerialization['id'] == null
|
||||
? null
|
||||
: _is.UuidValueJsonExtension.fromJson(jsonSerialization['id']),
|
||||
spaceId: jsonSerialization['spaceId'] as int?,
|
||||
keyId: jsonSerialization['keyId'] as String?,
|
||||
payload: _is.ByteDataJsonExtension.fromJson(jsonSerialization['payload']),
|
||||
nonce: jsonSerialization['nonce'] == null
|
||||
? null
|
||||
: _is.ByteDataJsonExtension.fromJson(jsonSerialization['nonce']),
|
||||
);
|
||||
}
|
||||
|
||||
static final t = AssistantConversationTable();
|
||||
|
||||
static const db = AssistantConversationRepository._();
|
||||
|
||||
@override
|
||||
_is.UuidValue? id;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
int? spaceId;
|
||||
|
||||
/// The key it is sealed with: the person's personal key.
|
||||
String? keyId;
|
||||
|
||||
/// The content as UTF-8 JSON: {"schemaVersion", "title", "assistant",
|
||||
/// "scope"}.
|
||||
_idt.ByteData payload;
|
||||
|
||||
/// The encryption nonce.
|
||||
_idt.ByteData? nonce;
|
||||
|
||||
@override
|
||||
_is.Table<_is.UuidValue?> get table => t;
|
||||
|
||||
/// Returns a shallow copy of this [AssistantConversation]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
AssistantConversation copyWith({
|
||||
_is.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? keyId,
|
||||
_idt.ByteData? payload,
|
||||
_idt.ByteData? nonce,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'AssistantConversation',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
if (keyId != null) 'keyId': keyId,
|
||||
'payload': payload.toJson(),
|
||||
if (nonce != null) 'nonce': nonce?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'AssistantConversation',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
if (keyId != null) 'keyId': keyId,
|
||||
'payload': payload.toJson(),
|
||||
if (nonce != null) 'nonce': nonce?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
static AssistantConversationInclude include() {
|
||||
return AssistantConversationInclude._();
|
||||
}
|
||||
|
||||
static AssistantConversationIncludeList includeList({
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantConversationTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantConversationTable>? orderByList,
|
||||
AssistantConversationInclude? include,
|
||||
}) {
|
||||
return AssistantConversationIncludeList._(
|
||||
where: where,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(AssistantConversation.t),
|
||||
orderByList: orderByList?.call(AssistantConversation.t),
|
||||
include: include,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _is.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _AssistantConversationImpl extends AssistantConversation {
|
||||
_AssistantConversationImpl({
|
||||
_is.UuidValue? id,
|
||||
int? spaceId,
|
||||
String? keyId,
|
||||
required _idt.ByteData payload,
|
||||
_idt.ByteData? nonce,
|
||||
}) : super._(
|
||||
id: id,
|
||||
spaceId: spaceId,
|
||||
keyId: keyId,
|
||||
payload: payload,
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [AssistantConversation]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
@override
|
||||
AssistantConversation copyWith({
|
||||
Object? id = _Undefined,
|
||||
Object? spaceId = _Undefined,
|
||||
Object? keyId = _Undefined,
|
||||
_idt.ByteData? payload,
|
||||
Object? nonce = _Undefined,
|
||||
}) {
|
||||
return AssistantConversation(
|
||||
id: id is _is.UuidValue? ? id : this.id,
|
||||
spaceId: spaceId is int? ? spaceId : this.spaceId,
|
||||
keyId: keyId is String? ? keyId : this.keyId,
|
||||
payload: payload ?? this.payload.clone(),
|
||||
nonce: nonce is _idt.ByteData? ? nonce : this.nonce?.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AssistantConversationUpdateTable
|
||||
extends _is.UpdateTable<AssistantConversationTable> {
|
||||
AssistantConversationUpdateTable(super.table);
|
||||
|
||||
_is.ColumnValue<int, int> spaceId(int? value) => _is.ColumnValue(
|
||||
table.spaceId,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<String, String> keyId(String? value) => _is.ColumnValue(
|
||||
table.keyId,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<_idt.ByteData, _idt.ByteData> payload(_idt.ByteData value) =>
|
||||
_is.ColumnValue(
|
||||
table.payload,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<_idt.ByteData, _idt.ByteData> nonce(_idt.ByteData? value) =>
|
||||
_is.ColumnValue(
|
||||
table.nonce,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
class AssistantConversationTable extends _is.Table<_is.UuidValue?> {
|
||||
AssistantConversationTable({super.tableRelation})
|
||||
: super(tableName: 'assistant_conversation') {
|
||||
updateTable = AssistantConversationUpdateTable(this);
|
||||
spaceId = _is.ColumnInt(
|
||||
'spaceId',
|
||||
this,
|
||||
);
|
||||
keyId = _is.ColumnString(
|
||||
'keyId',
|
||||
this,
|
||||
);
|
||||
payload = _is.ColumnByteData(
|
||||
'payload',
|
||||
this,
|
||||
);
|
||||
nonce = _is.ColumnByteData(
|
||||
'nonce',
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
late final AssistantConversationUpdateTable updateTable;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
late final _is.ColumnInt spaceId;
|
||||
|
||||
/// The key it is sealed with: the person's personal key.
|
||||
late final _is.ColumnString keyId;
|
||||
|
||||
/// The content as UTF-8 JSON: {"schemaVersion", "title", "assistant",
|
||||
/// "scope"}.
|
||||
late final _is.ColumnByteData payload;
|
||||
|
||||
/// The encryption nonce.
|
||||
late final _is.ColumnByteData nonce;
|
||||
|
||||
@override
|
||||
List<_is.Column> get columns => [
|
||||
id,
|
||||
spaceId,
|
||||
keyId,
|
||||
payload,
|
||||
nonce,
|
||||
];
|
||||
}
|
||||
|
||||
class AssistantConversationInclude extends _is.IncludeObject {
|
||||
AssistantConversationInclude._();
|
||||
|
||||
@override
|
||||
Map<String, _is.Include?> get includes => {};
|
||||
|
||||
@override
|
||||
_is.Table<_is.UuidValue?> get table => AssistantConversation.t;
|
||||
}
|
||||
|
||||
class AssistantConversationIncludeList extends _is.IncludeList {
|
||||
AssistantConversationIncludeList._({
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? where,
|
||||
super.limit,
|
||||
super.offset,
|
||||
super.orderBy,
|
||||
super.orderByList,
|
||||
super.include,
|
||||
}) {
|
||||
super.where = where?.call(AssistantConversation.t);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, _is.Include?> get includes => include?.includes ?? {};
|
||||
|
||||
@override
|
||||
_is.Table<_is.UuidValue?> get table => AssistantConversation.t;
|
||||
}
|
||||
|
||||
class AssistantConversationRepository {
|
||||
const AssistantConversationRepository._();
|
||||
|
||||
/// Returns a list of [AssistantConversation]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<AssistantConversation>> find(
|
||||
_is.DatabaseSession session, {
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantConversationTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantConversationTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
_is.LockMode? lockMode,
|
||||
_is.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.find<AssistantConversation>(
|
||||
where: where?.call(AssistantConversation.t),
|
||||
orderBy: orderBy?.call(AssistantConversation.t),
|
||||
orderByList: orderByList?.call(AssistantConversation.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the first matching [AssistantConversation] 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<AssistantConversation?> findFirstRow(
|
||||
_is.DatabaseSession session, {
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? where,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantConversationTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantConversationTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
_is.LockMode? lockMode,
|
||||
_is.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findFirstRow<AssistantConversation>(
|
||||
where: where?.call(AssistantConversation.t),
|
||||
orderBy: orderBy?.call(AssistantConversation.t),
|
||||
orderByList: orderByList?.call(AssistantConversation.t),
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Finds a single [AssistantConversation] by its [id] or null if no such row exists.
|
||||
Future<AssistantConversation?> findById(
|
||||
_is.DatabaseSession session,
|
||||
_is.UuidValue id, {
|
||||
_is.Transaction? transaction,
|
||||
_is.LockMode? lockMode,
|
||||
_is.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findById<AssistantConversation>(
|
||||
id,
|
||||
transaction: transaction,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts all [AssistantConversation]s in the list and returns the inserted rows.
|
||||
///
|
||||
/// The returned [AssistantConversation]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<AssistantConversation>> insert(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantConversation> rows, {
|
||||
_is.Transaction? transaction,
|
||||
bool ignoreConflicts = false,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.insert<AssistantConversation>(
|
||||
rows,
|
||||
transaction: transaction,
|
||||
ignoreConflicts: ignoreConflicts,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts a single [AssistantConversation] and returns the inserted row.
|
||||
///
|
||||
/// The returned [AssistantConversation] will have its `id` field set.
|
||||
Future<AssistantConversation> insertRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantConversation row, {
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.insertRow<AssistantConversation>(
|
||||
row,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts all [AssistantConversation]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 [AssistantConversation]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<AssistantConversation>> upsert(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantConversation> rows, {
|
||||
required _is.ColumnSelections<AssistantConversationTable> conflictColumns,
|
||||
_is.ColumnSelections<AssistantConversationTable>? updateColumns,
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? updateWhere,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.upsert<AssistantConversation>(
|
||||
rows,
|
||||
conflictColumns: conflictColumns(AssistantConversation.t),
|
||||
updateColumns: updateColumns?.call(AssistantConversation.t),
|
||||
updateWhere: updateWhere?.call(AssistantConversation.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts a single [AssistantConversation] 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 [AssistantConversation] will have its `id` field set.
|
||||
Future<AssistantConversation?> upsertRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantConversation row, {
|
||||
required _is.ColumnSelections<AssistantConversationTable> conflictColumns,
|
||||
_is.ColumnSelections<AssistantConversationTable>? updateColumns,
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? updateWhere,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.upsertRow<AssistantConversation>(
|
||||
row,
|
||||
conflictColumns: conflictColumns(AssistantConversation.t),
|
||||
updateColumns: updateColumns?.call(AssistantConversation.t),
|
||||
updateWhere: updateWhere?.call(AssistantConversation.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [AssistantConversation]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<AssistantConversation>> update(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantConversation> rows, {
|
||||
_is.ColumnSelections<AssistantConversationTable>? columns,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.update<AssistantConversation>(
|
||||
rows,
|
||||
columns: columns?.call(AssistantConversation.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [AssistantConversation]. 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<AssistantConversation> updateRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantConversation row, {
|
||||
_is.ColumnSelections<AssistantConversationTable>? columns,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateRow<AssistantConversation>(
|
||||
row,
|
||||
columns: columns?.call(AssistantConversation.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [AssistantConversation] by its [id] with the specified [columnValues].
|
||||
/// Returns the updated row or null if no row with the given id exists.
|
||||
Future<AssistantConversation?> updateById(
|
||||
_is.DatabaseSession session,
|
||||
_is.UuidValue id, {
|
||||
required _is.ColumnValueListBuilder<AssistantConversationUpdateTable>
|
||||
columnValues,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateById<AssistantConversation>(
|
||||
id,
|
||||
columnValues: columnValues(AssistantConversation.t.updateTable),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [AssistantConversation]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<AssistantConversation>> updateWhere(
|
||||
_is.DatabaseSession session, {
|
||||
required _is.ColumnValueListBuilder<AssistantConversationUpdateTable>
|
||||
columnValues,
|
||||
required _is.WhereExpressionBuilder<AssistantConversationTable> where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantConversationTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantConversationTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.updateWhere<AssistantConversation>(
|
||||
columnValues: columnValues(AssistantConversation.t.updateTable),
|
||||
where: where(AssistantConversation.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(AssistantConversation.t),
|
||||
orderByList: orderByList?.call(AssistantConversation.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all [AssistantConversation]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<AssistantConversation>> delete(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantConversation> rows, {
|
||||
_is.OrderByBuilder<AssistantConversationTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantConversationTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.delete<AssistantConversation>(
|
||||
rows,
|
||||
orderBy: orderBy?.call(AssistantConversation.t),
|
||||
orderByList: orderByList?.call(AssistantConversation.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes a single [AssistantConversation].
|
||||
Future<AssistantConversation> deleteRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantConversation row, {
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.deleteRow<AssistantConversation>(
|
||||
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<AssistantConversation>> deleteWhere(
|
||||
_is.DatabaseSession session, {
|
||||
required _is.WhereExpressionBuilder<AssistantConversationTable> where,
|
||||
_is.OrderByBuilder<AssistantConversationTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantConversationTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.deleteWhere<AssistantConversation>(
|
||||
where: where(AssistantConversation.t),
|
||||
orderBy: orderBy?.call(AssistantConversation.t),
|
||||
orderByList: orderByList?.call(AssistantConversation.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(
|
||||
_is.DatabaseSession session, {
|
||||
_is.WhereExpressionBuilder<AssistantConversationTable>? where,
|
||||
int? limit,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.count<AssistantConversation>(
|
||||
where: where?.call(AssistantConversation.t),
|
||||
limit: limit,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Acquires row-level locks on [AssistantConversation] rows matching the [where] expression.
|
||||
Future<void> lockRows(
|
||||
_is.DatabaseSession session, {
|
||||
required _is.WhereExpressionBuilder<AssistantConversationTable> where,
|
||||
required _is.LockMode lockMode,
|
||||
required _is.Transaction transaction,
|
||||
_is.LockBehavior lockBehavior = _is.LockBehavior.wait,
|
||||
}) async {
|
||||
return session.db.lockRows<AssistantConversation>(
|
||||
where: where(AssistantConversation.t),
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,793 @@
|
|||
/* 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: dead_code, unnecessary_null_comparison
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:typed_data' as _idt;
|
||||
import 'package:halkyon_learn_server/src/generated/protocol.dart' as _i5lsenq5;
|
||||
import 'package:serverpod/serverpod.dart' as _is;
|
||||
import '../assistant/assistant_conversation.dart' as _ix0ywfho;
|
||||
|
||||
/// One turn of a conversation with an assistant: a question and everything up
|
||||
/// to its answer (the lookups' calls and results too), never changed once
|
||||
/// written (ADR 0001, rule 2; ADR 0021, D51), so two devices continuing a
|
||||
/// conversation offline lose nothing. Sealed with the person's key, bound to its
|
||||
/// conversation. Turns are read in the order of their UUID v7 ids (ADR 0001,
|
||||
/// rule 7). Deleting a conversation blanks every turn's payload first (ADR 0002,
|
||||
/// rule 2).
|
||||
abstract class AssistantTurn
|
||||
implements _is.TableRow<_is.UuidValue?>, _is.ProtocolSerialization {
|
||||
AssistantTurn._({
|
||||
this.id,
|
||||
this.spaceId,
|
||||
required this.conversationId,
|
||||
this.conversation,
|
||||
this.keyId,
|
||||
required this.payload,
|
||||
this.nonce,
|
||||
});
|
||||
|
||||
factory AssistantTurn({
|
||||
_is.UuidValue? id,
|
||||
int? spaceId,
|
||||
required _is.UuidValue conversationId,
|
||||
_ix0ywfho.AssistantConversation? conversation,
|
||||
String? keyId,
|
||||
required _idt.ByteData payload,
|
||||
_idt.ByteData? nonce,
|
||||
}) = _AssistantTurnImpl;
|
||||
|
||||
factory AssistantTurn.fromJson(Map<String, dynamic> jsonSerialization) {
|
||||
return AssistantTurn(
|
||||
id: jsonSerialization['id'] == null
|
||||
? null
|
||||
: _is.UuidValueJsonExtension.fromJson(jsonSerialization['id']),
|
||||
spaceId: jsonSerialization['spaceId'] as int?,
|
||||
conversationId: _is.UuidValueJsonExtension.fromJson(
|
||||
jsonSerialization['conversationId'],
|
||||
),
|
||||
conversation: jsonSerialization['conversation'] == null
|
||||
? null
|
||||
: _i5lsenq5.Protocol().deserialize<_ix0ywfho.AssistantConversation>(
|
||||
jsonSerialization['conversation'],
|
||||
),
|
||||
keyId: jsonSerialization['keyId'] as String?,
|
||||
payload: _is.ByteDataJsonExtension.fromJson(jsonSerialization['payload']),
|
||||
nonce: jsonSerialization['nonce'] == null
|
||||
? null
|
||||
: _is.ByteDataJsonExtension.fromJson(jsonSerialization['nonce']),
|
||||
);
|
||||
}
|
||||
|
||||
static final t = AssistantTurnTable();
|
||||
|
||||
static const db = AssistantTurnRepository._();
|
||||
|
||||
@override
|
||||
_is.UuidValue? id;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
int? spaceId;
|
||||
|
||||
_is.UuidValue conversationId;
|
||||
|
||||
/// The conversation it is a turn of; its turns go with it.
|
||||
_ix0ywfho.AssistantConversation? conversation;
|
||||
|
||||
/// The key it is sealed with: the person's personal key.
|
||||
String? keyId;
|
||||
|
||||
/// The content as UTF-8 JSON: {"schemaVersion", "messages", "usage"}.
|
||||
_idt.ByteData payload;
|
||||
|
||||
/// The encryption nonce.
|
||||
_idt.ByteData? nonce;
|
||||
|
||||
@override
|
||||
_is.Table<_is.UuidValue?> get table => t;
|
||||
|
||||
/// Returns a shallow copy of this [AssistantTurn]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
AssistantTurn copyWith({
|
||||
_is.UuidValue? id,
|
||||
int? spaceId,
|
||||
_is.UuidValue? conversationId,
|
||||
_ix0ywfho.AssistantConversation? conversation,
|
||||
String? keyId,
|
||||
_idt.ByteData? payload,
|
||||
_idt.ByteData? nonce,
|
||||
});
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'__className__': 'AssistantTurn',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
'conversationId': conversationId.toJson(),
|
||||
if (conversation != null) 'conversation': conversation?.toJson(),
|
||||
if (keyId != null) 'keyId': keyId,
|
||||
'payload': payload.toJson(),
|
||||
if (nonce != null) 'nonce': nonce?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJsonForProtocol() {
|
||||
return {
|
||||
'__className__': 'AssistantTurn',
|
||||
if (id != null) 'id': id?.toJson(),
|
||||
if (spaceId != null) 'spaceId': spaceId,
|
||||
'conversationId': conversationId.toJson(),
|
||||
if (conversation != null)
|
||||
'conversation': conversation?.toJsonForProtocol(),
|
||||
if (keyId != null) 'keyId': keyId,
|
||||
'payload': payload.toJson(),
|
||||
if (nonce != null) 'nonce': nonce?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
static AssistantTurnInclude include({
|
||||
_ix0ywfho.AssistantConversationInclude? conversation,
|
||||
}) {
|
||||
return AssistantTurnInclude._(conversation: conversation);
|
||||
}
|
||||
|
||||
static AssistantTurnIncludeList includeList({
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantTurnTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantTurnTable>? orderByList,
|
||||
AssistantTurnInclude? include,
|
||||
}) {
|
||||
return AssistantTurnIncludeList._(
|
||||
where: where,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(AssistantTurn.t),
|
||||
orderByList: orderByList?.call(AssistantTurn.t),
|
||||
include: include,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return _is.SerializationManager.encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
class _Undefined {}
|
||||
|
||||
class _AssistantTurnImpl extends AssistantTurn {
|
||||
_AssistantTurnImpl({
|
||||
_is.UuidValue? id,
|
||||
int? spaceId,
|
||||
required _is.UuidValue conversationId,
|
||||
_ix0ywfho.AssistantConversation? conversation,
|
||||
String? keyId,
|
||||
required _idt.ByteData payload,
|
||||
_idt.ByteData? nonce,
|
||||
}) : super._(
|
||||
id: id,
|
||||
spaceId: spaceId,
|
||||
conversationId: conversationId,
|
||||
conversation: conversation,
|
||||
keyId: keyId,
|
||||
payload: payload,
|
||||
nonce: nonce,
|
||||
);
|
||||
|
||||
/// Returns a shallow copy of this [AssistantTurn]
|
||||
/// with some or all fields replaced by the given arguments.
|
||||
@_is.useResult
|
||||
@override
|
||||
AssistantTurn copyWith({
|
||||
Object? id = _Undefined,
|
||||
Object? spaceId = _Undefined,
|
||||
_is.UuidValue? conversationId,
|
||||
Object? conversation = _Undefined,
|
||||
Object? keyId = _Undefined,
|
||||
_idt.ByteData? payload,
|
||||
Object? nonce = _Undefined,
|
||||
}) {
|
||||
return AssistantTurn(
|
||||
id: id is _is.UuidValue? ? id : this.id,
|
||||
spaceId: spaceId is int? ? spaceId : this.spaceId,
|
||||
conversationId: conversationId ?? this.conversationId,
|
||||
conversation: conversation is _ix0ywfho.AssistantConversation?
|
||||
? conversation
|
||||
: this.conversation?.copyWith(),
|
||||
keyId: keyId is String? ? keyId : this.keyId,
|
||||
payload: payload ?? this.payload.clone(),
|
||||
nonce: nonce is _idt.ByteData? ? nonce : this.nonce?.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AssistantTurnUpdateTable extends _is.UpdateTable<AssistantTurnTable> {
|
||||
AssistantTurnUpdateTable(super.table);
|
||||
|
||||
_is.ColumnValue<int, int> spaceId(int? value) => _is.ColumnValue(
|
||||
table.spaceId,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<_is.UuidValue, _is.UuidValue> conversationId(
|
||||
_is.UuidValue value,
|
||||
) => _is.ColumnValue(
|
||||
table.conversationId,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<String, String> keyId(String? value) => _is.ColumnValue(
|
||||
table.keyId,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<_idt.ByteData, _idt.ByteData> payload(_idt.ByteData value) =>
|
||||
_is.ColumnValue(
|
||||
table.payload,
|
||||
value,
|
||||
);
|
||||
|
||||
_is.ColumnValue<_idt.ByteData, _idt.ByteData> nonce(_idt.ByteData? value) =>
|
||||
_is.ColumnValue(
|
||||
table.nonce,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
class AssistantTurnTable extends _is.Table<_is.UuidValue?> {
|
||||
AssistantTurnTable({super.tableRelation})
|
||||
: super(tableName: 'assistant_turn') {
|
||||
updateTable = AssistantTurnUpdateTable(this);
|
||||
spaceId = _is.ColumnInt(
|
||||
'spaceId',
|
||||
this,
|
||||
);
|
||||
conversationId = _is.ColumnUuid(
|
||||
'conversationId',
|
||||
this,
|
||||
);
|
||||
keyId = _is.ColumnString(
|
||||
'keyId',
|
||||
this,
|
||||
);
|
||||
payload = _is.ColumnByteData(
|
||||
'payload',
|
||||
this,
|
||||
);
|
||||
nonce = _is.ColumnByteData(
|
||||
'nonce',
|
||||
this,
|
||||
);
|
||||
}
|
||||
|
||||
late final AssistantTurnUpdateTable updateTable;
|
||||
|
||||
/// The space owning this row. Maintained by the sync engine.
|
||||
late final _is.ColumnInt spaceId;
|
||||
|
||||
late final _is.ColumnUuid conversationId;
|
||||
|
||||
/// The conversation it is a turn of; its turns go with it.
|
||||
_ix0ywfho.AssistantConversationTable? _conversation;
|
||||
|
||||
/// The key it is sealed with: the person's personal key.
|
||||
late final _is.ColumnString keyId;
|
||||
|
||||
/// The content as UTF-8 JSON: {"schemaVersion", "messages", "usage"}.
|
||||
late final _is.ColumnByteData payload;
|
||||
|
||||
/// The encryption nonce.
|
||||
late final _is.ColumnByteData nonce;
|
||||
|
||||
_ix0ywfho.AssistantConversationTable get conversation {
|
||||
if (_conversation != null) return _conversation!;
|
||||
_conversation = _is.createRelationTable(
|
||||
relationFieldName: 'conversation',
|
||||
field: AssistantTurn.t.conversationId,
|
||||
foreignField: _ix0ywfho.AssistantConversation.t.id,
|
||||
tableRelation: tableRelation,
|
||||
createTable: (foreignTableRelation) =>
|
||||
_ix0ywfho.AssistantConversationTable(
|
||||
tableRelation: foreignTableRelation,
|
||||
),
|
||||
);
|
||||
return _conversation!;
|
||||
}
|
||||
|
||||
@override
|
||||
List<_is.Column> get columns => [
|
||||
id,
|
||||
spaceId,
|
||||
conversationId,
|
||||
keyId,
|
||||
payload,
|
||||
nonce,
|
||||
];
|
||||
|
||||
@override
|
||||
_is.Table? getRelationTable(String relationField) {
|
||||
if (relationField == 'conversation') {
|
||||
return conversation;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class AssistantTurnInclude extends _is.IncludeObject {
|
||||
AssistantTurnInclude._({
|
||||
_ix0ywfho.AssistantConversationInclude? conversation,
|
||||
}) {
|
||||
_conversation = conversation;
|
||||
}
|
||||
|
||||
_ix0ywfho.AssistantConversationInclude? _conversation;
|
||||
|
||||
@override
|
||||
Map<String, _is.Include?> get includes => {'conversation': _conversation};
|
||||
|
||||
@override
|
||||
_is.Table<_is.UuidValue?> get table => AssistantTurn.t;
|
||||
}
|
||||
|
||||
class AssistantTurnIncludeList extends _is.IncludeList {
|
||||
AssistantTurnIncludeList._({
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? where,
|
||||
super.limit,
|
||||
super.offset,
|
||||
super.orderBy,
|
||||
super.orderByList,
|
||||
super.include,
|
||||
}) {
|
||||
super.where = where?.call(AssistantTurn.t);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, _is.Include?> get includes => include?.includes ?? {};
|
||||
|
||||
@override
|
||||
_is.Table<_is.UuidValue?> get table => AssistantTurn.t;
|
||||
}
|
||||
|
||||
class AssistantTurnRepository {
|
||||
const AssistantTurnRepository._();
|
||||
|
||||
final attachRow = const AssistantTurnAttachRowRepository._();
|
||||
|
||||
/// Returns a list of [AssistantTurn]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<AssistantTurn>> find(
|
||||
_is.DatabaseSession session, {
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantTurnTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantTurnTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
AssistantTurnInclude? include,
|
||||
_is.LockMode? lockMode,
|
||||
_is.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.find<AssistantTurn>(
|
||||
where: where?.call(AssistantTurn.t),
|
||||
orderBy: orderBy?.call(AssistantTurn.t),
|
||||
orderByList: orderByList?.call(AssistantTurn.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
include: include,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the first matching [AssistantTurn] 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<AssistantTurn?> findFirstRow(
|
||||
_is.DatabaseSession session, {
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? where,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantTurnTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantTurnTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
AssistantTurnInclude? include,
|
||||
_is.LockMode? lockMode,
|
||||
_is.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findFirstRow<AssistantTurn>(
|
||||
where: where?.call(AssistantTurn.t),
|
||||
orderBy: orderBy?.call(AssistantTurn.t),
|
||||
orderByList: orderByList?.call(AssistantTurn.t),
|
||||
offset: offset,
|
||||
transaction: transaction,
|
||||
include: include,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Finds a single [AssistantTurn] by its [id] or null if no such row exists.
|
||||
Future<AssistantTurn?> findById(
|
||||
_is.DatabaseSession session,
|
||||
_is.UuidValue id, {
|
||||
_is.Transaction? transaction,
|
||||
AssistantTurnInclude? include,
|
||||
_is.LockMode? lockMode,
|
||||
_is.LockBehavior? lockBehavior,
|
||||
}) async {
|
||||
return session.db.findById<AssistantTurn>(
|
||||
id,
|
||||
transaction: transaction,
|
||||
include: include,
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts all [AssistantTurn]s in the list and returns the inserted rows.
|
||||
///
|
||||
/// The returned [AssistantTurn]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<AssistantTurn>> insert(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantTurn> rows, {
|
||||
_is.Transaction? transaction,
|
||||
bool ignoreConflicts = false,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.insert<AssistantTurn>(
|
||||
rows,
|
||||
transaction: transaction,
|
||||
ignoreConflicts: ignoreConflicts,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Inserts a single [AssistantTurn] and returns the inserted row.
|
||||
///
|
||||
/// The returned [AssistantTurn] will have its `id` field set.
|
||||
Future<AssistantTurn> insertRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantTurn row, {
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.insertRow<AssistantTurn>(
|
||||
row,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts all [AssistantTurn]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 [AssistantTurn]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<AssistantTurn>> upsert(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantTurn> rows, {
|
||||
required _is.ColumnSelections<AssistantTurnTable> conflictColumns,
|
||||
_is.ColumnSelections<AssistantTurnTable>? updateColumns,
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? updateWhere,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.upsert<AssistantTurn>(
|
||||
rows,
|
||||
conflictColumns: conflictColumns(AssistantTurn.t),
|
||||
updateColumns: updateColumns?.call(AssistantTurn.t),
|
||||
updateWhere: updateWhere?.call(AssistantTurn.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Upserts a single [AssistantTurn] 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 [AssistantTurn] will have its `id` field set.
|
||||
Future<AssistantTurn?> upsertRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantTurn row, {
|
||||
required _is.ColumnSelections<AssistantTurnTable> conflictColumns,
|
||||
_is.ColumnSelections<AssistantTurnTable>? updateColumns,
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? updateWhere,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.upsertRow<AssistantTurn>(
|
||||
row,
|
||||
conflictColumns: conflictColumns(AssistantTurn.t),
|
||||
updateColumns: updateColumns?.call(AssistantTurn.t),
|
||||
updateWhere: updateWhere?.call(AssistantTurn.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [AssistantTurn]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<AssistantTurn>> update(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantTurn> rows, {
|
||||
_is.ColumnSelections<AssistantTurnTable>? columns,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.update<AssistantTurn>(
|
||||
rows,
|
||||
columns: columns?.call(AssistantTurn.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [AssistantTurn]. 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<AssistantTurn> updateRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantTurn row, {
|
||||
_is.ColumnSelections<AssistantTurnTable>? columns,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateRow<AssistantTurn>(
|
||||
row,
|
||||
columns: columns?.call(AssistantTurn.t),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates a single [AssistantTurn] by its [id] with the specified [columnValues].
|
||||
/// Returns the updated row or null if no row with the given id exists.
|
||||
Future<AssistantTurn?> updateById(
|
||||
_is.DatabaseSession session,
|
||||
_is.UuidValue id, {
|
||||
required _is.ColumnValueListBuilder<AssistantTurnUpdateTable> columnValues,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.updateById<AssistantTurn>(
|
||||
id,
|
||||
columnValues: columnValues(AssistantTurn.t.updateTable),
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates all [AssistantTurn]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<AssistantTurn>> updateWhere(
|
||||
_is.DatabaseSession session, {
|
||||
required _is.ColumnValueListBuilder<AssistantTurnUpdateTable> columnValues,
|
||||
required _is.WhereExpressionBuilder<AssistantTurnTable> where,
|
||||
int? limit,
|
||||
int? offset,
|
||||
_is.OrderByBuilder<AssistantTurnTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantTurnTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.updateWhere<AssistantTurn>(
|
||||
columnValues: columnValues(AssistantTurn.t.updateTable),
|
||||
where: where(AssistantTurn.t),
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
orderBy: orderBy?.call(AssistantTurn.t),
|
||||
orderByList: orderByList?.call(AssistantTurn.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all [AssistantTurn]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<AssistantTurn>> delete(
|
||||
_is.DatabaseSession session,
|
||||
List<AssistantTurn> rows, {
|
||||
_is.OrderByBuilder<AssistantTurnTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantTurnTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.delete<AssistantTurn>(
|
||||
rows,
|
||||
orderBy: orderBy?.call(AssistantTurn.t),
|
||||
orderByList: orderByList?.call(AssistantTurn.t),
|
||||
transaction: transaction,
|
||||
noReturn: noReturn,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes a single [AssistantTurn].
|
||||
Future<AssistantTurn> deleteRow(
|
||||
_is.DatabaseSession session,
|
||||
AssistantTurn row, {
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.deleteRow<AssistantTurn>(
|
||||
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<AssistantTurn>> deleteWhere(
|
||||
_is.DatabaseSession session, {
|
||||
required _is.WhereExpressionBuilder<AssistantTurnTable> where,
|
||||
_is.OrderByBuilder<AssistantTurnTable>? orderBy,
|
||||
_is.OrderByListBuilder<AssistantTurnTable>? orderByList,
|
||||
_is.Transaction? transaction,
|
||||
bool noReturn = false,
|
||||
}) async {
|
||||
return session.db.deleteWhere<AssistantTurn>(
|
||||
where: where(AssistantTurn.t),
|
||||
orderBy: orderBy?.call(AssistantTurn.t),
|
||||
orderByList: orderByList?.call(AssistantTurn.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(
|
||||
_is.DatabaseSession session, {
|
||||
_is.WhereExpressionBuilder<AssistantTurnTable>? where,
|
||||
int? limit,
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
return session.db.count<AssistantTurn>(
|
||||
where: where?.call(AssistantTurn.t),
|
||||
limit: limit,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Acquires row-level locks on [AssistantTurn] rows matching the [where] expression.
|
||||
Future<void> lockRows(
|
||||
_is.DatabaseSession session, {
|
||||
required _is.WhereExpressionBuilder<AssistantTurnTable> where,
|
||||
required _is.LockMode lockMode,
|
||||
required _is.Transaction transaction,
|
||||
_is.LockBehavior lockBehavior = _is.LockBehavior.wait,
|
||||
}) async {
|
||||
return session.db.lockRows<AssistantTurn>(
|
||||
where: where(AssistantTurn.t),
|
||||
lockMode: lockMode,
|
||||
lockBehavior: lockBehavior,
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AssistantTurnAttachRowRepository {
|
||||
const AssistantTurnAttachRowRepository._();
|
||||
|
||||
/// Creates a relation between the given [AssistantTurn] and [AssistantConversation]
|
||||
/// by setting the [AssistantTurn]'s foreign key `conversationId` to refer to the [AssistantConversation].
|
||||
Future<void> conversation(
|
||||
_is.DatabaseSession session,
|
||||
AssistantTurn assistantTurn,
|
||||
_ix0ywfho.AssistantConversation conversation, {
|
||||
_is.Transaction? transaction,
|
||||
}) async {
|
||||
if (assistantTurn.id == null) {
|
||||
throw ArgumentError.notNull('assistantTurn.id');
|
||||
}
|
||||
if (conversation.id == null) {
|
||||
throw ArgumentError.notNull('conversation.id');
|
||||
}
|
||||
|
||||
var $assistantTurn = assistantTurn.copyWith(
|
||||
conversationId: conversation.id,
|
||||
);
|
||||
await session.db.updateRow<AssistantTurn>(
|
||||
$assistantTurn,
|
||||
columns: [AssistantTurn.t.conversationId],
|
||||
transaction: transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,8 @@ import 'asset/asset.dart' as _ipb7vkxr;
|
|||
import 'asset/file_allowance.dart' as _i9uv0f1n;
|
||||
import 'asset/file_limit_exceeded_exception.dart' as _it5d94hq;
|
||||
import 'asset/file_usage.dart' as _iurwo9k8;
|
||||
import 'assistant/assistant_conversation.dart' as _ikd6xdrt;
|
||||
import 'assistant/assistant_turn.dart' as _i5vmmfj2;
|
||||
import 'auth/device.dart' as _i6c5ny7n;
|
||||
import 'card/card.dart' as _ipiw1cmx;
|
||||
import 'card/card_revision.dart' as _ipbyuef1;
|
||||
|
|
@ -106,6 +108,8 @@ export 'asset/asset.dart';
|
|||
export 'asset/file_allowance.dart';
|
||||
export 'asset/file_limit_exceeded_exception.dart';
|
||||
export 'asset/file_usage.dart';
|
||||
export 'assistant/assistant_conversation.dart';
|
||||
export 'assistant/assistant_turn.dart';
|
||||
export 'auth/device.dart';
|
||||
export 'card/card.dart';
|
||||
export 'card/card_revision.dart';
|
||||
|
|
@ -277,6 +281,170 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
],
|
||||
managed: true,
|
||||
),
|
||||
_isp.TableDefinition(
|
||||
name: 'assistant_conversation',
|
||||
dartName: 'AssistantConversation',
|
||||
schema: 'public',
|
||||
module: 'halkyon_learn',
|
||||
columns: [
|
||||
_isp.ColumnDefinition(
|
||||
name: 'id',
|
||||
columnType: _isp.ColumnType.uuid,
|
||||
isNullable: false,
|
||||
dartType: 'UuidValue?',
|
||||
columnDefault: 'random_v7',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'spaceId',
|
||||
columnType: _isp.ColumnType.bigint,
|
||||
isNullable: true,
|
||||
dartType: 'int?',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'keyId',
|
||||
columnType: _isp.ColumnType.text,
|
||||
isNullable: true,
|
||||
dartType: 'String?',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'payload',
|
||||
columnType: _isp.ColumnType.bytea,
|
||||
isNullable: false,
|
||||
dartType: 'dart:typed_data:ByteData',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'nonce',
|
||||
columnType: _isp.ColumnType.bytea,
|
||||
isNullable: true,
|
||||
dartType: 'dart:typed_data:ByteData?',
|
||||
),
|
||||
],
|
||||
foreignKeys: [
|
||||
_isp.ForeignKeyDefinition(
|
||||
constraintName: 'assistant_conversation_fk_0',
|
||||
columns: ['spaceId'],
|
||||
referenceTable: 'offline_sync_spaces',
|
||||
referenceTableSchema: 'public',
|
||||
referenceColumns: ['id'],
|
||||
onUpdate: _isp.ForeignKeyAction.noAction,
|
||||
onDelete: _isp.ForeignKeyAction.cascade,
|
||||
matchType: null,
|
||||
),
|
||||
],
|
||||
indexes: [
|
||||
_isp.IndexDefinition(
|
||||
indexName: 'assistant_conversation_space_idx',
|
||||
tableSpace: null,
|
||||
elements: [
|
||||
_isp.IndexElementDefinition(
|
||||
type: _isp.IndexElementDefinitionType.column,
|
||||
definition: 'spaceId',
|
||||
),
|
||||
],
|
||||
type: 'btree',
|
||||
isUnique: false,
|
||||
isPrimary: false,
|
||||
),
|
||||
],
|
||||
managed: true,
|
||||
),
|
||||
_isp.TableDefinition(
|
||||
name: 'assistant_turn',
|
||||
dartName: 'AssistantTurn',
|
||||
schema: 'public',
|
||||
module: 'halkyon_learn',
|
||||
columns: [
|
||||
_isp.ColumnDefinition(
|
||||
name: 'id',
|
||||
columnType: _isp.ColumnType.uuid,
|
||||
isNullable: false,
|
||||
dartType: 'UuidValue?',
|
||||
columnDefault: 'random_v7',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'spaceId',
|
||||
columnType: _isp.ColumnType.bigint,
|
||||
isNullable: true,
|
||||
dartType: 'int?',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'conversationId',
|
||||
columnType: _isp.ColumnType.uuid,
|
||||
isNullable: false,
|
||||
dartType: 'UuidValue',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'keyId',
|
||||
columnType: _isp.ColumnType.text,
|
||||
isNullable: true,
|
||||
dartType: 'String?',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'payload',
|
||||
columnType: _isp.ColumnType.bytea,
|
||||
isNullable: false,
|
||||
dartType: 'dart:typed_data:ByteData',
|
||||
),
|
||||
_isp.ColumnDefinition(
|
||||
name: 'nonce',
|
||||
columnType: _isp.ColumnType.bytea,
|
||||
isNullable: true,
|
||||
dartType: 'dart:typed_data:ByteData?',
|
||||
),
|
||||
],
|
||||
foreignKeys: [
|
||||
_isp.ForeignKeyDefinition(
|
||||
constraintName: 'assistant_turn_fk_0',
|
||||
columns: ['spaceId'],
|
||||
referenceTable: 'offline_sync_spaces',
|
||||
referenceTableSchema: 'public',
|
||||
referenceColumns: ['id'],
|
||||
onUpdate: _isp.ForeignKeyAction.noAction,
|
||||
onDelete: _isp.ForeignKeyAction.cascade,
|
||||
matchType: null,
|
||||
),
|
||||
_isp.ForeignKeyDefinition(
|
||||
constraintName: 'assistant_turn_fk_1',
|
||||
columns: ['conversationId'],
|
||||
referenceTable: 'assistant_conversation',
|
||||
referenceTableSchema: 'public',
|
||||
referenceColumns: ['id'],
|
||||
onUpdate: _isp.ForeignKeyAction.noAction,
|
||||
onDelete: _isp.ForeignKeyAction.cascade,
|
||||
matchType: null,
|
||||
deferrable: _isp.DeferrableConstraint.initiallyDeferred,
|
||||
),
|
||||
],
|
||||
indexes: [
|
||||
_isp.IndexDefinition(
|
||||
indexName: 'assistant_turn_space_idx',
|
||||
tableSpace: null,
|
||||
elements: [
|
||||
_isp.IndexElementDefinition(
|
||||
type: _isp.IndexElementDefinitionType.column,
|
||||
definition: 'spaceId',
|
||||
),
|
||||
],
|
||||
type: 'btree',
|
||||
isUnique: false,
|
||||
isPrimary: false,
|
||||
),
|
||||
_isp.IndexDefinition(
|
||||
indexName: 'assistant_turn_conversation_idx',
|
||||
tableSpace: null,
|
||||
elements: [
|
||||
_isp.IndexElementDefinition(
|
||||
type: _isp.IndexElementDefinitionType.column,
|
||||
definition: 'conversationId',
|
||||
),
|
||||
],
|
||||
type: 'btree',
|
||||
isUnique: false,
|
||||
isPrimary: false,
|
||||
),
|
||||
],
|
||||
managed: true,
|
||||
),
|
||||
_isp.TableDefinition(
|
||||
name: 'card',
|
||||
dartName: 'Card',
|
||||
|
|
@ -3619,6 +3787,12 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
if (t == _iurwo9k8.FileUsage) {
|
||||
return _iurwo9k8.FileUsage.fromJson(data) as T;
|
||||
}
|
||||
if (t == _ikd6xdrt.AssistantConversation) {
|
||||
return _ikd6xdrt.AssistantConversation.fromJson(data) as T;
|
||||
}
|
||||
if (t == _i5vmmfj2.AssistantTurn) {
|
||||
return _i5vmmfj2.AssistantTurn.fromJson(data) as T;
|
||||
}
|
||||
if (t == _i6c5ny7n.Device) {
|
||||
return _i6c5ny7n.Device.fromJson(data) as T;
|
||||
}
|
||||
|
|
@ -3812,6 +3986,16 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
if (t == _is.getType<_iurwo9k8.FileUsage?>()) {
|
||||
return (data != null ? _iurwo9k8.FileUsage.fromJson(data) : null) as T;
|
||||
}
|
||||
if (t == _is.getType<_ikd6xdrt.AssistantConversation?>()) {
|
||||
return (data != null
|
||||
? _ikd6xdrt.AssistantConversation.fromJson(data)
|
||||
: null)
|
||||
as T;
|
||||
}
|
||||
if (t == _is.getType<_i5vmmfj2.AssistantTurn?>()) {
|
||||
return (data != null ? _i5vmmfj2.AssistantTurn.fromJson(data) : null)
|
||||
as T;
|
||||
}
|
||||
if (t == _is.getType<_i6c5ny7n.Device?>()) {
|
||||
return (data != null ? _i6c5ny7n.Device.fromJson(data) : null) as T;
|
||||
}
|
||||
|
|
@ -4175,6 +4359,8 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
_i9uv0f1n.FileAllowance => 'FileAllowance',
|
||||
_it5d94hq.FileLimitExceededException => 'FileLimitExceededException',
|
||||
_iurwo9k8.FileUsage => 'FileUsage',
|
||||
_ikd6xdrt.AssistantConversation => 'AssistantConversation',
|
||||
_i5vmmfj2.AssistantTurn => 'AssistantTurn',
|
||||
_i6c5ny7n.Device => 'Device',
|
||||
_ipiw1cmx.Card => 'Card',
|
||||
_ipbyuef1.CardRevision => 'CardRevision',
|
||||
|
|
@ -4259,6 +4445,10 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
return 'FileLimitExceededException';
|
||||
case _iurwo9k8.FileUsage():
|
||||
return 'FileUsage';
|
||||
case _ikd6xdrt.AssistantConversation():
|
||||
return 'AssistantConversation';
|
||||
case _i5vmmfj2.AssistantTurn():
|
||||
return 'AssistantTurn';
|
||||
case _i6c5ny7n.Device():
|
||||
return 'Device';
|
||||
case _ipiw1cmx.Card():
|
||||
|
|
@ -4429,6 +4619,12 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
if (dataClassName == 'FileUsage') {
|
||||
return deserialize<_iurwo9k8.FileUsage>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'AssistantConversation') {
|
||||
return deserialize<_ikd6xdrt.AssistantConversation>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'AssistantTurn') {
|
||||
return deserialize<_i5vmmfj2.AssistantTurn>(data['data']);
|
||||
}
|
||||
if (dataClassName == 'Device') {
|
||||
return deserialize<_i6c5ny7n.Device>(data['data']);
|
||||
}
|
||||
|
|
@ -4684,6 +4880,10 @@ class Protocol extends _is.DatabaseSerializationManager {
|
|||
return _ipb7vkxr.Asset.t;
|
||||
case _i9uv0f1n.FileAllowance:
|
||||
return _i9uv0f1n.FileAllowance.t;
|
||||
case _ikd6xdrt.AssistantConversation:
|
||||
return _ikd6xdrt.AssistantConversation.t;
|
||||
case _i5vmmfj2.AssistantTurn:
|
||||
return _i5vmmfj2.AssistantTurn.t;
|
||||
case _ipiw1cmx.Card:
|
||||
return _ipiw1cmx.Card.t;
|
||||
case _ipbyuef1.CardRevision:
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:serverpod/serverpod.dart' as _is;
|
||||
import 'asset/asset.dart' as _ipb7vkxr;
|
||||
import 'assistant/assistant_conversation.dart' as _ikd6xdrt;
|
||||
import 'assistant/assistant_turn.dart' as _i5vmmfj2;
|
||||
import 'card/card.dart' as _ipiw1cmx;
|
||||
import 'card/card_revision.dart' as _ipbyuef1;
|
||||
import 'feedback/feedback_decision.dart' as _idsmz0xa;
|
||||
|
|
@ -39,6 +41,8 @@ import 'tag/tag.dart' as _ie8t3ar4;
|
|||
/// shared packages.
|
||||
final List<_is.Table> syncTables = [
|
||||
_ipb7vkxr.Asset.t,
|
||||
_ikd6xdrt.AssistantConversation.t,
|
||||
_i5vmmfj2.AssistantTurn.t,
|
||||
_ipiw1cmx.Card.t,
|
||||
_ipbyuef1.CardRevision.t,
|
||||
_i6jz6nyq.CardTag.t,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,218 @@
|
|||
{
|
||||
"__className__": "serverpod.DatabaseMigration",
|
||||
"actions": [
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationAction",
|
||||
"type": "createTable",
|
||||
"createTable": {
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "assistant_conversation",
|
||||
"dartName": "AssistantConversation",
|
||||
"module": "halkyon_learn",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "assistant_conversation_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "assistant_conversation_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.DatabaseMigrationAction",
|
||||
"type": "createTable",
|
||||
"createTable": {
|
||||
"__className__": "serverpod.TableDefinition",
|
||||
"name": "assistant_turn",
|
||||
"dartName": "AssistantTurn",
|
||||
"module": "halkyon_learn",
|
||||
"schema": "public",
|
||||
"columns": [
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "id",
|
||||
"fieldName": "id",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"columnDefault": "random_v7",
|
||||
"dartType": "UuidValue?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "spaceId",
|
||||
"fieldName": "spaceId",
|
||||
"columnType": 6,
|
||||
"isNullable": true,
|
||||
"dartType": "int?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "conversationId",
|
||||
"fieldName": "conversationId",
|
||||
"columnType": 7,
|
||||
"isNullable": false,
|
||||
"dartType": "UuidValue"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "keyId",
|
||||
"fieldName": "keyId",
|
||||
"columnType": 0,
|
||||
"isNullable": true,
|
||||
"dartType": "String?"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "payload",
|
||||
"fieldName": "payload",
|
||||
"columnType": 5,
|
||||
"isNullable": false,
|
||||
"dartType": "dart:typed_data:ByteData"
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ColumnDefinition",
|
||||
"name": "nonce",
|
||||
"fieldName": "nonce",
|
||||
"columnType": 5,
|
||||
"isNullable": true,
|
||||
"dartType": "dart:typed_data:ByteData?"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "assistant_turn_fk_0",
|
||||
"columns": [
|
||||
"spaceId"
|
||||
],
|
||||
"referenceTable": "offline_sync_spaces",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.ForeignKeyDefinition",
|
||||
"constraintName": "assistant_turn_fk_1",
|
||||
"columns": [
|
||||
"conversationId"
|
||||
],
|
||||
"referenceTable": "assistant_conversation",
|
||||
"referenceTableSchema": "public",
|
||||
"referenceColumns": [
|
||||
"id"
|
||||
],
|
||||
"onUpdate": 3,
|
||||
"onDelete": 4,
|
||||
"deferrable": "initiallyDeferred"
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "assistant_turn_space_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "spaceId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
},
|
||||
{
|
||||
"__className__": "serverpod.IndexDefinition",
|
||||
"indexName": "assistant_turn_conversation_idx",
|
||||
"elements": [
|
||||
{
|
||||
"__className__": "serverpod.IndexElementDefinition",
|
||||
"type": 0,
|
||||
"definition": "conversationId"
|
||||
}
|
||||
],
|
||||
"type": "btree",
|
||||
"isUnique": false,
|
||||
"isPrimary": false
|
||||
}
|
||||
],
|
||||
"managed": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"warnings": [],
|
||||
"migrationApiVersion": 1
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
BEGIN;
|
||||
|
||||
--
|
||||
-- Function: gen_random_uuid_v7()
|
||||
-- Source: https://gist.github.com/kjmph/5bd772b2c2df145aa645b837da7eca74
|
||||
-- License: MIT (copyright notice included on the generator source code).
|
||||
--
|
||||
create or replace function gen_random_uuid_v7()
|
||||
returns uuid
|
||||
as $$
|
||||
begin
|
||||
-- use random v4 uuid as starting point (which has the same variant we need)
|
||||
-- then overlay timestamp
|
||||
-- then set version 7 by flipping the 2 and 1 bit in the version 4 string
|
||||
return encode(
|
||||
set_bit(
|
||||
set_bit(
|
||||
overlay(uuid_send(gen_random_uuid())
|
||||
placing substring(int8send(floor(extract(epoch from clock_timestamp()) * 1000)::bigint) from 3)
|
||||
from 1 for 6
|
||||
),
|
||||
52, 1
|
||||
),
|
||||
53, 1
|
||||
),
|
||||
'hex')::uuid;
|
||||
end
|
||||
$$
|
||||
language plpgsql
|
||||
volatile;
|
||||
|
||||
--
|
||||
-- ACTION CREATE TABLE
|
||||
--
|
||||
CREATE TABLE "assistant_conversation" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid_v7(),
|
||||
"spaceId" bigint,
|
||||
"keyId" text,
|
||||
"payload" bytea NOT NULL,
|
||||
"nonce" bytea
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX "assistant_conversation_space_idx" ON "assistant_conversation" USING btree ("spaceId");
|
||||
|
||||
--
|
||||
-- ACTION CREATE TABLE
|
||||
--
|
||||
CREATE TABLE "assistant_turn" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid_v7(),
|
||||
"spaceId" bigint,
|
||||
"conversationId" uuid NOT NULL,
|
||||
"keyId" text,
|
||||
"payload" bytea NOT NULL,
|
||||
"nonce" bytea
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX "assistant_turn_space_idx" ON "assistant_turn" USING btree ("spaceId");
|
||||
CREATE INDEX "assistant_turn_conversation_idx" ON "assistant_turn" USING btree ("conversationId");
|
||||
|
||||
--
|
||||
-- ACTION CREATE FOREIGN KEY
|
||||
--
|
||||
ALTER TABLE ONLY "assistant_conversation"
|
||||
ADD CONSTRAINT "assistant_conversation_fk_0"
|
||||
FOREIGN KEY("spaceId")
|
||||
REFERENCES "offline_sync_spaces"("id")
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE NO ACTION;
|
||||
|
||||
--
|
||||
-- ACTION CREATE FOREIGN KEY
|
||||
--
|
||||
ALTER TABLE ONLY "assistant_turn"
|
||||
ADD CONSTRAINT "assistant_turn_fk_0"
|
||||
FOREIGN KEY("spaceId")
|
||||
REFERENCES "offline_sync_spaces"("id")
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE NO ACTION;
|
||||
ALTER TABLE ONLY "assistant_turn"
|
||||
ADD CONSTRAINT "assistant_turn_fk_1"
|
||||
FOREIGN KEY("conversationId")
|
||||
REFERENCES "assistant_conversation"("id")
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE NO ACTION
|
||||
DEFERRABLE INITIALLY DEFERRED;
|
||||
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR halkyon_learn
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('halkyon_learn', '20261025184004860-assistant-conversations', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20261025184004860-assistant-conversations', "timestamp" = now();
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR halkyon_base
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('halkyon_base', '20261025165102522-assistants', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20261025165102522-assistants', "timestamp" = now();
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR serverpod
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('serverpod', '20260824182259319', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20260824182259319', "timestamp" = now();
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR serverpod_auth_idp
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('serverpod_auth_idp', '20260924105404509', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20260924105404509', "timestamp" = now();
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR serverpod_offline_sync
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('serverpod_offline_sync', '20260914143806119', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20260914143806119', "timestamp" = now();
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR halkyon_oidc
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('halkyon_oidc', '20261023180644988', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20261023180644988', "timestamp" = now();
|
||||
|
||||
--
|
||||
-- MIGRATION VERSION FOR serverpod_auth_core
|
||||
--
|
||||
INSERT INTO "serverpod_migrations" ("module", "version", "timestamp")
|
||||
VALUES ('serverpod_auth_core', '20260924105232991', now())
|
||||
ON CONFLICT ("module")
|
||||
DO UPDATE SET "version" = '20260924105232991', "timestamp" = now();
|
||||
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -50,3 +50,4 @@
|
|||
20261023192913178-simplelogin-keys
|
||||
20261025135744595-waiting-accounts
|
||||
20261025165102861-assistants
|
||||
20261025184004860-assistant-conversations
|
||||
|
|
|
|||
Loading…
Reference in a new issue