This commit is contained in:
2025-11-24 17:53:00 +09:00
parent e992a5ca5e
commit dde81cab65
34 changed files with 3718 additions and 469 deletions
@@ -0,0 +1,47 @@
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
part 'ephemeral_database.g.dart'; // (나중에 생성될 파일)
// 테이블 정의: 미디어 메타데이터
class MediaItems extends Table {
TextColumn get id => text()(); // UUID
TextColumn get senderId => text()();
TextColumn get senderName => text()();
TextColumn get type => text()(); // 'IMAGE', 'VIDEO', 'AUDIO'
TextColumn get filePath => text()(); // 로컬 저장 경로
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
@override
Set<Column> get primaryKey => {id};
}
@DriftDatabase(tables: [MediaItems])
class EphemeralDatabase extends _$EphemeralDatabase {
// 싱글톤이 아닌 인스턴스로 관리 (방 만들 때 생성, 나갈 때 close)
EphemeralDatabase(QueryExecutor e) : super(e);
@override
int get schemaVersion => 1;
// 팩토리: 파일 기반 DB 생성
static Future<EphemeralDatabase> create(String roomName) async {
final dbFolder = await getApplicationDocumentsDirectory();
// 방 이름이나 ID로 파일명 구분
final file = File(p.join(dbFolder.path, 'room_$roomName.sqlite'));
return EphemeralDatabase(NativeDatabase(file));
}
// CRUD 쿼리
Future<List<MediaItem>> getAllMedia() => select(mediaItems).get();
Future<int> insertMedia(MediaItemsCompanion entry) => into(mediaItems).insert(entry);
// [핵심] 방 폭파 시 데이터 삭제
Future<void> wipeData() async {
await close(); // DB 연결 종료
// 실제 파일 삭제 로직은 Manager에서 수행 (DB 파일 자체를 날림)
}
}
@@ -0,0 +1,557 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'ephemeral_database.dart';
// ignore_for_file: type=lint
class $MediaItemsTable extends MediaItems
with TableInfo<$MediaItemsTable, MediaItem> {
@override
final GeneratedDatabase attachedDatabase;
final String? _alias;
$MediaItemsTable(this.attachedDatabase, [this._alias]);
static const VerificationMeta _idMeta = const VerificationMeta('id');
@override
late final GeneratedColumn<String> id = GeneratedColumn<String>(
'id', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true);
static const VerificationMeta _senderIdMeta =
const VerificationMeta('senderId');
@override
late final GeneratedColumn<String> senderId = GeneratedColumn<String>(
'sender_id', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true);
static const VerificationMeta _senderNameMeta =
const VerificationMeta('senderName');
@override
late final GeneratedColumn<String> senderName = GeneratedColumn<String>(
'sender_name', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true);
static const VerificationMeta _typeMeta = const VerificationMeta('type');
@override
late final GeneratedColumn<String> type = GeneratedColumn<String>(
'type', aliasedName, false,
type: DriftSqlType.string, requiredDuringInsert: true);
static const VerificationMeta _filePathMeta =
const VerificationMeta('filePath');
@override
late final GeneratedColumn<String> filePath = GeneratedColumn<String>(
'file_path', aliasedName, false,
type: DriftSqlType.string, 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, senderId, senderName, type, filePath, createdAt];
@override
String get aliasedName => _alias ?? actualTableName;
@override
String get actualTableName => $name;
static const String $name = 'media_items';
@override
VerificationContext validateIntegrity(Insertable<MediaItem> instance,
{bool isInserting = false}) {
final context = VerificationContext();
final data = instance.toColumns(true);
if (data.containsKey('id')) {
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
} else if (isInserting) {
context.missing(_idMeta);
}
if (data.containsKey('sender_id')) {
context.handle(_senderIdMeta,
senderId.isAcceptableOrUnknown(data['sender_id']!, _senderIdMeta));
} else if (isInserting) {
context.missing(_senderIdMeta);
}
if (data.containsKey('sender_name')) {
context.handle(
_senderNameMeta,
senderName.isAcceptableOrUnknown(
data['sender_name']!, _senderNameMeta));
} else if (isInserting) {
context.missing(_senderNameMeta);
}
if (data.containsKey('type')) {
context.handle(
_typeMeta, type.isAcceptableOrUnknown(data['type']!, _typeMeta));
} else if (isInserting) {
context.missing(_typeMeta);
}
if (data.containsKey('file_path')) {
context.handle(_filePathMeta,
filePath.isAcceptableOrUnknown(data['file_path']!, _filePathMeta));
} else if (isInserting) {
context.missing(_filePathMeta);
}
if (data.containsKey('created_at')) {
context.handle(_createdAtMeta,
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
}
return context;
}
@override
Set<GeneratedColumn> get $primaryKey => {id};
@override
MediaItem map(Map<String, dynamic> data, {String? tablePrefix}) {
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
return MediaItem(
id: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}id'])!,
senderId: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}sender_id'])!,
senderName: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}sender_name'])!,
type: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}type'])!,
filePath: attachedDatabase.typeMapping
.read(DriftSqlType.string, data['${effectivePrefix}file_path'])!,
createdAt: attachedDatabase.typeMapping
.read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
);
}
@override
$MediaItemsTable createAlias(String alias) {
return $MediaItemsTable(attachedDatabase, alias);
}
}
class MediaItem extends DataClass implements Insertable<MediaItem> {
final String id;
final String senderId;
final String senderName;
final String type;
final String filePath;
final DateTime createdAt;
const MediaItem(
{required this.id,
required this.senderId,
required this.senderName,
required this.type,
required this.filePath,
required this.createdAt});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
final map = <String, Expression>{};
map['id'] = Variable<String>(id);
map['sender_id'] = Variable<String>(senderId);
map['sender_name'] = Variable<String>(senderName);
map['type'] = Variable<String>(type);
map['file_path'] = Variable<String>(filePath);
map['created_at'] = Variable<DateTime>(createdAt);
return map;
}
MediaItemsCompanion toCompanion(bool nullToAbsent) {
return MediaItemsCompanion(
id: Value(id),
senderId: Value(senderId),
senderName: Value(senderName),
type: Value(type),
filePath: Value(filePath),
createdAt: Value(createdAt),
);
}
factory MediaItem.fromJson(Map<String, dynamic> json,
{ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return MediaItem(
id: serializer.fromJson<String>(json['id']),
senderId: serializer.fromJson<String>(json['senderId']),
senderName: serializer.fromJson<String>(json['senderName']),
type: serializer.fromJson<String>(json['type']),
filePath: serializer.fromJson<String>(json['filePath']),
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
);
}
@override
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
serializer ??= driftRuntimeOptions.defaultSerializer;
return <String, dynamic>{
'id': serializer.toJson<String>(id),
'senderId': serializer.toJson<String>(senderId),
'senderName': serializer.toJson<String>(senderName),
'type': serializer.toJson<String>(type),
'filePath': serializer.toJson<String>(filePath),
'createdAt': serializer.toJson<DateTime>(createdAt),
};
}
MediaItem copyWith(
{String? id,
String? senderId,
String? senderName,
String? type,
String? filePath,
DateTime? createdAt}) =>
MediaItem(
id: id ?? this.id,
senderId: senderId ?? this.senderId,
senderName: senderName ?? this.senderName,
type: type ?? this.type,
filePath: filePath ?? this.filePath,
createdAt: createdAt ?? this.createdAt,
);
MediaItem copyWithCompanion(MediaItemsCompanion data) {
return MediaItem(
id: data.id.present ? data.id.value : this.id,
senderId: data.senderId.present ? data.senderId.value : this.senderId,
senderName:
data.senderName.present ? data.senderName.value : this.senderName,
type: data.type.present ? data.type.value : this.type,
filePath: data.filePath.present ? data.filePath.value : this.filePath,
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
);
}
@override
String toString() {
return (StringBuffer('MediaItem(')
..write('id: $id, ')
..write('senderId: $senderId, ')
..write('senderName: $senderName, ')
..write('type: $type, ')
..write('filePath: $filePath, ')
..write('createdAt: $createdAt')
..write(')'))
.toString();
}
@override
int get hashCode =>
Object.hash(id, senderId, senderName, type, filePath, createdAt);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is MediaItem &&
other.id == this.id &&
other.senderId == this.senderId &&
other.senderName == this.senderName &&
other.type == this.type &&
other.filePath == this.filePath &&
other.createdAt == this.createdAt);
}
class MediaItemsCompanion extends UpdateCompanion<MediaItem> {
final Value<String> id;
final Value<String> senderId;
final Value<String> senderName;
final Value<String> type;
final Value<String> filePath;
final Value<DateTime> createdAt;
final Value<int> rowid;
const MediaItemsCompanion({
this.id = const Value.absent(),
this.senderId = const Value.absent(),
this.senderName = const Value.absent(),
this.type = const Value.absent(),
this.filePath = const Value.absent(),
this.createdAt = const Value.absent(),
this.rowid = const Value.absent(),
});
MediaItemsCompanion.insert({
required String id,
required String senderId,
required String senderName,
required String type,
required String filePath,
this.createdAt = const Value.absent(),
this.rowid = const Value.absent(),
}) : id = Value(id),
senderId = Value(senderId),
senderName = Value(senderName),
type = Value(type),
filePath = Value(filePath);
static Insertable<MediaItem> custom({
Expression<String>? id,
Expression<String>? senderId,
Expression<String>? senderName,
Expression<String>? type,
Expression<String>? filePath,
Expression<DateTime>? createdAt,
Expression<int>? rowid,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
if (senderId != null) 'sender_id': senderId,
if (senderName != null) 'sender_name': senderName,
if (type != null) 'type': type,
if (filePath != null) 'file_path': filePath,
if (createdAt != null) 'created_at': createdAt,
if (rowid != null) 'rowid': rowid,
});
}
MediaItemsCompanion copyWith(
{Value<String>? id,
Value<String>? senderId,
Value<String>? senderName,
Value<String>? type,
Value<String>? filePath,
Value<DateTime>? createdAt,
Value<int>? rowid}) {
return MediaItemsCompanion(
id: id ?? this.id,
senderId: senderId ?? this.senderId,
senderName: senderName ?? this.senderName,
type: type ?? this.type,
filePath: filePath ?? this.filePath,
createdAt: createdAt ?? this.createdAt,
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 (senderId.present) {
map['sender_id'] = Variable<String>(senderId.value);
}
if (senderName.present) {
map['sender_name'] = Variable<String>(senderName.value);
}
if (type.present) {
map['type'] = Variable<String>(type.value);
}
if (filePath.present) {
map['file_path'] = Variable<String>(filePath.value);
}
if (createdAt.present) {
map['created_at'] = Variable<DateTime>(createdAt.value);
}
if (rowid.present) {
map['rowid'] = Variable<int>(rowid.value);
}
return map;
}
@override
String toString() {
return (StringBuffer('MediaItemsCompanion(')
..write('id: $id, ')
..write('senderId: $senderId, ')
..write('senderName: $senderName, ')
..write('type: $type, ')
..write('filePath: $filePath, ')
..write('createdAt: $createdAt, ')
..write('rowid: $rowid')
..write(')'))
.toString();
}
}
abstract class _$EphemeralDatabase extends GeneratedDatabase {
_$EphemeralDatabase(QueryExecutor e) : super(e);
$EphemeralDatabaseManager get managers => $EphemeralDatabaseManager(this);
late final $MediaItemsTable mediaItems = $MediaItemsTable(this);
@override
Iterable<TableInfo<Table, Object?>> get allTables =>
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
@override
List<DatabaseSchemaEntity> get allSchemaEntities => [mediaItems];
}
typedef $$MediaItemsTableCreateCompanionBuilder = MediaItemsCompanion Function({
required String id,
required String senderId,
required String senderName,
required String type,
required String filePath,
Value<DateTime> createdAt,
Value<int> rowid,
});
typedef $$MediaItemsTableUpdateCompanionBuilder = MediaItemsCompanion Function({
Value<String> id,
Value<String> senderId,
Value<String> senderName,
Value<String> type,
Value<String> filePath,
Value<DateTime> createdAt,
Value<int> rowid,
});
class $$MediaItemsTableFilterComposer
extends Composer<_$EphemeralDatabase, $MediaItemsTable> {
$$MediaItemsTableFilterComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnFilters<String> get id => $composableBuilder(
column: $table.id, builder: (column) => ColumnFilters(column));
ColumnFilters<String> get senderId => $composableBuilder(
column: $table.senderId, builder: (column) => ColumnFilters(column));
ColumnFilters<String> get senderName => $composableBuilder(
column: $table.senderName, builder: (column) => ColumnFilters(column));
ColumnFilters<String> get type => $composableBuilder(
column: $table.type, builder: (column) => ColumnFilters(column));
ColumnFilters<String> get filePath => $composableBuilder(
column: $table.filePath, builder: (column) => ColumnFilters(column));
ColumnFilters<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt, builder: (column) => ColumnFilters(column));
}
class $$MediaItemsTableOrderingComposer
extends Composer<_$EphemeralDatabase, $MediaItemsTable> {
$$MediaItemsTableOrderingComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
ColumnOrderings<String> get id => $composableBuilder(
column: $table.id, builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get senderId => $composableBuilder(
column: $table.senderId, builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get senderName => $composableBuilder(
column: $table.senderName, builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get type => $composableBuilder(
column: $table.type, builder: (column) => ColumnOrderings(column));
ColumnOrderings<String> get filePath => $composableBuilder(
column: $table.filePath, builder: (column) => ColumnOrderings(column));
ColumnOrderings<DateTime> get createdAt => $composableBuilder(
column: $table.createdAt, builder: (column) => ColumnOrderings(column));
}
class $$MediaItemsTableAnnotationComposer
extends Composer<_$EphemeralDatabase, $MediaItemsTable> {
$$MediaItemsTableAnnotationComposer({
required super.$db,
required super.$table,
super.joinBuilder,
super.$addJoinBuilderToRootComposer,
super.$removeJoinBuilderFromRootComposer,
});
GeneratedColumn<String> get id =>
$composableBuilder(column: $table.id, builder: (column) => column);
GeneratedColumn<String> get senderId =>
$composableBuilder(column: $table.senderId, builder: (column) => column);
GeneratedColumn<String> get senderName => $composableBuilder(
column: $table.senderName, builder: (column) => column);
GeneratedColumn<String> get type =>
$composableBuilder(column: $table.type, builder: (column) => column);
GeneratedColumn<String> get filePath =>
$composableBuilder(column: $table.filePath, builder: (column) => column);
GeneratedColumn<DateTime> get createdAt =>
$composableBuilder(column: $table.createdAt, builder: (column) => column);
}
class $$MediaItemsTableTableManager extends RootTableManager<
_$EphemeralDatabase,
$MediaItemsTable,
MediaItem,
$$MediaItemsTableFilterComposer,
$$MediaItemsTableOrderingComposer,
$$MediaItemsTableAnnotationComposer,
$$MediaItemsTableCreateCompanionBuilder,
$$MediaItemsTableUpdateCompanionBuilder,
(
MediaItem,
BaseReferences<_$EphemeralDatabase, $MediaItemsTable, MediaItem>
),
MediaItem,
PrefetchHooks Function()> {
$$MediaItemsTableTableManager(_$EphemeralDatabase db, $MediaItemsTable table)
: super(TableManagerState(
db: db,
table: table,
createFilteringComposer: () =>
$$MediaItemsTableFilterComposer($db: db, $table: table),
createOrderingComposer: () =>
$$MediaItemsTableOrderingComposer($db: db, $table: table),
createComputedFieldComposer: () =>
$$MediaItemsTableAnnotationComposer($db: db, $table: table),
updateCompanionCallback: ({
Value<String> id = const Value.absent(),
Value<String> senderId = const Value.absent(),
Value<String> senderName = const Value.absent(),
Value<String> type = const Value.absent(),
Value<String> filePath = const Value.absent(),
Value<DateTime> createdAt = const Value.absent(),
Value<int> rowid = const Value.absent(),
}) =>
MediaItemsCompanion(
id: id,
senderId: senderId,
senderName: senderName,
type: type,
filePath: filePath,
createdAt: createdAt,
rowid: rowid,
),
createCompanionCallback: ({
required String id,
required String senderId,
required String senderName,
required String type,
required String filePath,
Value<DateTime> createdAt = const Value.absent(),
Value<int> rowid = const Value.absent(),
}) =>
MediaItemsCompanion.insert(
id: id,
senderId: senderId,
senderName: senderName,
type: type,
filePath: filePath,
createdAt: createdAt,
rowid: rowid,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
.toList(),
prefetchHooksCallback: null,
));
}
typedef $$MediaItemsTableProcessedTableManager = ProcessedTableManager<
_$EphemeralDatabase,
$MediaItemsTable,
MediaItem,
$$MediaItemsTableFilterComposer,
$$MediaItemsTableOrderingComposer,
$$MediaItemsTableAnnotationComposer,
$$MediaItemsTableCreateCompanionBuilder,
$$MediaItemsTableUpdateCompanionBuilder,
(
MediaItem,
BaseReferences<_$EphemeralDatabase, $MediaItemsTable, MediaItem>
),
MediaItem,
PrefetchHooks Function()>;
class $EphemeralDatabaseManager {
final _$EphemeralDatabase _db;
$EphemeralDatabaseManager(this._db);
$$MediaItemsTableTableManager get mediaItems =>
$$MediaItemsTableTableManager(_db, _db.mediaItems);
}