From 93c6fa6e5346bd7ea6ff34fa92b97c4b4a071289 Mon Sep 17 00:00:00 2001
From: LittleSheep <littlesheep.code@hotmail.com>
Date: Tue, 4 Mar 2025 21:49:24 +0800
Subject: [PATCH] :card_file_box: Add more cache ability to local database

---
 .../my_database/drift_schema_v3.json          |    1 +
 lib/database/account.dart                     |   40 +
 lib/database/attachment.dart                  |   45 +
 lib/database/chat.dart                        |   41 +
 lib/database/database.dart                    |   17 +-
 lib/database/database.g.dart                  | 1532 +++++++++++++++-
 lib/database/database.steps.dart              |  206 +++
 test/drift/my_database/generated/schema.dart  |    5 +-
 .../my_database/generated/schema_v3.dart      | 1553 +++++++++++++++++
 9 files changed, 3433 insertions(+), 7 deletions(-)
 create mode 100644 drift_schemas/my_database/drift_schema_v3.json
 create mode 100644 lib/database/account.dart
 create mode 100644 lib/database/attachment.dart
 create mode 100644 test/drift/my_database/generated/schema_v3.dart

diff --git a/drift_schemas/my_database/drift_schema_v3.json b/drift_schemas/my_database/drift_schema_v3.json
new file mode 100644
index 0000000..2ad8682
--- /dev/null
+++ b/drift_schemas/my_database/drift_schema_v3.json
@@ -0,0 +1 @@
+{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.2.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"sn_local_chat_channel","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"alias","getter_name":"alias","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"content","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SnChannelConverter()","dart_type_name":"SnChannel"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":1,"references":[],"type":"table","data":{"name":"sn_local_chat_message","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"channel_id","getter_name":"channelId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"sender_id","getter_name":"senderId","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"content","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SnMessageConverter()","dart_type_name":"SnChatMessage"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":2,"references":[],"type":"table","data":{"name":"sn_local_channel_member","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"channel_id","getter_name":"channelId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"account_id","getter_name":"accountId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"content","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"SnChannelMemberConverter()","dart_type_name":"SnChannelMember"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":3,"references":[],"type":"table","data":{"name":"sn_local_key_pair","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"account_id","getter_name":"accountId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"public_key","getter_name":"publicKey","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"private_key","getter_name":"privateKey","moor_type":"string","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"is_active","getter_name":"isActive","moor_type":"bool","nullable":false,"customConstraints":null,"defaultConstraints":"CHECK (\"is_active\" IN (0, 1))","dialectAwareDefaultConstraints":{"sqlite":"CHECK (\"is_active\" IN (0, 1))"},"default_dart":"const CustomExpression('0')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[],"explicit_pk":["id"]}},{"id":4,"references":[],"type":"table","data":{"name":"sn_local_account","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"name","getter_name":"name","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"content","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SnAccountConverter()","dart_type_name":"SnAccount"}},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":5,"references":[],"type":"table","data":{"name":"sn_local_attachment","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","dialectAwareDefaultConstraints":{"sqlite":"PRIMARY KEY AUTOINCREMENT"},"default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"rid","getter_name":"rid","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"UNIQUE","dialectAwareDefaultConstraints":{"sqlite":"UNIQUE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"uuid","getter_name":"uuid","moor_type":"string","nullable":false,"customConstraints":null,"defaultConstraints":"UNIQUE","dialectAwareDefaultConstraints":{"sqlite":"UNIQUE"},"default_dart":null,"default_client_dart":null,"dsl_features":["unknown"]},{"name":"content","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[],"type_converter":{"dart_expr":"const SnAttachmentConverter()","dart_type_name":"SnAttachment"}},{"name":"account_id","getter_name":"accountId","moor_type":"int","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"created_at","getter_name":"createdAt","moor_type":"dateTime","nullable":false,"customConstraints":null,"default_dart":"const CustomExpression('CAST(strftime(\\'%s\\', CURRENT_TIMESTAMP) AS INTEGER)')","default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}},{"id":6,"references":[0],"type":"index","data":{"on":0,"name":"idx_channel_alias","sql":null,"unique":false,"columns":["alias"]}},{"id":7,"references":[1],"type":"index","data":{"on":1,"name":"idx_chat_channel","sql":null,"unique":false,"columns":["channel_id"]}},{"id":8,"references":[4],"type":"index","data":{"on":4,"name":"idx_account_name","sql":null,"unique":false,"columns":["name"]}},{"id":9,"references":[5],"type":"index","data":{"on":5,"name":"idx_attachment_rid","sql":null,"unique":false,"columns":["rid"]}},{"id":10,"references":[5],"type":"index","data":{"on":5,"name":"idx_attachment_account","sql":null,"unique":false,"columns":["account_id"]}}]}
\ No newline at end of file
diff --git a/lib/database/account.dart b/lib/database/account.dart
new file mode 100644
index 0000000..c061174
--- /dev/null
+++ b/lib/database/account.dart
@@ -0,0 +1,40 @@
+import 'dart:convert';
+
+import 'package:drift/drift.dart';
+import 'package:surface/types/account.dart';
+
+class SnAccountConverter extends TypeConverter<SnAccount, String>
+    with JsonTypeConverter2<SnAccount, String, Map<String, Object?>> {
+  const SnAccountConverter();
+
+  @override
+  SnAccount fromSql(String fromDb) {
+    return fromJson(jsonDecode(fromDb) as Map<String, dynamic>);
+  }
+
+  @override
+  String toSql(SnAccount value) {
+    return jsonEncode(toJson(value));
+  }
+
+  @override
+  SnAccount fromJson(Map<String, Object?> json) {
+    return SnAccount.fromJson(json);
+  }
+
+  @override
+  Map<String, Object?> toJson(SnAccount value) {
+    return value.toJson();
+  }
+}
+
+@TableIndex(name: 'idx_account_name', columns: {#name})
+class SnLocalAccount extends Table {
+  IntColumn get id => integer().autoIncrement()();
+
+  TextColumn get name => text()();
+
+  TextColumn get content => text().map(const SnAccountConverter())();
+
+  DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
+}
diff --git a/lib/database/attachment.dart b/lib/database/attachment.dart
new file mode 100644
index 0000000..0fccd7f
--- /dev/null
+++ b/lib/database/attachment.dart
@@ -0,0 +1,45 @@
+import 'dart:convert';
+
+import 'package:drift/drift.dart';
+import 'package:surface/types/attachment.dart';
+
+class SnAttachmentConverter extends TypeConverter<SnAttachment, String>
+    with JsonTypeConverter2<SnAttachment, String, Map<String, Object?>> {
+  const SnAttachmentConverter();
+
+  @override
+  SnAttachment fromSql(String fromDb) {
+    return fromJson(jsonDecode(fromDb) as Map<String, dynamic>);
+  }
+
+  @override
+  String toSql(SnAttachment value) {
+    return jsonEncode(toJson(value));
+  }
+
+  @override
+  SnAttachment fromJson(Map<String, Object?> json) {
+    return SnAttachment.fromJson(json);
+  }
+
+  @override
+  Map<String, Object?> toJson(SnAttachment value) {
+    return value.toJson();
+  }
+}
+
+@TableIndex(name: 'idx_attachment_rid', columns: {#rid})
+@TableIndex(name: 'idx_attachment_account', columns: {#accountId})
+class SnLocalAttachment extends Table {
+  IntColumn get id => integer().autoIncrement()();
+
+  TextColumn get rid => text().unique()();
+
+  TextColumn get uuid => text().unique()();
+
+  TextColumn get content => text().map(const SnAttachmentConverter())();
+
+  IntColumn get accountId => integer()();
+
+  DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
+}
diff --git a/lib/database/chat.dart b/lib/database/chat.dart
index 96cb229..80da902 100644
--- a/lib/database/chat.dart
+++ b/lib/database/chat.dart
@@ -28,6 +28,7 @@ class SnChannelConverter extends TypeConverter<SnChannel, String>
   }
 }
 
+@TableIndex(name: 'idx_channel_alias', columns: {#alias})
 class SnLocalChatChannel extends Table {
   IntColumn get id => integer().autoIncrement()();
 
@@ -63,12 +64,52 @@ class SnMessageConverter extends TypeConverter<SnChatMessage, String>
   }
 }
 
+@TableIndex(name: 'idx_chat_channel', columns: {#channelId})
 class SnLocalChatMessage extends Table {
   IntColumn get id => integer().autoIncrement()();
 
   IntColumn get channelId => integer()();
 
+  IntColumn get senderId => integer().nullable()();
+
   TextColumn get content => text().map(const SnMessageConverter())();
 
   DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
 }
+
+class SnChannelMemberConverter extends TypeConverter<SnChannelMember, String>
+    with JsonTypeConverter2<SnChannelMember, String, Map<String, Object?>> {
+  const SnChannelMemberConverter();
+
+  @override
+  SnChannelMember fromSql(String fromDb) {
+    return fromJson(jsonDecode(fromDb) as Map<String, dynamic>);
+  }
+
+  @override
+  String toSql(SnChannelMember value) {
+    return jsonEncode(toJson(value));
+  }
+
+  @override
+  SnChannelMember fromJson(Map<String, Object?> json) {
+    return SnChannelMember.fromJson(json);
+  }
+
+  @override
+  Map<String, Object?> toJson(SnChannelMember value) {
+    return value.toJson();
+  }
+}
+
+class SnLocalChannelMember extends Table {
+  IntColumn get id => integer().autoIncrement()();
+
+  IntColumn get channelId => integer()();
+
+  IntColumn get accountId => integer()();
+
+  TextColumn get content => text().map(SnChannelMemberConverter())();
+
+  DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
+}
diff --git a/lib/database/database.dart b/lib/database/database.dart
index 8decd52..5c5c95d 100644
--- a/lib/database/database.dart
+++ b/lib/database/database.dart
@@ -1,19 +1,30 @@
 import 'package:drift/drift.dart';
 import 'package:drift_flutter/drift_flutter.dart';
 import 'package:path_provider/path_provider.dart';
+import 'package:surface/database/account.dart';
+import 'package:surface/database/attachment.dart';
 import 'package:surface/database/chat.dart';
 import 'package:surface/database/database.steps.dart';
 import 'package:surface/database/keypair.dart';
 import 'package:surface/types/chat.dart';
+import 'package:surface/types/attachment.dart';
+import 'package:surface/types/account.dart';
 
 part 'database.g.dart';
 
-@DriftDatabase(tables: [SnLocalChatChannel, SnLocalChatMessage, SnLocalKeyPair])
+@DriftDatabase(tables: [
+  SnLocalChatChannel,
+  SnLocalChatMessage,
+  SnLocalChannelMember,
+  SnLocalKeyPair,
+  SnLocalAccount,
+  SnLocalAttachment,
+])
 class AppDatabase extends _$AppDatabase {
   AppDatabase([QueryExecutor? e]) : super(e ?? _openConnection());
 
   @override
-  int get schemaVersion => 2;
+  int get schemaVersion => 3;
 
   static QueryExecutor _openConnection() {
     return driftDatabase(
@@ -33,6 +44,8 @@ class AppDatabase extends _$AppDatabase {
     return MigrationStrategy(
       onUpgrade: stepByStep(from1To2: (m, schema) async {
         // Nothing else to do here
+      }, from2To3: (m, schema) async {
+        // Nothing else to do here, too
       }),
     );
   }
diff --git a/lib/database/database.g.dart b/lib/database/database.g.dart
index 57c1e76..797b343 100644
--- a/lib/database/database.g.dart
+++ b/lib/database/database.g.dart
@@ -289,6 +289,12 @@ class $SnLocalChatMessageTable extends SnLocalChatMessage
   late final GeneratedColumn<int> channelId = GeneratedColumn<int>(
       'channel_id', aliasedName, false,
       type: DriftSqlType.int, requiredDuringInsert: true);
+  static const VerificationMeta _senderIdMeta =
+      const VerificationMeta('senderId');
+  @override
+  late final GeneratedColumn<int> senderId = GeneratedColumn<int>(
+      'sender_id', aliasedName, true,
+      type: DriftSqlType.int, requiredDuringInsert: false);
   static const VerificationMeta _contentMeta =
       const VerificationMeta('content');
   @override
@@ -306,7 +312,8 @@ class $SnLocalChatMessageTable extends SnLocalChatMessage
       requiredDuringInsert: false,
       defaultValue: currentDateAndTime);
   @override
-  List<GeneratedColumn> get $columns => [id, channelId, content, createdAt];
+  List<GeneratedColumn> get $columns =>
+      [id, channelId, senderId, content, createdAt];
   @override
   String get aliasedName => _alias ?? actualTableName;
   @override
@@ -327,6 +334,10 @@ class $SnLocalChatMessageTable extends SnLocalChatMessage
     } else if (isInserting) {
       context.missing(_channelIdMeta);
     }
+    if (data.containsKey('sender_id')) {
+      context.handle(_senderIdMeta,
+          senderId.isAcceptableOrUnknown(data['sender_id']!, _senderIdMeta));
+    }
     context.handle(_contentMeta, const VerificationResult.success());
     if (data.containsKey('created_at')) {
       context.handle(_createdAtMeta,
@@ -345,6 +356,8 @@ class $SnLocalChatMessageTable extends SnLocalChatMessage
           .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
       channelId: attachedDatabase.typeMapping
           .read(DriftSqlType.int, data['${effectivePrefix}channel_id'])!,
+      senderId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}sender_id']),
       content: $SnLocalChatMessageTable.$convertercontent.fromSql(
           attachedDatabase.typeMapping
               .read(DriftSqlType.string, data['${effectivePrefix}content'])!),
@@ -366,11 +379,13 @@ class SnLocalChatMessageData extends DataClass
     implements Insertable<SnLocalChatMessageData> {
   final int id;
   final int channelId;
+  final int? senderId;
   final SnChatMessage content;
   final DateTime createdAt;
   const SnLocalChatMessageData(
       {required this.id,
       required this.channelId,
+      this.senderId,
       required this.content,
       required this.createdAt});
   @override
@@ -378,6 +393,9 @@ class SnLocalChatMessageData extends DataClass
     final map = <String, Expression>{};
     map['id'] = Variable<int>(id);
     map['channel_id'] = Variable<int>(channelId);
+    if (!nullToAbsent || senderId != null) {
+      map['sender_id'] = Variable<int>(senderId);
+    }
     {
       map['content'] = Variable<String>(
           $SnLocalChatMessageTable.$convertercontent.toSql(content));
@@ -390,6 +408,9 @@ class SnLocalChatMessageData extends DataClass
     return SnLocalChatMessageCompanion(
       id: Value(id),
       channelId: Value(channelId),
+      senderId: senderId == null && nullToAbsent
+          ? const Value.absent()
+          : Value(senderId),
       content: Value(content),
       createdAt: Value(createdAt),
     );
@@ -401,6 +422,7 @@ class SnLocalChatMessageData extends DataClass
     return SnLocalChatMessageData(
       id: serializer.fromJson<int>(json['id']),
       channelId: serializer.fromJson<int>(json['channelId']),
+      senderId: serializer.fromJson<int?>(json['senderId']),
       content: $SnLocalChatMessageTable.$convertercontent
           .fromJson(serializer.fromJson<Map<String, Object?>>(json['content'])),
       createdAt: serializer.fromJson<DateTime>(json['createdAt']),
@@ -412,6 +434,7 @@ class SnLocalChatMessageData extends DataClass
     return <String, dynamic>{
       'id': serializer.toJson<int>(id),
       'channelId': serializer.toJson<int>(channelId),
+      'senderId': serializer.toJson<int?>(senderId),
       'content': serializer.toJson<Map<String, Object?>>(
           $SnLocalChatMessageTable.$convertercontent.toJson(content)),
       'createdAt': serializer.toJson<DateTime>(createdAt),
@@ -421,11 +444,13 @@ class SnLocalChatMessageData extends DataClass
   SnLocalChatMessageData copyWith(
           {int? id,
           int? channelId,
+          Value<int?> senderId = const Value.absent(),
           SnChatMessage? content,
           DateTime? createdAt}) =>
       SnLocalChatMessageData(
         id: id ?? this.id,
         channelId: channelId ?? this.channelId,
+        senderId: senderId.present ? senderId.value : this.senderId,
         content: content ?? this.content,
         createdAt: createdAt ?? this.createdAt,
       );
@@ -433,6 +458,7 @@ class SnLocalChatMessageData extends DataClass
     return SnLocalChatMessageData(
       id: data.id.present ? data.id.value : this.id,
       channelId: data.channelId.present ? data.channelId.value : this.channelId,
+      senderId: data.senderId.present ? data.senderId.value : this.senderId,
       content: data.content.present ? data.content.value : this.content,
       createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
     );
@@ -443,6 +469,7 @@ class SnLocalChatMessageData extends DataClass
     return (StringBuffer('SnLocalChatMessageData(')
           ..write('id: $id, ')
           ..write('channelId: $channelId, ')
+          ..write('senderId: $senderId, ')
           ..write('content: $content, ')
           ..write('createdAt: $createdAt')
           ..write(')'))
@@ -450,13 +477,14 @@ class SnLocalChatMessageData extends DataClass
   }
 
   @override
-  int get hashCode => Object.hash(id, channelId, content, createdAt);
+  int get hashCode => Object.hash(id, channelId, senderId, content, createdAt);
   @override
   bool operator ==(Object other) =>
       identical(this, other) ||
       (other is SnLocalChatMessageData &&
           other.id == this.id &&
           other.channelId == this.channelId &&
+          other.senderId == this.senderId &&
           other.content == this.content &&
           other.createdAt == this.createdAt);
 }
@@ -465,17 +493,20 @@ class SnLocalChatMessageCompanion
     extends UpdateCompanion<SnLocalChatMessageData> {
   final Value<int> id;
   final Value<int> channelId;
+  final Value<int?> senderId;
   final Value<SnChatMessage> content;
   final Value<DateTime> createdAt;
   const SnLocalChatMessageCompanion({
     this.id = const Value.absent(),
     this.channelId = const Value.absent(),
+    this.senderId = const Value.absent(),
     this.content = const Value.absent(),
     this.createdAt = const Value.absent(),
   });
   SnLocalChatMessageCompanion.insert({
     this.id = const Value.absent(),
     required int channelId,
+    this.senderId = const Value.absent(),
     required SnChatMessage content,
     this.createdAt = const Value.absent(),
   })  : channelId = Value(channelId),
@@ -483,12 +514,14 @@ class SnLocalChatMessageCompanion
   static Insertable<SnLocalChatMessageData> custom({
     Expression<int>? id,
     Expression<int>? channelId,
+    Expression<int>? senderId,
     Expression<String>? content,
     Expression<DateTime>? createdAt,
   }) {
     return RawValuesInsertable({
       if (id != null) 'id': id,
       if (channelId != null) 'channel_id': channelId,
+      if (senderId != null) 'sender_id': senderId,
       if (content != null) 'content': content,
       if (createdAt != null) 'created_at': createdAt,
     });
@@ -497,11 +530,13 @@ class SnLocalChatMessageCompanion
   SnLocalChatMessageCompanion copyWith(
       {Value<int>? id,
       Value<int>? channelId,
+      Value<int?>? senderId,
       Value<SnChatMessage>? content,
       Value<DateTime>? createdAt}) {
     return SnLocalChatMessageCompanion(
       id: id ?? this.id,
       channelId: channelId ?? this.channelId,
+      senderId: senderId ?? this.senderId,
       content: content ?? this.content,
       createdAt: createdAt ?? this.createdAt,
     );
@@ -516,6 +551,9 @@ class SnLocalChatMessageCompanion
     if (channelId.present) {
       map['channel_id'] = Variable<int>(channelId.value);
     }
+    if (senderId.present) {
+      map['sender_id'] = Variable<int>(senderId.value);
+    }
     if (content.present) {
       map['content'] = Variable<String>(
           $SnLocalChatMessageTable.$convertercontent.toSql(content.value));
@@ -531,6 +569,317 @@ class SnLocalChatMessageCompanion
     return (StringBuffer('SnLocalChatMessageCompanion(')
           ..write('id: $id, ')
           ..write('channelId: $channelId, ')
+          ..write('senderId: $senderId, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class $SnLocalChannelMemberTable extends SnLocalChannelMember
+    with TableInfo<$SnLocalChannelMemberTable, SnLocalChannelMemberData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  $SnLocalChannelMemberTable(this.attachedDatabase, [this._alias]);
+  static const VerificationMeta _idMeta = const VerificationMeta('id');
+  @override
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  static const VerificationMeta _channelIdMeta =
+      const VerificationMeta('channelId');
+  @override
+  late final GeneratedColumn<int> channelId = GeneratedColumn<int>(
+      'channel_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  static const VerificationMeta _accountIdMeta =
+      const VerificationMeta('accountId');
+  @override
+  late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
+      'account_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  static const VerificationMeta _contentMeta =
+      const VerificationMeta('content');
+  @override
+  late final GeneratedColumnWithTypeConverter<SnChannelMember, String> content =
+      GeneratedColumn<String>('content', aliasedName, false,
+              type: DriftSqlType.string, requiredDuringInsert: true)
+          .withConverter<SnChannelMember>(
+              $SnLocalChannelMemberTable.$convertercontent);
+  static const VerificationMeta _createdAtMeta =
+      const VerificationMeta('createdAt');
+  @override
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: currentDateAndTime);
+  @override
+  List<GeneratedColumn> get $columns =>
+      [id, channelId, accountId, content, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_channel_member';
+  @override
+  VerificationContext validateIntegrity(
+      Insertable<SnLocalChannelMemberData> instance,
+      {bool isInserting = false}) {
+    final context = VerificationContext();
+    final data = instance.toColumns(true);
+    if (data.containsKey('id')) {
+      context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
+    }
+    if (data.containsKey('channel_id')) {
+      context.handle(_channelIdMeta,
+          channelId.isAcceptableOrUnknown(data['channel_id']!, _channelIdMeta));
+    } else if (isInserting) {
+      context.missing(_channelIdMeta);
+    }
+    if (data.containsKey('account_id')) {
+      context.handle(_accountIdMeta,
+          accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta));
+    } else if (isInserting) {
+      context.missing(_accountIdMeta);
+    }
+    context.handle(_contentMeta, const VerificationResult.success());
+    if (data.containsKey('created_at')) {
+      context.handle(_createdAtMeta,
+          createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
+    }
+    return context;
+  }
+
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalChannelMemberData map(Map<String, dynamic> data,
+      {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalChannelMemberData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      channelId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}channel_id'])!,
+      accountId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}account_id'])!,
+      content: $SnLocalChannelMemberTable.$convertercontent.fromSql(
+          attachedDatabase.typeMapping
+              .read(DriftSqlType.string, data['${effectivePrefix}content'])!),
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  $SnLocalChannelMemberTable createAlias(String alias) {
+    return $SnLocalChannelMemberTable(attachedDatabase, alias);
+  }
+
+  static JsonTypeConverter2<SnChannelMember, String, Map<String, Object?>>
+      $convertercontent = SnChannelMemberConverter();
+}
+
+class SnLocalChannelMemberData extends DataClass
+    implements Insertable<SnLocalChannelMemberData> {
+  final int id;
+  final int channelId;
+  final int accountId;
+  final SnChannelMember content;
+  final DateTime createdAt;
+  const SnLocalChannelMemberData(
+      {required this.id,
+      required this.channelId,
+      required this.accountId,
+      required this.content,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['channel_id'] = Variable<int>(channelId);
+    map['account_id'] = Variable<int>(accountId);
+    {
+      map['content'] = Variable<String>(
+          $SnLocalChannelMemberTable.$convertercontent.toSql(content));
+    }
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalChannelMemberCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalChannelMemberCompanion(
+      id: Value(id),
+      channelId: Value(channelId),
+      accountId: Value(accountId),
+      content: Value(content),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalChannelMemberData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalChannelMemberData(
+      id: serializer.fromJson<int>(json['id']),
+      channelId: serializer.fromJson<int>(json['channelId']),
+      accountId: serializer.fromJson<int>(json['accountId']),
+      content: $SnLocalChannelMemberTable.$convertercontent
+          .fromJson(serializer.fromJson<Map<String, Object?>>(json['content'])),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'channelId': serializer.toJson<int>(channelId),
+      'accountId': serializer.toJson<int>(accountId),
+      'content': serializer.toJson<Map<String, Object?>>(
+          $SnLocalChannelMemberTable.$convertercontent.toJson(content)),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalChannelMemberData copyWith(
+          {int? id,
+          int? channelId,
+          int? accountId,
+          SnChannelMember? content,
+          DateTime? createdAt}) =>
+      SnLocalChannelMemberData(
+        id: id ?? this.id,
+        channelId: channelId ?? this.channelId,
+        accountId: accountId ?? this.accountId,
+        content: content ?? this.content,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalChannelMemberData copyWithCompanion(
+      SnLocalChannelMemberCompanion data) {
+    return SnLocalChannelMemberData(
+      id: data.id.present ? data.id.value : this.id,
+      channelId: data.channelId.present ? data.channelId.value : this.channelId,
+      accountId: data.accountId.present ? data.accountId.value : this.accountId,
+      content: data.content.present ? data.content.value : this.content,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChannelMemberData(')
+          ..write('id: $id, ')
+          ..write('channelId: $channelId, ')
+          ..write('accountId: $accountId, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, channelId, accountId, content, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalChannelMemberData &&
+          other.id == this.id &&
+          other.channelId == this.channelId &&
+          other.accountId == this.accountId &&
+          other.content == this.content &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalChannelMemberCompanion
+    extends UpdateCompanion<SnLocalChannelMemberData> {
+  final Value<int> id;
+  final Value<int> channelId;
+  final Value<int> accountId;
+  final Value<SnChannelMember> content;
+  final Value<DateTime> createdAt;
+  const SnLocalChannelMemberCompanion({
+    this.id = const Value.absent(),
+    this.channelId = const Value.absent(),
+    this.accountId = const Value.absent(),
+    this.content = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalChannelMemberCompanion.insert({
+    this.id = const Value.absent(),
+    required int channelId,
+    required int accountId,
+    required SnChannelMember content,
+    this.createdAt = const Value.absent(),
+  })  : channelId = Value(channelId),
+        accountId = Value(accountId),
+        content = Value(content);
+  static Insertable<SnLocalChannelMemberData> custom({
+    Expression<int>? id,
+    Expression<int>? channelId,
+    Expression<int>? accountId,
+    Expression<String>? content,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (channelId != null) 'channel_id': channelId,
+      if (accountId != null) 'account_id': accountId,
+      if (content != null) 'content': content,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalChannelMemberCompanion copyWith(
+      {Value<int>? id,
+      Value<int>? channelId,
+      Value<int>? accountId,
+      Value<SnChannelMember>? content,
+      Value<DateTime>? createdAt}) {
+    return SnLocalChannelMemberCompanion(
+      id: id ?? this.id,
+      channelId: channelId ?? this.channelId,
+      accountId: accountId ?? this.accountId,
+      content: content ?? this.content,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (channelId.present) {
+      map['channel_id'] = Variable<int>(channelId.value);
+    }
+    if (accountId.present) {
+      map['account_id'] = Variable<int>(accountId.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(
+          $SnLocalChannelMemberTable.$convertercontent.toSql(content.value));
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChannelMemberCompanion(')
+          ..write('id: $id, ')
+          ..write('channelId: $channelId, ')
+          ..write('accountId: $accountId, ')
           ..write('content: $content, ')
           ..write('createdAt: $createdAt')
           ..write(')'))
@@ -854,6 +1203,616 @@ class SnLocalKeyPairCompanion extends UpdateCompanion<SnLocalKeyPairData> {
   }
 }
 
+class $SnLocalAccountTable extends SnLocalAccount
+    with TableInfo<$SnLocalAccountTable, SnLocalAccountData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  $SnLocalAccountTable(this.attachedDatabase, [this._alias]);
+  static const VerificationMeta _idMeta = const VerificationMeta('id');
+  @override
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  static const VerificationMeta _nameMeta = const VerificationMeta('name');
+  @override
+  late final GeneratedColumn<String> name = GeneratedColumn<String>(
+      'name', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  static const VerificationMeta _contentMeta =
+      const VerificationMeta('content');
+  @override
+  late final GeneratedColumnWithTypeConverter<SnAccount, String> content =
+      GeneratedColumn<String>('content', aliasedName, false,
+              type: DriftSqlType.string, requiredDuringInsert: true)
+          .withConverter<SnAccount>($SnLocalAccountTable.$convertercontent);
+  static const VerificationMeta _createdAtMeta =
+      const VerificationMeta('createdAt');
+  @override
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: currentDateAndTime);
+  @override
+  List<GeneratedColumn> get $columns => [id, name, content, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_account';
+  @override
+  VerificationContext validateIntegrity(Insertable<SnLocalAccountData> instance,
+      {bool isInserting = false}) {
+    final context = VerificationContext();
+    final data = instance.toColumns(true);
+    if (data.containsKey('id')) {
+      context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
+    }
+    if (data.containsKey('name')) {
+      context.handle(
+          _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta));
+    } else if (isInserting) {
+      context.missing(_nameMeta);
+    }
+    context.handle(_contentMeta, const VerificationResult.success());
+    if (data.containsKey('created_at')) {
+      context.handle(_createdAtMeta,
+          createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
+    }
+    return context;
+  }
+
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalAccountData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalAccountData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      name: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}name'])!,
+      content: $SnLocalAccountTable.$convertercontent.fromSql(attachedDatabase
+          .typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}content'])!),
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  $SnLocalAccountTable createAlias(String alias) {
+    return $SnLocalAccountTable(attachedDatabase, alias);
+  }
+
+  static JsonTypeConverter2<SnAccount, String, Map<String, Object?>>
+      $convertercontent = const SnAccountConverter();
+}
+
+class SnLocalAccountData extends DataClass
+    implements Insertable<SnLocalAccountData> {
+  final int id;
+  final String name;
+  final SnAccount content;
+  final DateTime createdAt;
+  const SnLocalAccountData(
+      {required this.id,
+      required this.name,
+      required this.content,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['name'] = Variable<String>(name);
+    {
+      map['content'] = Variable<String>(
+          $SnLocalAccountTable.$convertercontent.toSql(content));
+    }
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalAccountCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalAccountCompanion(
+      id: Value(id),
+      name: Value(name),
+      content: Value(content),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalAccountData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalAccountData(
+      id: serializer.fromJson<int>(json['id']),
+      name: serializer.fromJson<String>(json['name']),
+      content: $SnLocalAccountTable.$convertercontent
+          .fromJson(serializer.fromJson<Map<String, Object?>>(json['content'])),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'name': serializer.toJson<String>(name),
+      'content': serializer.toJson<Map<String, Object?>>(
+          $SnLocalAccountTable.$convertercontent.toJson(content)),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalAccountData copyWith(
+          {int? id, String? name, SnAccount? content, DateTime? createdAt}) =>
+      SnLocalAccountData(
+        id: id ?? this.id,
+        name: name ?? this.name,
+        content: content ?? this.content,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalAccountData copyWithCompanion(SnLocalAccountCompanion data) {
+    return SnLocalAccountData(
+      id: data.id.present ? data.id.value : this.id,
+      name: data.name.present ? data.name.value : this.name,
+      content: data.content.present ? data.content.value : this.content,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAccountData(')
+          ..write('id: $id, ')
+          ..write('name: $name, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, name, content, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalAccountData &&
+          other.id == this.id &&
+          other.name == this.name &&
+          other.content == this.content &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalAccountCompanion extends UpdateCompanion<SnLocalAccountData> {
+  final Value<int> id;
+  final Value<String> name;
+  final Value<SnAccount> content;
+  final Value<DateTime> createdAt;
+  const SnLocalAccountCompanion({
+    this.id = const Value.absent(),
+    this.name = const Value.absent(),
+    this.content = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalAccountCompanion.insert({
+    this.id = const Value.absent(),
+    required String name,
+    required SnAccount content,
+    this.createdAt = const Value.absent(),
+  })  : name = Value(name),
+        content = Value(content);
+  static Insertable<SnLocalAccountData> custom({
+    Expression<int>? id,
+    Expression<String>? name,
+    Expression<String>? content,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (name != null) 'name': name,
+      if (content != null) 'content': content,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalAccountCompanion copyWith(
+      {Value<int>? id,
+      Value<String>? name,
+      Value<SnAccount>? content,
+      Value<DateTime>? createdAt}) {
+    return SnLocalAccountCompanion(
+      id: id ?? this.id,
+      name: name ?? this.name,
+      content: content ?? this.content,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (name.present) {
+      map['name'] = Variable<String>(name.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(
+          $SnLocalAccountTable.$convertercontent.toSql(content.value));
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAccountCompanion(')
+          ..write('id: $id, ')
+          ..write('name: $name, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class $SnLocalAttachmentTable extends SnLocalAttachment
+    with TableInfo<$SnLocalAttachmentTable, SnLocalAttachmentData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  $SnLocalAttachmentTable(this.attachedDatabase, [this._alias]);
+  static const VerificationMeta _idMeta = const VerificationMeta('id');
+  @override
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  static const VerificationMeta _ridMeta = const VerificationMeta('rid');
+  @override
+  late final GeneratedColumn<String> rid = GeneratedColumn<String>(
+      'rid', aliasedName, false,
+      type: DriftSqlType.string,
+      requiredDuringInsert: true,
+      defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'));
+  static const VerificationMeta _uuidMeta = const VerificationMeta('uuid');
+  @override
+  late final GeneratedColumn<String> uuid = GeneratedColumn<String>(
+      'uuid', aliasedName, false,
+      type: DriftSqlType.string,
+      requiredDuringInsert: true,
+      defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'));
+  static const VerificationMeta _contentMeta =
+      const VerificationMeta('content');
+  @override
+  late final GeneratedColumnWithTypeConverter<SnAttachment, String> content =
+      GeneratedColumn<String>('content', aliasedName, false,
+              type: DriftSqlType.string, requiredDuringInsert: true)
+          .withConverter<SnAttachment>(
+              $SnLocalAttachmentTable.$convertercontent);
+  static const VerificationMeta _accountIdMeta =
+      const VerificationMeta('accountId');
+  @override
+  late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
+      'account_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  static const VerificationMeta _createdAtMeta =
+      const VerificationMeta('createdAt');
+  @override
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: currentDateAndTime);
+  @override
+  List<GeneratedColumn> get $columns =>
+      [id, rid, uuid, content, accountId, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_attachment';
+  @override
+  VerificationContext validateIntegrity(
+      Insertable<SnLocalAttachmentData> instance,
+      {bool isInserting = false}) {
+    final context = VerificationContext();
+    final data = instance.toColumns(true);
+    if (data.containsKey('id')) {
+      context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
+    }
+    if (data.containsKey('rid')) {
+      context.handle(
+          _ridMeta, rid.isAcceptableOrUnknown(data['rid']!, _ridMeta));
+    } else if (isInserting) {
+      context.missing(_ridMeta);
+    }
+    if (data.containsKey('uuid')) {
+      context.handle(
+          _uuidMeta, uuid.isAcceptableOrUnknown(data['uuid']!, _uuidMeta));
+    } else if (isInserting) {
+      context.missing(_uuidMeta);
+    }
+    context.handle(_contentMeta, const VerificationResult.success());
+    if (data.containsKey('account_id')) {
+      context.handle(_accountIdMeta,
+          accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta));
+    } else if (isInserting) {
+      context.missing(_accountIdMeta);
+    }
+    if (data.containsKey('created_at')) {
+      context.handle(_createdAtMeta,
+          createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
+    }
+    return context;
+  }
+
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalAttachmentData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalAttachmentData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      rid: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}rid'])!,
+      uuid: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}uuid'])!,
+      content: $SnLocalAttachmentTable.$convertercontent.fromSql(
+          attachedDatabase.typeMapping
+              .read(DriftSqlType.string, data['${effectivePrefix}content'])!),
+      accountId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}account_id'])!,
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  $SnLocalAttachmentTable createAlias(String alias) {
+    return $SnLocalAttachmentTable(attachedDatabase, alias);
+  }
+
+  static JsonTypeConverter2<SnAttachment, String, Map<String, Object?>>
+      $convertercontent = const SnAttachmentConverter();
+}
+
+class SnLocalAttachmentData extends DataClass
+    implements Insertable<SnLocalAttachmentData> {
+  final int id;
+  final String rid;
+  final String uuid;
+  final SnAttachment content;
+  final int accountId;
+  final DateTime createdAt;
+  const SnLocalAttachmentData(
+      {required this.id,
+      required this.rid,
+      required this.uuid,
+      required this.content,
+      required this.accountId,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['rid'] = Variable<String>(rid);
+    map['uuid'] = Variable<String>(uuid);
+    {
+      map['content'] = Variable<String>(
+          $SnLocalAttachmentTable.$convertercontent.toSql(content));
+    }
+    map['account_id'] = Variable<int>(accountId);
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalAttachmentCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalAttachmentCompanion(
+      id: Value(id),
+      rid: Value(rid),
+      uuid: Value(uuid),
+      content: Value(content),
+      accountId: Value(accountId),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalAttachmentData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalAttachmentData(
+      id: serializer.fromJson<int>(json['id']),
+      rid: serializer.fromJson<String>(json['rid']),
+      uuid: serializer.fromJson<String>(json['uuid']),
+      content: $SnLocalAttachmentTable.$convertercontent
+          .fromJson(serializer.fromJson<Map<String, Object?>>(json['content'])),
+      accountId: serializer.fromJson<int>(json['accountId']),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'rid': serializer.toJson<String>(rid),
+      'uuid': serializer.toJson<String>(uuid),
+      'content': serializer.toJson<Map<String, Object?>>(
+          $SnLocalAttachmentTable.$convertercontent.toJson(content)),
+      'accountId': serializer.toJson<int>(accountId),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalAttachmentData copyWith(
+          {int? id,
+          String? rid,
+          String? uuid,
+          SnAttachment? content,
+          int? accountId,
+          DateTime? createdAt}) =>
+      SnLocalAttachmentData(
+        id: id ?? this.id,
+        rid: rid ?? this.rid,
+        uuid: uuid ?? this.uuid,
+        content: content ?? this.content,
+        accountId: accountId ?? this.accountId,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalAttachmentData copyWithCompanion(SnLocalAttachmentCompanion data) {
+    return SnLocalAttachmentData(
+      id: data.id.present ? data.id.value : this.id,
+      rid: data.rid.present ? data.rid.value : this.rid,
+      uuid: data.uuid.present ? data.uuid.value : this.uuid,
+      content: data.content.present ? data.content.value : this.content,
+      accountId: data.accountId.present ? data.accountId.value : this.accountId,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAttachmentData(')
+          ..write('id: $id, ')
+          ..write('rid: $rid, ')
+          ..write('uuid: $uuid, ')
+          ..write('content: $content, ')
+          ..write('accountId: $accountId, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, rid, uuid, content, accountId, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalAttachmentData &&
+          other.id == this.id &&
+          other.rid == this.rid &&
+          other.uuid == this.uuid &&
+          other.content == this.content &&
+          other.accountId == this.accountId &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalAttachmentCompanion
+    extends UpdateCompanion<SnLocalAttachmentData> {
+  final Value<int> id;
+  final Value<String> rid;
+  final Value<String> uuid;
+  final Value<SnAttachment> content;
+  final Value<int> accountId;
+  final Value<DateTime> createdAt;
+  const SnLocalAttachmentCompanion({
+    this.id = const Value.absent(),
+    this.rid = const Value.absent(),
+    this.uuid = const Value.absent(),
+    this.content = const Value.absent(),
+    this.accountId = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalAttachmentCompanion.insert({
+    this.id = const Value.absent(),
+    required String rid,
+    required String uuid,
+    required SnAttachment content,
+    required int accountId,
+    this.createdAt = const Value.absent(),
+  })  : rid = Value(rid),
+        uuid = Value(uuid),
+        content = Value(content),
+        accountId = Value(accountId);
+  static Insertable<SnLocalAttachmentData> custom({
+    Expression<int>? id,
+    Expression<String>? rid,
+    Expression<String>? uuid,
+    Expression<String>? content,
+    Expression<int>? accountId,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (rid != null) 'rid': rid,
+      if (uuid != null) 'uuid': uuid,
+      if (content != null) 'content': content,
+      if (accountId != null) 'account_id': accountId,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalAttachmentCompanion copyWith(
+      {Value<int>? id,
+      Value<String>? rid,
+      Value<String>? uuid,
+      Value<SnAttachment>? content,
+      Value<int>? accountId,
+      Value<DateTime>? createdAt}) {
+    return SnLocalAttachmentCompanion(
+      id: id ?? this.id,
+      rid: rid ?? this.rid,
+      uuid: uuid ?? this.uuid,
+      content: content ?? this.content,
+      accountId: accountId ?? this.accountId,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (rid.present) {
+      map['rid'] = Variable<String>(rid.value);
+    }
+    if (uuid.present) {
+      map['uuid'] = Variable<String>(uuid.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(
+          $SnLocalAttachmentTable.$convertercontent.toSql(content.value));
+    }
+    if (accountId.present) {
+      map['account_id'] = Variable<int>(accountId.value);
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAttachmentCompanion(')
+          ..write('id: $id, ')
+          ..write('rid: $rid, ')
+          ..write('uuid: $uuid, ')
+          ..write('content: $content, ')
+          ..write('accountId: $accountId, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
 abstract class _$AppDatabase extends GeneratedDatabase {
   _$AppDatabase(QueryExecutor e) : super(e);
   $AppDatabaseManager get managers => $AppDatabaseManager(this);
@@ -861,13 +1820,39 @@ abstract class _$AppDatabase extends GeneratedDatabase {
       $SnLocalChatChannelTable(this);
   late final $SnLocalChatMessageTable snLocalChatMessage =
       $SnLocalChatMessageTable(this);
+  late final $SnLocalChannelMemberTable snLocalChannelMember =
+      $SnLocalChannelMemberTable(this);
   late final $SnLocalKeyPairTable snLocalKeyPair = $SnLocalKeyPairTable(this);
+  late final $SnLocalAccountTable snLocalAccount = $SnLocalAccountTable(this);
+  late final $SnLocalAttachmentTable snLocalAttachment =
+      $SnLocalAttachmentTable(this);
+  late final Index idxChannelAlias = Index('idx_channel_alias',
+      'CREATE INDEX idx_channel_alias ON sn_local_chat_channel (alias)');
+  late final Index idxChatChannel = Index('idx_chat_channel',
+      'CREATE INDEX idx_chat_channel ON sn_local_chat_message (channel_id)');
+  late final Index idxAccountName = Index('idx_account_name',
+      'CREATE INDEX idx_account_name ON sn_local_account (name)');
+  late final Index idxAttachmentRid = Index('idx_attachment_rid',
+      'CREATE INDEX idx_attachment_rid ON sn_local_attachment (rid)');
+  late final Index idxAttachmentAccount = Index('idx_attachment_account',
+      'CREATE INDEX idx_attachment_account ON sn_local_attachment (account_id)');
   @override
   Iterable<TableInfo<Table, Object?>> get allTables =>
       allSchemaEntities.whereType<TableInfo<Table, Object?>>();
   @override
-  List<DatabaseSchemaEntity> get allSchemaEntities =>
-      [snLocalChatChannel, snLocalChatMessage, snLocalKeyPair];
+  List<DatabaseSchemaEntity> get allSchemaEntities => [
+        snLocalChatChannel,
+        snLocalChatMessage,
+        snLocalChannelMember,
+        snLocalKeyPair,
+        snLocalAccount,
+        snLocalAttachment,
+        idxChannelAlias,
+        idxChatChannel,
+        idxAccountName,
+        idxAttachmentRid,
+        idxAttachmentAccount
+      ];
 }
 
 typedef $$SnLocalChatChannelTableCreateCompanionBuilder
@@ -1032,6 +2017,7 @@ typedef $$SnLocalChatMessageTableCreateCompanionBuilder
     = SnLocalChatMessageCompanion Function({
   Value<int> id,
   required int channelId,
+  Value<int?> senderId,
   required SnChatMessage content,
   Value<DateTime> createdAt,
 });
@@ -1039,6 +2025,7 @@ typedef $$SnLocalChatMessageTableUpdateCompanionBuilder
     = SnLocalChatMessageCompanion Function({
   Value<int> id,
   Value<int> channelId,
+  Value<int?> senderId,
   Value<SnChatMessage> content,
   Value<DateTime> createdAt,
 });
@@ -1058,6 +2045,9 @@ class $$SnLocalChatMessageTableFilterComposer
   ColumnFilters<int> get channelId => $composableBuilder(
       column: $table.channelId, builder: (column) => ColumnFilters(column));
 
+  ColumnFilters<int> get senderId => $composableBuilder(
+      column: $table.senderId, builder: (column) => ColumnFilters(column));
+
   ColumnWithTypeConverterFilters<SnChatMessage, SnChatMessage, String>
       get content => $composableBuilder(
           column: $table.content,
@@ -1082,6 +2072,9 @@ class $$SnLocalChatMessageTableOrderingComposer
   ColumnOrderings<int> get channelId => $composableBuilder(
       column: $table.channelId, builder: (column) => ColumnOrderings(column));
 
+  ColumnOrderings<int> get senderId => $composableBuilder(
+      column: $table.senderId, builder: (column) => ColumnOrderings(column));
+
   ColumnOrderings<String> get content => $composableBuilder(
       column: $table.content, builder: (column) => ColumnOrderings(column));
 
@@ -1104,6 +2097,9 @@ class $$SnLocalChatMessageTableAnnotationComposer
   GeneratedColumn<int> get channelId =>
       $composableBuilder(column: $table.channelId, builder: (column) => column);
 
+  GeneratedColumn<int> get senderId =>
+      $composableBuilder(column: $table.senderId, builder: (column) => column);
+
   GeneratedColumnWithTypeConverter<SnChatMessage, String> get content =>
       $composableBuilder(column: $table.content, builder: (column) => column);
 
@@ -1142,24 +2138,28 @@ class $$SnLocalChatMessageTableTableManager extends RootTableManager<
           updateCompanionCallback: ({
             Value<int> id = const Value.absent(),
             Value<int> channelId = const Value.absent(),
+            Value<int?> senderId = const Value.absent(),
             Value<SnChatMessage> content = const Value.absent(),
             Value<DateTime> createdAt = const Value.absent(),
           }) =>
               SnLocalChatMessageCompanion(
             id: id,
             channelId: channelId,
+            senderId: senderId,
             content: content,
             createdAt: createdAt,
           ),
           createCompanionCallback: ({
             Value<int> id = const Value.absent(),
             required int channelId,
+            Value<int?> senderId = const Value.absent(),
             required SnChatMessage content,
             Value<DateTime> createdAt = const Value.absent(),
           }) =>
               SnLocalChatMessageCompanion.insert(
             id: id,
             channelId: channelId,
+            senderId: senderId,
             content: content,
             createdAt: createdAt,
           ),
@@ -1186,6 +2186,181 @@ typedef $$SnLocalChatMessageTableProcessedTableManager = ProcessedTableManager<
     ),
     SnLocalChatMessageData,
     PrefetchHooks Function()>;
+typedef $$SnLocalChannelMemberTableCreateCompanionBuilder
+    = SnLocalChannelMemberCompanion Function({
+  Value<int> id,
+  required int channelId,
+  required int accountId,
+  required SnChannelMember content,
+  Value<DateTime> createdAt,
+});
+typedef $$SnLocalChannelMemberTableUpdateCompanionBuilder
+    = SnLocalChannelMemberCompanion Function({
+  Value<int> id,
+  Value<int> channelId,
+  Value<int> accountId,
+  Value<SnChannelMember> content,
+  Value<DateTime> createdAt,
+});
+
+class $$SnLocalChannelMemberTableFilterComposer
+    extends Composer<_$AppDatabase, $SnLocalChannelMemberTable> {
+  $$SnLocalChannelMemberTableFilterComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  ColumnFilters<int> get id => $composableBuilder(
+      column: $table.id, builder: (column) => ColumnFilters(column));
+
+  ColumnFilters<int> get channelId => $composableBuilder(
+      column: $table.channelId, builder: (column) => ColumnFilters(column));
+
+  ColumnFilters<int> get accountId => $composableBuilder(
+      column: $table.accountId, builder: (column) => ColumnFilters(column));
+
+  ColumnWithTypeConverterFilters<SnChannelMember, SnChannelMember, String>
+      get content => $composableBuilder(
+          column: $table.content,
+          builder: (column) => ColumnWithTypeConverterFilters(column));
+
+  ColumnFilters<DateTime> get createdAt => $composableBuilder(
+      column: $table.createdAt, builder: (column) => ColumnFilters(column));
+}
+
+class $$SnLocalChannelMemberTableOrderingComposer
+    extends Composer<_$AppDatabase, $SnLocalChannelMemberTable> {
+  $$SnLocalChannelMemberTableOrderingComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  ColumnOrderings<int> get id => $composableBuilder(
+      column: $table.id, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<int> get channelId => $composableBuilder(
+      column: $table.channelId, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<int> get accountId => $composableBuilder(
+      column: $table.accountId, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<String> get content => $composableBuilder(
+      column: $table.content, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<DateTime> get createdAt => $composableBuilder(
+      column: $table.createdAt, builder: (column) => ColumnOrderings(column));
+}
+
+class $$SnLocalChannelMemberTableAnnotationComposer
+    extends Composer<_$AppDatabase, $SnLocalChannelMemberTable> {
+  $$SnLocalChannelMemberTableAnnotationComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  GeneratedColumn<int> get id =>
+      $composableBuilder(column: $table.id, builder: (column) => column);
+
+  GeneratedColumn<int> get channelId =>
+      $composableBuilder(column: $table.channelId, builder: (column) => column);
+
+  GeneratedColumn<int> get accountId =>
+      $composableBuilder(column: $table.accountId, builder: (column) => column);
+
+  GeneratedColumnWithTypeConverter<SnChannelMember, String> get content =>
+      $composableBuilder(column: $table.content, builder: (column) => column);
+
+  GeneratedColumn<DateTime> get createdAt =>
+      $composableBuilder(column: $table.createdAt, builder: (column) => column);
+}
+
+class $$SnLocalChannelMemberTableTableManager extends RootTableManager<
+    _$AppDatabase,
+    $SnLocalChannelMemberTable,
+    SnLocalChannelMemberData,
+    $$SnLocalChannelMemberTableFilterComposer,
+    $$SnLocalChannelMemberTableOrderingComposer,
+    $$SnLocalChannelMemberTableAnnotationComposer,
+    $$SnLocalChannelMemberTableCreateCompanionBuilder,
+    $$SnLocalChannelMemberTableUpdateCompanionBuilder,
+    (
+      SnLocalChannelMemberData,
+      BaseReferences<_$AppDatabase, $SnLocalChannelMemberTable,
+          SnLocalChannelMemberData>
+    ),
+    SnLocalChannelMemberData,
+    PrefetchHooks Function()> {
+  $$SnLocalChannelMemberTableTableManager(
+      _$AppDatabase db, $SnLocalChannelMemberTable table)
+      : super(TableManagerState(
+          db: db,
+          table: table,
+          createFilteringComposer: () =>
+              $$SnLocalChannelMemberTableFilterComposer($db: db, $table: table),
+          createOrderingComposer: () =>
+              $$SnLocalChannelMemberTableOrderingComposer(
+                  $db: db, $table: table),
+          createComputedFieldComposer: () =>
+              $$SnLocalChannelMemberTableAnnotationComposer(
+                  $db: db, $table: table),
+          updateCompanionCallback: ({
+            Value<int> id = const Value.absent(),
+            Value<int> channelId = const Value.absent(),
+            Value<int> accountId = const Value.absent(),
+            Value<SnChannelMember> content = const Value.absent(),
+            Value<DateTime> createdAt = const Value.absent(),
+          }) =>
+              SnLocalChannelMemberCompanion(
+            id: id,
+            channelId: channelId,
+            accountId: accountId,
+            content: content,
+            createdAt: createdAt,
+          ),
+          createCompanionCallback: ({
+            Value<int> id = const Value.absent(),
+            required int channelId,
+            required int accountId,
+            required SnChannelMember content,
+            Value<DateTime> createdAt = const Value.absent(),
+          }) =>
+              SnLocalChannelMemberCompanion.insert(
+            id: id,
+            channelId: channelId,
+            accountId: accountId,
+            content: content,
+            createdAt: createdAt,
+          ),
+          withReferenceMapper: (p0) => p0
+              .map((e) => (e.readTable(table), BaseReferences(db, table, e)))
+              .toList(),
+          prefetchHooksCallback: null,
+        ));
+}
+
+typedef $$SnLocalChannelMemberTableProcessedTableManager
+    = ProcessedTableManager<
+        _$AppDatabase,
+        $SnLocalChannelMemberTable,
+        SnLocalChannelMemberData,
+        $$SnLocalChannelMemberTableFilterComposer,
+        $$SnLocalChannelMemberTableOrderingComposer,
+        $$SnLocalChannelMemberTableAnnotationComposer,
+        $$SnLocalChannelMemberTableCreateCompanionBuilder,
+        $$SnLocalChannelMemberTableUpdateCompanionBuilder,
+        (
+          SnLocalChannelMemberData,
+          BaseReferences<_$AppDatabase, $SnLocalChannelMemberTable,
+              SnLocalChannelMemberData>
+        ),
+        SnLocalChannelMemberData,
+        PrefetchHooks Function()>;
 typedef $$SnLocalKeyPairTableCreateCompanionBuilder = SnLocalKeyPairCompanion
     Function({
   required String id,
@@ -1360,6 +2535,349 @@ typedef $$SnLocalKeyPairTableProcessedTableManager = ProcessedTableManager<
     ),
     SnLocalKeyPairData,
     PrefetchHooks Function()>;
+typedef $$SnLocalAccountTableCreateCompanionBuilder = SnLocalAccountCompanion
+    Function({
+  Value<int> id,
+  required String name,
+  required SnAccount content,
+  Value<DateTime> createdAt,
+});
+typedef $$SnLocalAccountTableUpdateCompanionBuilder = SnLocalAccountCompanion
+    Function({
+  Value<int> id,
+  Value<String> name,
+  Value<SnAccount> content,
+  Value<DateTime> createdAt,
+});
+
+class $$SnLocalAccountTableFilterComposer
+    extends Composer<_$AppDatabase, $SnLocalAccountTable> {
+  $$SnLocalAccountTableFilterComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  ColumnFilters<int> get id => $composableBuilder(
+      column: $table.id, builder: (column) => ColumnFilters(column));
+
+  ColumnFilters<String> get name => $composableBuilder(
+      column: $table.name, builder: (column) => ColumnFilters(column));
+
+  ColumnWithTypeConverterFilters<SnAccount, SnAccount, String> get content =>
+      $composableBuilder(
+          column: $table.content,
+          builder: (column) => ColumnWithTypeConverterFilters(column));
+
+  ColumnFilters<DateTime> get createdAt => $composableBuilder(
+      column: $table.createdAt, builder: (column) => ColumnFilters(column));
+}
+
+class $$SnLocalAccountTableOrderingComposer
+    extends Composer<_$AppDatabase, $SnLocalAccountTable> {
+  $$SnLocalAccountTableOrderingComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  ColumnOrderings<int> get id => $composableBuilder(
+      column: $table.id, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<String> get name => $composableBuilder(
+      column: $table.name, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<String> get content => $composableBuilder(
+      column: $table.content, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<DateTime> get createdAt => $composableBuilder(
+      column: $table.createdAt, builder: (column) => ColumnOrderings(column));
+}
+
+class $$SnLocalAccountTableAnnotationComposer
+    extends Composer<_$AppDatabase, $SnLocalAccountTable> {
+  $$SnLocalAccountTableAnnotationComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  GeneratedColumn<int> get id =>
+      $composableBuilder(column: $table.id, builder: (column) => column);
+
+  GeneratedColumn<String> get name =>
+      $composableBuilder(column: $table.name, builder: (column) => column);
+
+  GeneratedColumnWithTypeConverter<SnAccount, String> get content =>
+      $composableBuilder(column: $table.content, builder: (column) => column);
+
+  GeneratedColumn<DateTime> get createdAt =>
+      $composableBuilder(column: $table.createdAt, builder: (column) => column);
+}
+
+class $$SnLocalAccountTableTableManager extends RootTableManager<
+    _$AppDatabase,
+    $SnLocalAccountTable,
+    SnLocalAccountData,
+    $$SnLocalAccountTableFilterComposer,
+    $$SnLocalAccountTableOrderingComposer,
+    $$SnLocalAccountTableAnnotationComposer,
+    $$SnLocalAccountTableCreateCompanionBuilder,
+    $$SnLocalAccountTableUpdateCompanionBuilder,
+    (
+      SnLocalAccountData,
+      BaseReferences<_$AppDatabase, $SnLocalAccountTable, SnLocalAccountData>
+    ),
+    SnLocalAccountData,
+    PrefetchHooks Function()> {
+  $$SnLocalAccountTableTableManager(
+      _$AppDatabase db, $SnLocalAccountTable table)
+      : super(TableManagerState(
+          db: db,
+          table: table,
+          createFilteringComposer: () =>
+              $$SnLocalAccountTableFilterComposer($db: db, $table: table),
+          createOrderingComposer: () =>
+              $$SnLocalAccountTableOrderingComposer($db: db, $table: table),
+          createComputedFieldComposer: () =>
+              $$SnLocalAccountTableAnnotationComposer($db: db, $table: table),
+          updateCompanionCallback: ({
+            Value<int> id = const Value.absent(),
+            Value<String> name = const Value.absent(),
+            Value<SnAccount> content = const Value.absent(),
+            Value<DateTime> createdAt = const Value.absent(),
+          }) =>
+              SnLocalAccountCompanion(
+            id: id,
+            name: name,
+            content: content,
+            createdAt: createdAt,
+          ),
+          createCompanionCallback: ({
+            Value<int> id = const Value.absent(),
+            required String name,
+            required SnAccount content,
+            Value<DateTime> createdAt = const Value.absent(),
+          }) =>
+              SnLocalAccountCompanion.insert(
+            id: id,
+            name: name,
+            content: content,
+            createdAt: createdAt,
+          ),
+          withReferenceMapper: (p0) => p0
+              .map((e) => (e.readTable(table), BaseReferences(db, table, e)))
+              .toList(),
+          prefetchHooksCallback: null,
+        ));
+}
+
+typedef $$SnLocalAccountTableProcessedTableManager = ProcessedTableManager<
+    _$AppDatabase,
+    $SnLocalAccountTable,
+    SnLocalAccountData,
+    $$SnLocalAccountTableFilterComposer,
+    $$SnLocalAccountTableOrderingComposer,
+    $$SnLocalAccountTableAnnotationComposer,
+    $$SnLocalAccountTableCreateCompanionBuilder,
+    $$SnLocalAccountTableUpdateCompanionBuilder,
+    (
+      SnLocalAccountData,
+      BaseReferences<_$AppDatabase, $SnLocalAccountTable, SnLocalAccountData>
+    ),
+    SnLocalAccountData,
+    PrefetchHooks Function()>;
+typedef $$SnLocalAttachmentTableCreateCompanionBuilder
+    = SnLocalAttachmentCompanion Function({
+  Value<int> id,
+  required String rid,
+  required String uuid,
+  required SnAttachment content,
+  required int accountId,
+  Value<DateTime> createdAt,
+});
+typedef $$SnLocalAttachmentTableUpdateCompanionBuilder
+    = SnLocalAttachmentCompanion Function({
+  Value<int> id,
+  Value<String> rid,
+  Value<String> uuid,
+  Value<SnAttachment> content,
+  Value<int> accountId,
+  Value<DateTime> createdAt,
+});
+
+class $$SnLocalAttachmentTableFilterComposer
+    extends Composer<_$AppDatabase, $SnLocalAttachmentTable> {
+  $$SnLocalAttachmentTableFilterComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  ColumnFilters<int> get id => $composableBuilder(
+      column: $table.id, builder: (column) => ColumnFilters(column));
+
+  ColumnFilters<String> get rid => $composableBuilder(
+      column: $table.rid, builder: (column) => ColumnFilters(column));
+
+  ColumnFilters<String> get uuid => $composableBuilder(
+      column: $table.uuid, builder: (column) => ColumnFilters(column));
+
+  ColumnWithTypeConverterFilters<SnAttachment, SnAttachment, String>
+      get content => $composableBuilder(
+          column: $table.content,
+          builder: (column) => ColumnWithTypeConverterFilters(column));
+
+  ColumnFilters<int> get accountId => $composableBuilder(
+      column: $table.accountId, builder: (column) => ColumnFilters(column));
+
+  ColumnFilters<DateTime> get createdAt => $composableBuilder(
+      column: $table.createdAt, builder: (column) => ColumnFilters(column));
+}
+
+class $$SnLocalAttachmentTableOrderingComposer
+    extends Composer<_$AppDatabase, $SnLocalAttachmentTable> {
+  $$SnLocalAttachmentTableOrderingComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  ColumnOrderings<int> get id => $composableBuilder(
+      column: $table.id, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<String> get rid => $composableBuilder(
+      column: $table.rid, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<String> get uuid => $composableBuilder(
+      column: $table.uuid, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<String> get content => $composableBuilder(
+      column: $table.content, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<int> get accountId => $composableBuilder(
+      column: $table.accountId, builder: (column) => ColumnOrderings(column));
+
+  ColumnOrderings<DateTime> get createdAt => $composableBuilder(
+      column: $table.createdAt, builder: (column) => ColumnOrderings(column));
+}
+
+class $$SnLocalAttachmentTableAnnotationComposer
+    extends Composer<_$AppDatabase, $SnLocalAttachmentTable> {
+  $$SnLocalAttachmentTableAnnotationComposer({
+    required super.$db,
+    required super.$table,
+    super.joinBuilder,
+    super.$addJoinBuilderToRootComposer,
+    super.$removeJoinBuilderFromRootComposer,
+  });
+  GeneratedColumn<int> get id =>
+      $composableBuilder(column: $table.id, builder: (column) => column);
+
+  GeneratedColumn<String> get rid =>
+      $composableBuilder(column: $table.rid, builder: (column) => column);
+
+  GeneratedColumn<String> get uuid =>
+      $composableBuilder(column: $table.uuid, builder: (column) => column);
+
+  GeneratedColumnWithTypeConverter<SnAttachment, String> get content =>
+      $composableBuilder(column: $table.content, builder: (column) => column);
+
+  GeneratedColumn<int> get accountId =>
+      $composableBuilder(column: $table.accountId, builder: (column) => column);
+
+  GeneratedColumn<DateTime> get createdAt =>
+      $composableBuilder(column: $table.createdAt, builder: (column) => column);
+}
+
+class $$SnLocalAttachmentTableTableManager extends RootTableManager<
+    _$AppDatabase,
+    $SnLocalAttachmentTable,
+    SnLocalAttachmentData,
+    $$SnLocalAttachmentTableFilterComposer,
+    $$SnLocalAttachmentTableOrderingComposer,
+    $$SnLocalAttachmentTableAnnotationComposer,
+    $$SnLocalAttachmentTableCreateCompanionBuilder,
+    $$SnLocalAttachmentTableUpdateCompanionBuilder,
+    (
+      SnLocalAttachmentData,
+      BaseReferences<_$AppDatabase, $SnLocalAttachmentTable,
+          SnLocalAttachmentData>
+    ),
+    SnLocalAttachmentData,
+    PrefetchHooks Function()> {
+  $$SnLocalAttachmentTableTableManager(
+      _$AppDatabase db, $SnLocalAttachmentTable table)
+      : super(TableManagerState(
+          db: db,
+          table: table,
+          createFilteringComposer: () =>
+              $$SnLocalAttachmentTableFilterComposer($db: db, $table: table),
+          createOrderingComposer: () =>
+              $$SnLocalAttachmentTableOrderingComposer($db: db, $table: table),
+          createComputedFieldComposer: () =>
+              $$SnLocalAttachmentTableAnnotationComposer(
+                  $db: db, $table: table),
+          updateCompanionCallback: ({
+            Value<int> id = const Value.absent(),
+            Value<String> rid = const Value.absent(),
+            Value<String> uuid = const Value.absent(),
+            Value<SnAttachment> content = const Value.absent(),
+            Value<int> accountId = const Value.absent(),
+            Value<DateTime> createdAt = const Value.absent(),
+          }) =>
+              SnLocalAttachmentCompanion(
+            id: id,
+            rid: rid,
+            uuid: uuid,
+            content: content,
+            accountId: accountId,
+            createdAt: createdAt,
+          ),
+          createCompanionCallback: ({
+            Value<int> id = const Value.absent(),
+            required String rid,
+            required String uuid,
+            required SnAttachment content,
+            required int accountId,
+            Value<DateTime> createdAt = const Value.absent(),
+          }) =>
+              SnLocalAttachmentCompanion.insert(
+            id: id,
+            rid: rid,
+            uuid: uuid,
+            content: content,
+            accountId: accountId,
+            createdAt: createdAt,
+          ),
+          withReferenceMapper: (p0) => p0
+              .map((e) => (e.readTable(table), BaseReferences(db, table, e)))
+              .toList(),
+          prefetchHooksCallback: null,
+        ));
+}
+
+typedef $$SnLocalAttachmentTableProcessedTableManager = ProcessedTableManager<
+    _$AppDatabase,
+    $SnLocalAttachmentTable,
+    SnLocalAttachmentData,
+    $$SnLocalAttachmentTableFilterComposer,
+    $$SnLocalAttachmentTableOrderingComposer,
+    $$SnLocalAttachmentTableAnnotationComposer,
+    $$SnLocalAttachmentTableCreateCompanionBuilder,
+    $$SnLocalAttachmentTableUpdateCompanionBuilder,
+    (
+      SnLocalAttachmentData,
+      BaseReferences<_$AppDatabase, $SnLocalAttachmentTable,
+          SnLocalAttachmentData>
+    ),
+    SnLocalAttachmentData,
+    PrefetchHooks Function()>;
 
 class $AppDatabaseManager {
   final _$AppDatabase _db;
@@ -1368,6 +2886,12 @@ class $AppDatabaseManager {
       $$SnLocalChatChannelTableTableManager(_db, _db.snLocalChatChannel);
   $$SnLocalChatMessageTableTableManager get snLocalChatMessage =>
       $$SnLocalChatMessageTableTableManager(_db, _db.snLocalChatMessage);
+  $$SnLocalChannelMemberTableTableManager get snLocalChannelMember =>
+      $$SnLocalChannelMemberTableTableManager(_db, _db.snLocalChannelMember);
   $$SnLocalKeyPairTableTableManager get snLocalKeyPair =>
       $$SnLocalKeyPairTableTableManager(_db, _db.snLocalKeyPair);
+  $$SnLocalAccountTableTableManager get snLocalAccount =>
+      $$SnLocalAccountTableTableManager(_db, _db.snLocalAccount);
+  $$SnLocalAttachmentTableTableManager get snLocalAttachment =>
+      $$SnLocalAttachmentTableTableManager(_db, _db.snLocalAttachment);
 }
diff --git a/lib/database/database.steps.dart b/lib/database/database.steps.dart
index a3e8e26..5df1cd0 100644
--- a/lib/database/database.steps.dart
+++ b/lib/database/database.steps.dart
@@ -140,8 +140,207 @@ i1.GeneratedColumn<bool> _column_9(String aliasedName) =>
         defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
             'CHECK ("is_active" IN (0, 1))'),
         defaultValue: const CustomExpression('0'));
+
+final class Schema3 extends i0.VersionedSchema {
+  Schema3({required super.database}) : super(version: 3);
+  @override
+  late final List<i1.DatabaseSchemaEntity> entities = [
+    snLocalChatChannel,
+    snLocalChatMessage,
+    snLocalChannelMember,
+    snLocalKeyPair,
+    snLocalAccount,
+    snLocalAttachment,
+    idxChannelAlias,
+    idxChatChannel,
+    idxAccountName,
+    idxAttachmentRid,
+    idxAttachmentAccount,
+  ];
+  late final Shape0 snLocalChatChannel = Shape0(
+      source: i0.VersionedTable(
+        entityName: 'sn_local_chat_channel',
+        withoutRowId: false,
+        isStrict: false,
+        tableConstraints: [],
+        columns: [
+          _column_0,
+          _column_1,
+          _column_2,
+          _column_3,
+        ],
+        attachedDatabase: database,
+      ),
+      alias: null);
+  late final Shape3 snLocalChatMessage = Shape3(
+      source: i0.VersionedTable(
+        entityName: 'sn_local_chat_message',
+        withoutRowId: false,
+        isStrict: false,
+        tableConstraints: [],
+        columns: [
+          _column_0,
+          _column_4,
+          _column_10,
+          _column_2,
+          _column_3,
+        ],
+        attachedDatabase: database,
+      ),
+      alias: null);
+  late final Shape4 snLocalChannelMember = Shape4(
+      source: i0.VersionedTable(
+        entityName: 'sn_local_channel_member',
+        withoutRowId: false,
+        isStrict: false,
+        tableConstraints: [],
+        columns: [
+          _column_0,
+          _column_4,
+          _column_6,
+          _column_2,
+          _column_3,
+        ],
+        attachedDatabase: database,
+      ),
+      alias: null);
+  late final Shape2 snLocalKeyPair = Shape2(
+      source: i0.VersionedTable(
+        entityName: 'sn_local_key_pair',
+        withoutRowId: false,
+        isStrict: false,
+        tableConstraints: [
+          'PRIMARY KEY(id)',
+        ],
+        columns: [
+          _column_5,
+          _column_6,
+          _column_7,
+          _column_8,
+          _column_9,
+        ],
+        attachedDatabase: database,
+      ),
+      alias: null);
+  late final Shape5 snLocalAccount = Shape5(
+      source: i0.VersionedTable(
+        entityName: 'sn_local_account',
+        withoutRowId: false,
+        isStrict: false,
+        tableConstraints: [],
+        columns: [
+          _column_0,
+          _column_11,
+          _column_2,
+          _column_3,
+        ],
+        attachedDatabase: database,
+      ),
+      alias: null);
+  late final Shape6 snLocalAttachment = Shape6(
+      source: i0.VersionedTable(
+        entityName: 'sn_local_attachment',
+        withoutRowId: false,
+        isStrict: false,
+        tableConstraints: [],
+        columns: [
+          _column_0,
+          _column_12,
+          _column_13,
+          _column_2,
+          _column_6,
+          _column_3,
+        ],
+        attachedDatabase: database,
+      ),
+      alias: null);
+  final i1.Index idxChannelAlias = i1.Index('idx_channel_alias',
+      'CREATE INDEX idx_channel_alias ON sn_local_chat_channel (alias)');
+  final i1.Index idxChatChannel = i1.Index('idx_chat_channel',
+      'CREATE INDEX idx_chat_channel ON sn_local_chat_message (channel_id)');
+  final i1.Index idxAccountName = i1.Index('idx_account_name',
+      'CREATE INDEX idx_account_name ON sn_local_account (name)');
+  final i1.Index idxAttachmentRid = i1.Index('idx_attachment_rid',
+      'CREATE INDEX idx_attachment_rid ON sn_local_attachment (rid)');
+  final i1.Index idxAttachmentAccount = i1.Index('idx_attachment_account',
+      'CREATE INDEX idx_attachment_account ON sn_local_attachment (account_id)');
+}
+
+class Shape3 extends i0.VersionedTable {
+  Shape3({required super.source, required super.alias}) : super.aliased();
+  i1.GeneratedColumn<int> get id =>
+      columnsByName['id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<int> get channelId =>
+      columnsByName['channel_id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<int> get senderId =>
+      columnsByName['sender_id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<String> get content =>
+      columnsByName['content']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<DateTime> get createdAt =>
+      columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
+}
+
+i1.GeneratedColumn<int> _column_10(String aliasedName) =>
+    i1.GeneratedColumn<int>('sender_id', aliasedName, true,
+        type: i1.DriftSqlType.int);
+
+class Shape4 extends i0.VersionedTable {
+  Shape4({required super.source, required super.alias}) : super.aliased();
+  i1.GeneratedColumn<int> get id =>
+      columnsByName['id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<int> get channelId =>
+      columnsByName['channel_id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<int> get accountId =>
+      columnsByName['account_id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<String> get content =>
+      columnsByName['content']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<DateTime> get createdAt =>
+      columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
+}
+
+class Shape5 extends i0.VersionedTable {
+  Shape5({required super.source, required super.alias}) : super.aliased();
+  i1.GeneratedColumn<int> get id =>
+      columnsByName['id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<String> get name =>
+      columnsByName['name']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<String> get content =>
+      columnsByName['content']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<DateTime> get createdAt =>
+      columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
+}
+
+i1.GeneratedColumn<String> _column_11(String aliasedName) =>
+    i1.GeneratedColumn<String>('name', aliasedName, false,
+        type: i1.DriftSqlType.string);
+
+class Shape6 extends i0.VersionedTable {
+  Shape6({required super.source, required super.alias}) : super.aliased();
+  i1.GeneratedColumn<int> get id =>
+      columnsByName['id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<String> get rid =>
+      columnsByName['rid']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<String> get uuid =>
+      columnsByName['uuid']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<String> get content =>
+      columnsByName['content']! as i1.GeneratedColumn<String>;
+  i1.GeneratedColumn<int> get accountId =>
+      columnsByName['account_id']! as i1.GeneratedColumn<int>;
+  i1.GeneratedColumn<DateTime> get createdAt =>
+      columnsByName['created_at']! as i1.GeneratedColumn<DateTime>;
+}
+
+i1.GeneratedColumn<String> _column_12(String aliasedName) =>
+    i1.GeneratedColumn<String>('rid', aliasedName, false,
+        type: i1.DriftSqlType.string,
+        defaultConstraints: i1.GeneratedColumn.constraintIsAlways('UNIQUE'));
+i1.GeneratedColumn<String> _column_13(String aliasedName) =>
+    i1.GeneratedColumn<String>('uuid', aliasedName, false,
+        type: i1.DriftSqlType.string,
+        defaultConstraints: i1.GeneratedColumn.constraintIsAlways('UNIQUE'));
 i0.MigrationStepWithVersion migrationSteps({
   required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
+  required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
 }) {
   return (currentVersion, database) async {
     switch (currentVersion) {
@@ -150,6 +349,11 @@ i0.MigrationStepWithVersion migrationSteps({
         final migrator = i1.Migrator(database, schema);
         await from1To2(migrator, schema);
         return 2;
+      case 2:
+        final schema = Schema3(database: database);
+        final migrator = i1.Migrator(database, schema);
+        await from2To3(migrator, schema);
+        return 3;
       default:
         throw ArgumentError.value('Unknown migration from $currentVersion');
     }
@@ -158,8 +362,10 @@ i0.MigrationStepWithVersion migrationSteps({
 
 i1.OnUpgrade stepByStep({
   required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
+  required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
 }) =>
     i0.VersionedSchema.stepByStepHelper(
         step: migrationSteps(
       from1To2: from1To2,
+      from2To3: from2To3,
     ));
diff --git a/test/drift/my_database/generated/schema.dart b/test/drift/my_database/generated/schema.dart
index b2b7404..209e70d 100644
--- a/test/drift/my_database/generated/schema.dart
+++ b/test/drift/my_database/generated/schema.dart
@@ -5,6 +5,7 @@ import 'package:drift/drift.dart';
 import 'package:drift/internal/migrations.dart';
 import 'schema_v1.dart' as v1;
 import 'schema_v2.dart' as v2;
+import 'schema_v3.dart' as v3;
 
 class GeneratedHelper implements SchemaInstantiationHelper {
   @override
@@ -14,10 +15,12 @@ class GeneratedHelper implements SchemaInstantiationHelper {
         return v1.DatabaseAtV1(db);
       case 2:
         return v2.DatabaseAtV2(db);
+      case 3:
+        return v3.DatabaseAtV3(db);
       default:
         throw MissingSchemaException(version, versions);
     }
   }
 
-  static const versions = const [1, 2];
+  static const versions = const [1, 2, 3];
 }
diff --git a/test/drift/my_database/generated/schema_v3.dart b/test/drift/my_database/generated/schema_v3.dart
new file mode 100644
index 0000000..b6acb6b
--- /dev/null
+++ b/test/drift/my_database/generated/schema_v3.dart
@@ -0,0 +1,1553 @@
+// dart format width=80
+// GENERATED CODE, DO NOT EDIT BY HAND.
+// ignore_for_file: type=lint
+import 'package:drift/drift.dart';
+
+class SnLocalChatChannel extends Table
+    with TableInfo<SnLocalChatChannel, SnLocalChatChannelData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  SnLocalChatChannel(this.attachedDatabase, [this._alias]);
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  late final GeneratedColumn<String> alias = GeneratedColumn<String>(
+      'alias', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<String> content = GeneratedColumn<String>(
+      'content', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: const CustomExpression(
+          'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)'));
+  @override
+  List<GeneratedColumn> get $columns => [id, alias, content, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_chat_channel';
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalChatChannelData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalChatChannelData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      alias: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}alias'])!,
+      content: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}content'])!,
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  SnLocalChatChannel createAlias(String alias) {
+    return SnLocalChatChannel(attachedDatabase, alias);
+  }
+}
+
+class SnLocalChatChannelData extends DataClass
+    implements Insertable<SnLocalChatChannelData> {
+  final int id;
+  final String alias;
+  final String content;
+  final DateTime createdAt;
+  const SnLocalChatChannelData(
+      {required this.id,
+      required this.alias,
+      required this.content,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['alias'] = Variable<String>(alias);
+    map['content'] = Variable<String>(content);
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalChatChannelCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalChatChannelCompanion(
+      id: Value(id),
+      alias: Value(alias),
+      content: Value(content),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalChatChannelData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalChatChannelData(
+      id: serializer.fromJson<int>(json['id']),
+      alias: serializer.fromJson<String>(json['alias']),
+      content: serializer.fromJson<String>(json['content']),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'alias': serializer.toJson<String>(alias),
+      'content': serializer.toJson<String>(content),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalChatChannelData copyWith(
+          {int? id, String? alias, String? content, DateTime? createdAt}) =>
+      SnLocalChatChannelData(
+        id: id ?? this.id,
+        alias: alias ?? this.alias,
+        content: content ?? this.content,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalChatChannelData copyWithCompanion(SnLocalChatChannelCompanion data) {
+    return SnLocalChatChannelData(
+      id: data.id.present ? data.id.value : this.id,
+      alias: data.alias.present ? data.alias.value : this.alias,
+      content: data.content.present ? data.content.value : this.content,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChatChannelData(')
+          ..write('id: $id, ')
+          ..write('alias: $alias, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, alias, content, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalChatChannelData &&
+          other.id == this.id &&
+          other.alias == this.alias &&
+          other.content == this.content &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalChatChannelCompanion
+    extends UpdateCompanion<SnLocalChatChannelData> {
+  final Value<int> id;
+  final Value<String> alias;
+  final Value<String> content;
+  final Value<DateTime> createdAt;
+  const SnLocalChatChannelCompanion({
+    this.id = const Value.absent(),
+    this.alias = const Value.absent(),
+    this.content = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalChatChannelCompanion.insert({
+    this.id = const Value.absent(),
+    required String alias,
+    required String content,
+    this.createdAt = const Value.absent(),
+  })  : alias = Value(alias),
+        content = Value(content);
+  static Insertable<SnLocalChatChannelData> custom({
+    Expression<int>? id,
+    Expression<String>? alias,
+    Expression<String>? content,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (alias != null) 'alias': alias,
+      if (content != null) 'content': content,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalChatChannelCompanion copyWith(
+      {Value<int>? id,
+      Value<String>? alias,
+      Value<String>? content,
+      Value<DateTime>? createdAt}) {
+    return SnLocalChatChannelCompanion(
+      id: id ?? this.id,
+      alias: alias ?? this.alias,
+      content: content ?? this.content,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (alias.present) {
+      map['alias'] = Variable<String>(alias.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(content.value);
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChatChannelCompanion(')
+          ..write('id: $id, ')
+          ..write('alias: $alias, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class SnLocalChatMessage extends Table
+    with TableInfo<SnLocalChatMessage, SnLocalChatMessageData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  SnLocalChatMessage(this.attachedDatabase, [this._alias]);
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  late final GeneratedColumn<int> channelId = GeneratedColumn<int>(
+      'channel_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  late final GeneratedColumn<int> senderId = GeneratedColumn<int>(
+      'sender_id', aliasedName, true,
+      type: DriftSqlType.int, requiredDuringInsert: false);
+  late final GeneratedColumn<String> content = GeneratedColumn<String>(
+      'content', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: const CustomExpression(
+          'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)'));
+  @override
+  List<GeneratedColumn> get $columns =>
+      [id, channelId, senderId, content, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_chat_message';
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalChatMessageData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalChatMessageData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      channelId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}channel_id'])!,
+      senderId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}sender_id']),
+      content: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}content'])!,
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  SnLocalChatMessage createAlias(String alias) {
+    return SnLocalChatMessage(attachedDatabase, alias);
+  }
+}
+
+class SnLocalChatMessageData extends DataClass
+    implements Insertable<SnLocalChatMessageData> {
+  final int id;
+  final int channelId;
+  final int? senderId;
+  final String content;
+  final DateTime createdAt;
+  const SnLocalChatMessageData(
+      {required this.id,
+      required this.channelId,
+      this.senderId,
+      required this.content,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['channel_id'] = Variable<int>(channelId);
+    if (!nullToAbsent || senderId != null) {
+      map['sender_id'] = Variable<int>(senderId);
+    }
+    map['content'] = Variable<String>(content);
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalChatMessageCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalChatMessageCompanion(
+      id: Value(id),
+      channelId: Value(channelId),
+      senderId: senderId == null && nullToAbsent
+          ? const Value.absent()
+          : Value(senderId),
+      content: Value(content),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalChatMessageData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalChatMessageData(
+      id: serializer.fromJson<int>(json['id']),
+      channelId: serializer.fromJson<int>(json['channelId']),
+      senderId: serializer.fromJson<int?>(json['senderId']),
+      content: serializer.fromJson<String>(json['content']),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'channelId': serializer.toJson<int>(channelId),
+      'senderId': serializer.toJson<int?>(senderId),
+      'content': serializer.toJson<String>(content),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalChatMessageData copyWith(
+          {int? id,
+          int? channelId,
+          Value<int?> senderId = const Value.absent(),
+          String? content,
+          DateTime? createdAt}) =>
+      SnLocalChatMessageData(
+        id: id ?? this.id,
+        channelId: channelId ?? this.channelId,
+        senderId: senderId.present ? senderId.value : this.senderId,
+        content: content ?? this.content,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalChatMessageData copyWithCompanion(SnLocalChatMessageCompanion data) {
+    return SnLocalChatMessageData(
+      id: data.id.present ? data.id.value : this.id,
+      channelId: data.channelId.present ? data.channelId.value : this.channelId,
+      senderId: data.senderId.present ? data.senderId.value : this.senderId,
+      content: data.content.present ? data.content.value : this.content,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChatMessageData(')
+          ..write('id: $id, ')
+          ..write('channelId: $channelId, ')
+          ..write('senderId: $senderId, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, channelId, senderId, content, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalChatMessageData &&
+          other.id == this.id &&
+          other.channelId == this.channelId &&
+          other.senderId == this.senderId &&
+          other.content == this.content &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalChatMessageCompanion
+    extends UpdateCompanion<SnLocalChatMessageData> {
+  final Value<int> id;
+  final Value<int> channelId;
+  final Value<int?> senderId;
+  final Value<String> content;
+  final Value<DateTime> createdAt;
+  const SnLocalChatMessageCompanion({
+    this.id = const Value.absent(),
+    this.channelId = const Value.absent(),
+    this.senderId = const Value.absent(),
+    this.content = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalChatMessageCompanion.insert({
+    this.id = const Value.absent(),
+    required int channelId,
+    this.senderId = const Value.absent(),
+    required String content,
+    this.createdAt = const Value.absent(),
+  })  : channelId = Value(channelId),
+        content = Value(content);
+  static Insertable<SnLocalChatMessageData> custom({
+    Expression<int>? id,
+    Expression<int>? channelId,
+    Expression<int>? senderId,
+    Expression<String>? content,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (channelId != null) 'channel_id': channelId,
+      if (senderId != null) 'sender_id': senderId,
+      if (content != null) 'content': content,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalChatMessageCompanion copyWith(
+      {Value<int>? id,
+      Value<int>? channelId,
+      Value<int?>? senderId,
+      Value<String>? content,
+      Value<DateTime>? createdAt}) {
+    return SnLocalChatMessageCompanion(
+      id: id ?? this.id,
+      channelId: channelId ?? this.channelId,
+      senderId: senderId ?? this.senderId,
+      content: content ?? this.content,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (channelId.present) {
+      map['channel_id'] = Variable<int>(channelId.value);
+    }
+    if (senderId.present) {
+      map['sender_id'] = Variable<int>(senderId.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(content.value);
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChatMessageCompanion(')
+          ..write('id: $id, ')
+          ..write('channelId: $channelId, ')
+          ..write('senderId: $senderId, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class SnLocalChannelMember extends Table
+    with TableInfo<SnLocalChannelMember, SnLocalChannelMemberData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  SnLocalChannelMember(this.attachedDatabase, [this._alias]);
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  late final GeneratedColumn<int> channelId = GeneratedColumn<int>(
+      'channel_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
+      'account_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  late final GeneratedColumn<String> content = GeneratedColumn<String>(
+      'content', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: const CustomExpression(
+          'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)'));
+  @override
+  List<GeneratedColumn> get $columns =>
+      [id, channelId, accountId, content, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_channel_member';
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalChannelMemberData map(Map<String, dynamic> data,
+      {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalChannelMemberData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      channelId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}channel_id'])!,
+      accountId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}account_id'])!,
+      content: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}content'])!,
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  SnLocalChannelMember createAlias(String alias) {
+    return SnLocalChannelMember(attachedDatabase, alias);
+  }
+}
+
+class SnLocalChannelMemberData extends DataClass
+    implements Insertable<SnLocalChannelMemberData> {
+  final int id;
+  final int channelId;
+  final int accountId;
+  final String content;
+  final DateTime createdAt;
+  const SnLocalChannelMemberData(
+      {required this.id,
+      required this.channelId,
+      required this.accountId,
+      required this.content,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['channel_id'] = Variable<int>(channelId);
+    map['account_id'] = Variable<int>(accountId);
+    map['content'] = Variable<String>(content);
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalChannelMemberCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalChannelMemberCompanion(
+      id: Value(id),
+      channelId: Value(channelId),
+      accountId: Value(accountId),
+      content: Value(content),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalChannelMemberData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalChannelMemberData(
+      id: serializer.fromJson<int>(json['id']),
+      channelId: serializer.fromJson<int>(json['channelId']),
+      accountId: serializer.fromJson<int>(json['accountId']),
+      content: serializer.fromJson<String>(json['content']),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'channelId': serializer.toJson<int>(channelId),
+      'accountId': serializer.toJson<int>(accountId),
+      'content': serializer.toJson<String>(content),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalChannelMemberData copyWith(
+          {int? id,
+          int? channelId,
+          int? accountId,
+          String? content,
+          DateTime? createdAt}) =>
+      SnLocalChannelMemberData(
+        id: id ?? this.id,
+        channelId: channelId ?? this.channelId,
+        accountId: accountId ?? this.accountId,
+        content: content ?? this.content,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalChannelMemberData copyWithCompanion(
+      SnLocalChannelMemberCompanion data) {
+    return SnLocalChannelMemberData(
+      id: data.id.present ? data.id.value : this.id,
+      channelId: data.channelId.present ? data.channelId.value : this.channelId,
+      accountId: data.accountId.present ? data.accountId.value : this.accountId,
+      content: data.content.present ? data.content.value : this.content,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChannelMemberData(')
+          ..write('id: $id, ')
+          ..write('channelId: $channelId, ')
+          ..write('accountId: $accountId, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, channelId, accountId, content, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalChannelMemberData &&
+          other.id == this.id &&
+          other.channelId == this.channelId &&
+          other.accountId == this.accountId &&
+          other.content == this.content &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalChannelMemberCompanion
+    extends UpdateCompanion<SnLocalChannelMemberData> {
+  final Value<int> id;
+  final Value<int> channelId;
+  final Value<int> accountId;
+  final Value<String> content;
+  final Value<DateTime> createdAt;
+  const SnLocalChannelMemberCompanion({
+    this.id = const Value.absent(),
+    this.channelId = const Value.absent(),
+    this.accountId = const Value.absent(),
+    this.content = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalChannelMemberCompanion.insert({
+    this.id = const Value.absent(),
+    required int channelId,
+    required int accountId,
+    required String content,
+    this.createdAt = const Value.absent(),
+  })  : channelId = Value(channelId),
+        accountId = Value(accountId),
+        content = Value(content);
+  static Insertable<SnLocalChannelMemberData> custom({
+    Expression<int>? id,
+    Expression<int>? channelId,
+    Expression<int>? accountId,
+    Expression<String>? content,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (channelId != null) 'channel_id': channelId,
+      if (accountId != null) 'account_id': accountId,
+      if (content != null) 'content': content,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalChannelMemberCompanion copyWith(
+      {Value<int>? id,
+      Value<int>? channelId,
+      Value<int>? accountId,
+      Value<String>? content,
+      Value<DateTime>? createdAt}) {
+    return SnLocalChannelMemberCompanion(
+      id: id ?? this.id,
+      channelId: channelId ?? this.channelId,
+      accountId: accountId ?? this.accountId,
+      content: content ?? this.content,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (channelId.present) {
+      map['channel_id'] = Variable<int>(channelId.value);
+    }
+    if (accountId.present) {
+      map['account_id'] = Variable<int>(accountId.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(content.value);
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalChannelMemberCompanion(')
+          ..write('id: $id, ')
+          ..write('channelId: $channelId, ')
+          ..write('accountId: $accountId, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class SnLocalKeyPair extends Table
+    with TableInfo<SnLocalKeyPair, SnLocalKeyPairData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  SnLocalKeyPair(this.attachedDatabase, [this._alias]);
+  late final GeneratedColumn<String> id = GeneratedColumn<String>(
+      'id', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
+      'account_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  late final GeneratedColumn<String> publicKey = GeneratedColumn<String>(
+      'public_key', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<String> privateKey = GeneratedColumn<String>(
+      'private_key', aliasedName, true,
+      type: DriftSqlType.string, requiredDuringInsert: false);
+  late final GeneratedColumn<bool> isActive = GeneratedColumn<bool>(
+      'is_active', aliasedName, false,
+      type: DriftSqlType.bool,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('CHECK ("is_active" IN (0, 1))'),
+      defaultValue: const CustomExpression('0'));
+  @override
+  List<GeneratedColumn> get $columns =>
+      [id, accountId, publicKey, privateKey, isActive];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_key_pair';
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalKeyPairData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalKeyPairData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}id'])!,
+      accountId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}account_id'])!,
+      publicKey: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}public_key'])!,
+      privateKey: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}private_key']),
+      isActive: attachedDatabase.typeMapping
+          .read(DriftSqlType.bool, data['${effectivePrefix}is_active'])!,
+    );
+  }
+
+  @override
+  SnLocalKeyPair createAlias(String alias) {
+    return SnLocalKeyPair(attachedDatabase, alias);
+  }
+}
+
+class SnLocalKeyPairData extends DataClass
+    implements Insertable<SnLocalKeyPairData> {
+  final String id;
+  final int accountId;
+  final String publicKey;
+  final String? privateKey;
+  final bool isActive;
+  const SnLocalKeyPairData(
+      {required this.id,
+      required this.accountId,
+      required this.publicKey,
+      this.privateKey,
+      required this.isActive});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<String>(id);
+    map['account_id'] = Variable<int>(accountId);
+    map['public_key'] = Variable<String>(publicKey);
+    if (!nullToAbsent || privateKey != null) {
+      map['private_key'] = Variable<String>(privateKey);
+    }
+    map['is_active'] = Variable<bool>(isActive);
+    return map;
+  }
+
+  SnLocalKeyPairCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalKeyPairCompanion(
+      id: Value(id),
+      accountId: Value(accountId),
+      publicKey: Value(publicKey),
+      privateKey: privateKey == null && nullToAbsent
+          ? const Value.absent()
+          : Value(privateKey),
+      isActive: Value(isActive),
+    );
+  }
+
+  factory SnLocalKeyPairData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalKeyPairData(
+      id: serializer.fromJson<String>(json['id']),
+      accountId: serializer.fromJson<int>(json['accountId']),
+      publicKey: serializer.fromJson<String>(json['publicKey']),
+      privateKey: serializer.fromJson<String?>(json['privateKey']),
+      isActive: serializer.fromJson<bool>(json['isActive']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<String>(id),
+      'accountId': serializer.toJson<int>(accountId),
+      'publicKey': serializer.toJson<String>(publicKey),
+      'privateKey': serializer.toJson<String?>(privateKey),
+      'isActive': serializer.toJson<bool>(isActive),
+    };
+  }
+
+  SnLocalKeyPairData copyWith(
+          {String? id,
+          int? accountId,
+          String? publicKey,
+          Value<String?> privateKey = const Value.absent(),
+          bool? isActive}) =>
+      SnLocalKeyPairData(
+        id: id ?? this.id,
+        accountId: accountId ?? this.accountId,
+        publicKey: publicKey ?? this.publicKey,
+        privateKey: privateKey.present ? privateKey.value : this.privateKey,
+        isActive: isActive ?? this.isActive,
+      );
+  SnLocalKeyPairData copyWithCompanion(SnLocalKeyPairCompanion data) {
+    return SnLocalKeyPairData(
+      id: data.id.present ? data.id.value : this.id,
+      accountId: data.accountId.present ? data.accountId.value : this.accountId,
+      publicKey: data.publicKey.present ? data.publicKey.value : this.publicKey,
+      privateKey:
+          data.privateKey.present ? data.privateKey.value : this.privateKey,
+      isActive: data.isActive.present ? data.isActive.value : this.isActive,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalKeyPairData(')
+          ..write('id: $id, ')
+          ..write('accountId: $accountId, ')
+          ..write('publicKey: $publicKey, ')
+          ..write('privateKey: $privateKey, ')
+          ..write('isActive: $isActive')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode =>
+      Object.hash(id, accountId, publicKey, privateKey, isActive);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalKeyPairData &&
+          other.id == this.id &&
+          other.accountId == this.accountId &&
+          other.publicKey == this.publicKey &&
+          other.privateKey == this.privateKey &&
+          other.isActive == this.isActive);
+}
+
+class SnLocalKeyPairCompanion extends UpdateCompanion<SnLocalKeyPairData> {
+  final Value<String> id;
+  final Value<int> accountId;
+  final Value<String> publicKey;
+  final Value<String?> privateKey;
+  final Value<bool> isActive;
+  final Value<int> rowid;
+  const SnLocalKeyPairCompanion({
+    this.id = const Value.absent(),
+    this.accountId = const Value.absent(),
+    this.publicKey = const Value.absent(),
+    this.privateKey = const Value.absent(),
+    this.isActive = const Value.absent(),
+    this.rowid = const Value.absent(),
+  });
+  SnLocalKeyPairCompanion.insert({
+    required String id,
+    required int accountId,
+    required String publicKey,
+    this.privateKey = const Value.absent(),
+    this.isActive = const Value.absent(),
+    this.rowid = const Value.absent(),
+  })  : id = Value(id),
+        accountId = Value(accountId),
+        publicKey = Value(publicKey);
+  static Insertable<SnLocalKeyPairData> custom({
+    Expression<String>? id,
+    Expression<int>? accountId,
+    Expression<String>? publicKey,
+    Expression<String>? privateKey,
+    Expression<bool>? isActive,
+    Expression<int>? rowid,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (accountId != null) 'account_id': accountId,
+      if (publicKey != null) 'public_key': publicKey,
+      if (privateKey != null) 'private_key': privateKey,
+      if (isActive != null) 'is_active': isActive,
+      if (rowid != null) 'rowid': rowid,
+    });
+  }
+
+  SnLocalKeyPairCompanion copyWith(
+      {Value<String>? id,
+      Value<int>? accountId,
+      Value<String>? publicKey,
+      Value<String?>? privateKey,
+      Value<bool>? isActive,
+      Value<int>? rowid}) {
+    return SnLocalKeyPairCompanion(
+      id: id ?? this.id,
+      accountId: accountId ?? this.accountId,
+      publicKey: publicKey ?? this.publicKey,
+      privateKey: privateKey ?? this.privateKey,
+      isActive: isActive ?? this.isActive,
+      rowid: rowid ?? this.rowid,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<String>(id.value);
+    }
+    if (accountId.present) {
+      map['account_id'] = Variable<int>(accountId.value);
+    }
+    if (publicKey.present) {
+      map['public_key'] = Variable<String>(publicKey.value);
+    }
+    if (privateKey.present) {
+      map['private_key'] = Variable<String>(privateKey.value);
+    }
+    if (isActive.present) {
+      map['is_active'] = Variable<bool>(isActive.value);
+    }
+    if (rowid.present) {
+      map['rowid'] = Variable<int>(rowid.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalKeyPairCompanion(')
+          ..write('id: $id, ')
+          ..write('accountId: $accountId, ')
+          ..write('publicKey: $publicKey, ')
+          ..write('privateKey: $privateKey, ')
+          ..write('isActive: $isActive, ')
+          ..write('rowid: $rowid')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class SnLocalAccount extends Table
+    with TableInfo<SnLocalAccount, SnLocalAccountData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  SnLocalAccount(this.attachedDatabase, [this._alias]);
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  late final GeneratedColumn<String> name = GeneratedColumn<String>(
+      'name', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<String> content = GeneratedColumn<String>(
+      'content', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: const CustomExpression(
+          'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)'));
+  @override
+  List<GeneratedColumn> get $columns => [id, name, content, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_account';
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalAccountData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalAccountData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      name: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}name'])!,
+      content: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}content'])!,
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  SnLocalAccount createAlias(String alias) {
+    return SnLocalAccount(attachedDatabase, alias);
+  }
+}
+
+class SnLocalAccountData extends DataClass
+    implements Insertable<SnLocalAccountData> {
+  final int id;
+  final String name;
+  final String content;
+  final DateTime createdAt;
+  const SnLocalAccountData(
+      {required this.id,
+      required this.name,
+      required this.content,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['name'] = Variable<String>(name);
+    map['content'] = Variable<String>(content);
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalAccountCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalAccountCompanion(
+      id: Value(id),
+      name: Value(name),
+      content: Value(content),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalAccountData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalAccountData(
+      id: serializer.fromJson<int>(json['id']),
+      name: serializer.fromJson<String>(json['name']),
+      content: serializer.fromJson<String>(json['content']),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'name': serializer.toJson<String>(name),
+      'content': serializer.toJson<String>(content),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalAccountData copyWith(
+          {int? id, String? name, String? content, DateTime? createdAt}) =>
+      SnLocalAccountData(
+        id: id ?? this.id,
+        name: name ?? this.name,
+        content: content ?? this.content,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalAccountData copyWithCompanion(SnLocalAccountCompanion data) {
+    return SnLocalAccountData(
+      id: data.id.present ? data.id.value : this.id,
+      name: data.name.present ? data.name.value : this.name,
+      content: data.content.present ? data.content.value : this.content,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAccountData(')
+          ..write('id: $id, ')
+          ..write('name: $name, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, name, content, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalAccountData &&
+          other.id == this.id &&
+          other.name == this.name &&
+          other.content == this.content &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalAccountCompanion extends UpdateCompanion<SnLocalAccountData> {
+  final Value<int> id;
+  final Value<String> name;
+  final Value<String> content;
+  final Value<DateTime> createdAt;
+  const SnLocalAccountCompanion({
+    this.id = const Value.absent(),
+    this.name = const Value.absent(),
+    this.content = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalAccountCompanion.insert({
+    this.id = const Value.absent(),
+    required String name,
+    required String content,
+    this.createdAt = const Value.absent(),
+  })  : name = Value(name),
+        content = Value(content);
+  static Insertable<SnLocalAccountData> custom({
+    Expression<int>? id,
+    Expression<String>? name,
+    Expression<String>? content,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (name != null) 'name': name,
+      if (content != null) 'content': content,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalAccountCompanion copyWith(
+      {Value<int>? id,
+      Value<String>? name,
+      Value<String>? content,
+      Value<DateTime>? createdAt}) {
+    return SnLocalAccountCompanion(
+      id: id ?? this.id,
+      name: name ?? this.name,
+      content: content ?? this.content,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (name.present) {
+      map['name'] = Variable<String>(name.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(content.value);
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAccountCompanion(')
+          ..write('id: $id, ')
+          ..write('name: $name, ')
+          ..write('content: $content, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class SnLocalAttachment extends Table
+    with TableInfo<SnLocalAttachment, SnLocalAttachmentData> {
+  @override
+  final GeneratedDatabase attachedDatabase;
+  final String? _alias;
+  SnLocalAttachment(this.attachedDatabase, [this._alias]);
+  late final GeneratedColumn<int> id = GeneratedColumn<int>(
+      'id', aliasedName, false,
+      hasAutoIncrement: true,
+      type: DriftSqlType.int,
+      requiredDuringInsert: false,
+      defaultConstraints:
+          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
+  late final GeneratedColumn<String> rid = GeneratedColumn<String>(
+      'rid', aliasedName, false,
+      type: DriftSqlType.string,
+      requiredDuringInsert: true,
+      defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'));
+  late final GeneratedColumn<String> uuid = GeneratedColumn<String>(
+      'uuid', aliasedName, false,
+      type: DriftSqlType.string,
+      requiredDuringInsert: true,
+      defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'));
+  late final GeneratedColumn<String> content = GeneratedColumn<String>(
+      'content', aliasedName, false,
+      type: DriftSqlType.string, requiredDuringInsert: true);
+  late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
+      'account_id', aliasedName, false,
+      type: DriftSqlType.int, requiredDuringInsert: true);
+  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
+      'created_at', aliasedName, false,
+      type: DriftSqlType.dateTime,
+      requiredDuringInsert: false,
+      defaultValue: const CustomExpression(
+          'CAST(strftime(\'%s\', CURRENT_TIMESTAMP) AS INTEGER)'));
+  @override
+  List<GeneratedColumn> get $columns =>
+      [id, rid, uuid, content, accountId, createdAt];
+  @override
+  String get aliasedName => _alias ?? actualTableName;
+  @override
+  String get actualTableName => $name;
+  static const String $name = 'sn_local_attachment';
+  @override
+  Set<GeneratedColumn> get $primaryKey => {id};
+  @override
+  SnLocalAttachmentData map(Map<String, dynamic> data, {String? tablePrefix}) {
+    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
+    return SnLocalAttachmentData(
+      id: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
+      rid: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}rid'])!,
+      uuid: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}uuid'])!,
+      content: attachedDatabase.typeMapping
+          .read(DriftSqlType.string, data['${effectivePrefix}content'])!,
+      accountId: attachedDatabase.typeMapping
+          .read(DriftSqlType.int, data['${effectivePrefix}account_id'])!,
+      createdAt: attachedDatabase.typeMapping
+          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
+    );
+  }
+
+  @override
+  SnLocalAttachment createAlias(String alias) {
+    return SnLocalAttachment(attachedDatabase, alias);
+  }
+}
+
+class SnLocalAttachmentData extends DataClass
+    implements Insertable<SnLocalAttachmentData> {
+  final int id;
+  final String rid;
+  final String uuid;
+  final String content;
+  final int accountId;
+  final DateTime createdAt;
+  const SnLocalAttachmentData(
+      {required this.id,
+      required this.rid,
+      required this.uuid,
+      required this.content,
+      required this.accountId,
+      required this.createdAt});
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    map['id'] = Variable<int>(id);
+    map['rid'] = Variable<String>(rid);
+    map['uuid'] = Variable<String>(uuid);
+    map['content'] = Variable<String>(content);
+    map['account_id'] = Variable<int>(accountId);
+    map['created_at'] = Variable<DateTime>(createdAt);
+    return map;
+  }
+
+  SnLocalAttachmentCompanion toCompanion(bool nullToAbsent) {
+    return SnLocalAttachmentCompanion(
+      id: Value(id),
+      rid: Value(rid),
+      uuid: Value(uuid),
+      content: Value(content),
+      accountId: Value(accountId),
+      createdAt: Value(createdAt),
+    );
+  }
+
+  factory SnLocalAttachmentData.fromJson(Map<String, dynamic> json,
+      {ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return SnLocalAttachmentData(
+      id: serializer.fromJson<int>(json['id']),
+      rid: serializer.fromJson<String>(json['rid']),
+      uuid: serializer.fromJson<String>(json['uuid']),
+      content: serializer.fromJson<String>(json['content']),
+      accountId: serializer.fromJson<int>(json['accountId']),
+      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
+    );
+  }
+  @override
+  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
+    serializer ??= driftRuntimeOptions.defaultSerializer;
+    return <String, dynamic>{
+      'id': serializer.toJson<int>(id),
+      'rid': serializer.toJson<String>(rid),
+      'uuid': serializer.toJson<String>(uuid),
+      'content': serializer.toJson<String>(content),
+      'accountId': serializer.toJson<int>(accountId),
+      'createdAt': serializer.toJson<DateTime>(createdAt),
+    };
+  }
+
+  SnLocalAttachmentData copyWith(
+          {int? id,
+          String? rid,
+          String? uuid,
+          String? content,
+          int? accountId,
+          DateTime? createdAt}) =>
+      SnLocalAttachmentData(
+        id: id ?? this.id,
+        rid: rid ?? this.rid,
+        uuid: uuid ?? this.uuid,
+        content: content ?? this.content,
+        accountId: accountId ?? this.accountId,
+        createdAt: createdAt ?? this.createdAt,
+      );
+  SnLocalAttachmentData copyWithCompanion(SnLocalAttachmentCompanion data) {
+    return SnLocalAttachmentData(
+      id: data.id.present ? data.id.value : this.id,
+      rid: data.rid.present ? data.rid.value : this.rid,
+      uuid: data.uuid.present ? data.uuid.value : this.uuid,
+      content: data.content.present ? data.content.value : this.content,
+      accountId: data.accountId.present ? data.accountId.value : this.accountId,
+      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
+    );
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAttachmentData(')
+          ..write('id: $id, ')
+          ..write('rid: $rid, ')
+          ..write('uuid: $uuid, ')
+          ..write('content: $content, ')
+          ..write('accountId: $accountId, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+
+  @override
+  int get hashCode => Object.hash(id, rid, uuid, content, accountId, createdAt);
+  @override
+  bool operator ==(Object other) =>
+      identical(this, other) ||
+      (other is SnLocalAttachmentData &&
+          other.id == this.id &&
+          other.rid == this.rid &&
+          other.uuid == this.uuid &&
+          other.content == this.content &&
+          other.accountId == this.accountId &&
+          other.createdAt == this.createdAt);
+}
+
+class SnLocalAttachmentCompanion
+    extends UpdateCompanion<SnLocalAttachmentData> {
+  final Value<int> id;
+  final Value<String> rid;
+  final Value<String> uuid;
+  final Value<String> content;
+  final Value<int> accountId;
+  final Value<DateTime> createdAt;
+  const SnLocalAttachmentCompanion({
+    this.id = const Value.absent(),
+    this.rid = const Value.absent(),
+    this.uuid = const Value.absent(),
+    this.content = const Value.absent(),
+    this.accountId = const Value.absent(),
+    this.createdAt = const Value.absent(),
+  });
+  SnLocalAttachmentCompanion.insert({
+    this.id = const Value.absent(),
+    required String rid,
+    required String uuid,
+    required String content,
+    required int accountId,
+    this.createdAt = const Value.absent(),
+  })  : rid = Value(rid),
+        uuid = Value(uuid),
+        content = Value(content),
+        accountId = Value(accountId);
+  static Insertable<SnLocalAttachmentData> custom({
+    Expression<int>? id,
+    Expression<String>? rid,
+    Expression<String>? uuid,
+    Expression<String>? content,
+    Expression<int>? accountId,
+    Expression<DateTime>? createdAt,
+  }) {
+    return RawValuesInsertable({
+      if (id != null) 'id': id,
+      if (rid != null) 'rid': rid,
+      if (uuid != null) 'uuid': uuid,
+      if (content != null) 'content': content,
+      if (accountId != null) 'account_id': accountId,
+      if (createdAt != null) 'created_at': createdAt,
+    });
+  }
+
+  SnLocalAttachmentCompanion copyWith(
+      {Value<int>? id,
+      Value<String>? rid,
+      Value<String>? uuid,
+      Value<String>? content,
+      Value<int>? accountId,
+      Value<DateTime>? createdAt}) {
+    return SnLocalAttachmentCompanion(
+      id: id ?? this.id,
+      rid: rid ?? this.rid,
+      uuid: uuid ?? this.uuid,
+      content: content ?? this.content,
+      accountId: accountId ?? this.accountId,
+      createdAt: createdAt ?? this.createdAt,
+    );
+  }
+
+  @override
+  Map<String, Expression> toColumns(bool nullToAbsent) {
+    final map = <String, Expression>{};
+    if (id.present) {
+      map['id'] = Variable<int>(id.value);
+    }
+    if (rid.present) {
+      map['rid'] = Variable<String>(rid.value);
+    }
+    if (uuid.present) {
+      map['uuid'] = Variable<String>(uuid.value);
+    }
+    if (content.present) {
+      map['content'] = Variable<String>(content.value);
+    }
+    if (accountId.present) {
+      map['account_id'] = Variable<int>(accountId.value);
+    }
+    if (createdAt.present) {
+      map['created_at'] = Variable<DateTime>(createdAt.value);
+    }
+    return map;
+  }
+
+  @override
+  String toString() {
+    return (StringBuffer('SnLocalAttachmentCompanion(')
+          ..write('id: $id, ')
+          ..write('rid: $rid, ')
+          ..write('uuid: $uuid, ')
+          ..write('content: $content, ')
+          ..write('accountId: $accountId, ')
+          ..write('createdAt: $createdAt')
+          ..write(')'))
+        .toString();
+  }
+}
+
+class DatabaseAtV3 extends GeneratedDatabase {
+  DatabaseAtV3(QueryExecutor e) : super(e);
+  late final SnLocalChatChannel snLocalChatChannel = SnLocalChatChannel(this);
+  late final SnLocalChatMessage snLocalChatMessage = SnLocalChatMessage(this);
+  late final SnLocalChannelMember snLocalChannelMember =
+      SnLocalChannelMember(this);
+  late final SnLocalKeyPair snLocalKeyPair = SnLocalKeyPair(this);
+  late final SnLocalAccount snLocalAccount = SnLocalAccount(this);
+  late final SnLocalAttachment snLocalAttachment = SnLocalAttachment(this);
+  late final Index idxChannelAlias = Index('idx_channel_alias',
+      'CREATE INDEX idx_channel_alias ON sn_local_chat_channel (alias)');
+  late final Index idxChatChannel = Index('idx_chat_channel',
+      'CREATE INDEX idx_chat_channel ON sn_local_chat_message (channel_id)');
+  late final Index idxAccountName = Index('idx_account_name',
+      'CREATE INDEX idx_account_name ON sn_local_account (name)');
+  late final Index idxAttachmentRid = Index('idx_attachment_rid',
+      'CREATE INDEX idx_attachment_rid ON sn_local_attachment (rid)');
+  late final Index idxAttachmentAccount = Index('idx_attachment_account',
+      'CREATE INDEX idx_attachment_account ON sn_local_attachment (account_id)');
+  @override
+  Iterable<TableInfo<Table, Object?>> get allTables =>
+      allSchemaEntities.whereType<TableInfo<Table, Object?>>();
+  @override
+  List<DatabaseSchemaEntity> get allSchemaEntities => [
+        snLocalChatChannel,
+        snLocalChatMessage,
+        snLocalChannelMember,
+        snLocalKeyPair,
+        snLocalAccount,
+        snLocalAttachment,
+        idxChannelAlias,
+        idxChatChannel,
+        idxAccountName,
+        idxAttachmentRid,
+        idxAttachmentAccount
+      ];
+  @override
+  int get schemaVersion => 3;
+}