diff --git a/lib/library/database.dart b/lib/library/database.dart index c860868..f7645ea 100644 --- a/lib/library/database.dart +++ b/lib/library/database.dart @@ -4,6 +4,7 @@ import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; +import 'package:uuid/uuid.dart'; part 'database.g.dart'; @@ -36,12 +37,68 @@ class Folders extends Table { Set get primaryKey => {id}; } -@DriftDatabase(tables: [Songs, Folders]) +/// Nutzer-Playlisten. +class Playlists extends Table { + TextColumn get id => text()(); // uuid + TextColumn get name => text()(); + TextColumn get description => text().nullable()(); + IntColumn get createdAtMs => integer()(); + IntColumn get updatedAtMs => integer()(); + BoolColumn get deleted => boolean().withDefault(const Constant(false))(); + + @override + Set get primaryKey => {id}; +} + +/// Zuordnung Song ↔ Playlist mit Reihenfolge. +class PlaylistSongs extends Table { + TextColumn get playlistId => text().references(Playlists, #id)(); + TextColumn get songId => text().references(Songs, #id)(); + IntColumn get position => integer()(); + IntColumn get addedAtMs => integer()(); + + @override + Set get primaryKey => {playlistId, songId}; +} + +/// Favorisierte Songs. +class Favorites extends Table { + TextColumn get songId => text().references(Songs, #id)(); + IntColumn get createdAtMs => integer()(); + + @override + Set get primaryKey => {songId}; +} + +/// Wiedergabe-Historie: letzte Position pro Song (für Resume) + Verlauf. +class PlaybackHistory extends Table { + TextColumn get songId => text().references(Songs, #id)(); + IntColumn get positionMs => integer()(); + IntColumn get playedAtMs => integer()(); + + @override + Set get primaryKey => {songId, playedAtMs}; +} + +@DriftDatabase(tables: [Songs, Folders, Playlists, PlaylistSongs, Favorites, PlaybackHistory]) class MeloDb extends _$MeloDb { MeloDb([QueryExecutor? executor]) : super(executor ?? _open()); @override - int get schemaVersion => 1; + int get schemaVersion => 2; + + @override + MigrationStrategy get migration => MigrationStrategy( + onCreate: (m) => m.createAll(), + onUpgrade: (m, from, to) async { + if (from < 2) { + await m.createTable(playlists); + await m.createTable(playlistSongs); + await m.createTable(favorites); + await m.createTable(playbackHistory); + } + }, + ); /// Überwacht alle Songs (nicht getombstonte). Nach Titel sortiert. Stream> watchSongs() { @@ -109,6 +166,116 @@ class MeloDb extends _$MeloDb { Future addFolder(FoldersCompanion folder) => into(folders).insert(folder, onConflict: DoUpdate((_) => folder, target: [folders.path])); + + static const _uuid = Uuid(); + + // === Playlists === + Stream> watchPlaylists() => + (select(playlists) + ..where((p) => p.deleted.equals(false)) + ..orderBy([(p) => OrderingTerm(expression: p.createdAtMs, mode: OrderingMode.desc)])) + .watch(); + + Future createPlaylist(String name, {String? description}) async { + final id = _uuid.v4(); + final now = DateTime.now().millisecondsSinceEpoch; + await into(playlists).insert(PlaylistsCompanion.insert( + id: id, + name: name, + description: Value(description), + createdAtMs: now, + updatedAtMs: now, + )); + return id; + } + + Future deletePlaylist(String id) async { + await (update(playlists)..where((p) => p.id.equals(id))).write( + PlaylistsCompanion( + deleted: const Value(true), + updatedAtMs: Value(DateTime.now().millisecondsSinceEpoch), + ), + ); + } + + // === PlaylistSongs === + Stream> watchPlaylistSongs(String playlistId) { + final query = select(songs).join([ + innerJoin(playlistSongs, playlistSongs.songId.equalsExp(songs.id)), + ]) + ..where(playlistSongs.playlistId.equals(playlistId)) + ..orderBy([OrderingTerm(expression: playlistSongs.position)]); + return query.watch().map((rows) => rows.map((r) => r.readTable(songs)).toList()); + } + + Future addSongToPlaylist(String playlistId, String songId, int position) async { + await into(playlistSongs).insert( + PlaylistSongsCompanion.insert( + playlistId: playlistId, + songId: songId, + position: position, + addedAtMs: DateTime.now().millisecondsSinceEpoch, + ), + mode: InsertMode.insertOrReplace, + ); + } + + Future removeSongFromPlaylist(String playlistId, String songId) async { + await (delete(playlistSongs) + ..where((ps) => ps.playlistId.equals(playlistId) & ps.songId.equals(songId))) + .go(); + } + + Future reorderPlaylistSong(String playlistId, String songId, int newPosition) async { + await (update(playlistSongs) + ..where((ps) => ps.playlistId.equals(playlistId) & ps.songId.equals(songId))) + .write(PlaylistSongsCompanion(position: Value(newPosition))); + } + + // === Favorites === + Future toggleFavorite(String songId) async { + final existing = await (select(favorites)..where((f) => f.songId.equals(songId))).getSingleOrNull(); + if (existing == null) { + await into(favorites).insert(FavoritesCompanion.insert( + songId: songId, + createdAtMs: DateTime.now().millisecondsSinceEpoch, + )); + } else { + await (delete(favorites)..where((f) => f.songId.equals(songId))).go(); + } + } + + Stream watchIsFavorite(String songId) { + return (select(favorites)..where((f) => f.songId.equals(songId))) + .watchSingleOrNull() + .map((row) => row != null); + } + + Stream> watchFavorites() { + final query = select(songs).join([ + innerJoin(favorites, favorites.songId.equalsExp(songs.id)), + ]) + ..orderBy([OrderingTerm(expression: favorites.createdAtMs, mode: OrderingMode.desc)]); + return query.watch().map((rows) => rows.map((r) => r.readTable(songs)).toList()); + } + + // === Playback History === + Future recordPlayback(String songId, int positionMs) async { + await into(playbackHistory).insert(PlaybackHistoryCompanion.insert( + songId: songId, + positionMs: positionMs, + playedAtMs: DateTime.now().millisecondsSinceEpoch, + )); + } + + Future lastPosition(String songId) async { + final row = await (select(playbackHistory) + ..where((h) => h.songId.equals(songId)) + ..orderBy([(h) => OrderingTerm(expression: h.playedAtMs, mode: OrderingMode.desc)]) + ..limit(1)) + .getSingleOrNull(); + return row?.positionMs; + } } LazyDatabase _open() { diff --git a/lib/library/database.g.dart b/lib/library/database.g.dart index 7772e5e..9b759c3 100644 --- a/lib/library/database.g.dart +++ b/lib/library/database.g.dart @@ -934,16 +934,1281 @@ class FoldersCompanion extends UpdateCompanion { } } +class $PlaylistsTable extends Playlists + with TableInfo<$PlaylistsTable, Playlist> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $PlaylistsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + static const VerificationMeta _descriptionMeta = const VerificationMeta( + 'description', + ); + @override + late final GeneratedColumn description = GeneratedColumn( + 'description', + aliasedName, + true, + type: DriftSqlType.string, + requiredDuringInsert: false, + ); + static const VerificationMeta _createdAtMsMeta = const VerificationMeta( + 'createdAtMs', + ); + @override + late final GeneratedColumn createdAtMs = GeneratedColumn( + 'created_at_ms', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _updatedAtMsMeta = const VerificationMeta( + 'updatedAtMs', + ); + @override + late final GeneratedColumn updatedAtMs = GeneratedColumn( + 'updated_at_ms', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _deletedMeta = const VerificationMeta( + 'deleted', + ); + @override + late final GeneratedColumn deleted = GeneratedColumn( + 'deleted', + aliasedName, + false, + type: DriftSqlType.bool, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'CHECK ("deleted" IN (0, 1))', + ), + defaultValue: const Constant(false), + ); + @override + List get $columns => [ + id, + name, + description, + createdAtMs, + updatedAtMs, + deleted, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'playlists'; + @override + VerificationContext validateIntegrity( + Insertable 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('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('description')) { + context.handle( + _descriptionMeta, + description.isAcceptableOrUnknown( + data['description']!, + _descriptionMeta, + ), + ); + } + if (data.containsKey('created_at_ms')) { + context.handle( + _createdAtMsMeta, + createdAtMs.isAcceptableOrUnknown( + data['created_at_ms']!, + _createdAtMsMeta, + ), + ); + } else if (isInserting) { + context.missing(_createdAtMsMeta); + } + if (data.containsKey('updated_at_ms')) { + context.handle( + _updatedAtMsMeta, + updatedAtMs.isAcceptableOrUnknown( + data['updated_at_ms']!, + _updatedAtMsMeta, + ), + ); + } else if (isInserting) { + context.missing(_updatedAtMsMeta); + } + if (data.containsKey('deleted')) { + context.handle( + _deletedMeta, + deleted.isAcceptableOrUnknown(data['deleted']!, _deletedMeta), + ); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Playlist map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Playlist( + id: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + description: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}description'], + ), + createdAtMs: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at_ms'], + )!, + updatedAtMs: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}updated_at_ms'], + )!, + deleted: attachedDatabase.typeMapping.read( + DriftSqlType.bool, + data['${effectivePrefix}deleted'], + )!, + ); + } + + @override + $PlaylistsTable createAlias(String alias) { + return $PlaylistsTable(attachedDatabase, alias); + } +} + +class Playlist extends DataClass implements Insertable { + final String id; + final String name; + final String? description; + final int createdAtMs; + final int updatedAtMs; + final bool deleted; + const Playlist({ + required this.id, + required this.name, + this.description, + required this.createdAtMs, + required this.updatedAtMs, + required this.deleted, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + if (!nullToAbsent || description != null) { + map['description'] = Variable(description); + } + map['created_at_ms'] = Variable(createdAtMs); + map['updated_at_ms'] = Variable(updatedAtMs); + map['deleted'] = Variable(deleted); + return map; + } + + PlaylistsCompanion toCompanion(bool nullToAbsent) { + return PlaylistsCompanion( + id: Value(id), + name: Value(name), + description: description == null && nullToAbsent + ? const Value.absent() + : Value(description), + createdAtMs: Value(createdAtMs), + updatedAtMs: Value(updatedAtMs), + deleted: Value(deleted), + ); + } + + factory Playlist.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Playlist( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + description: serializer.fromJson(json['description']), + createdAtMs: serializer.fromJson(json['createdAtMs']), + updatedAtMs: serializer.fromJson(json['updatedAtMs']), + deleted: serializer.fromJson(json['deleted']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'description': serializer.toJson(description), + 'createdAtMs': serializer.toJson(createdAtMs), + 'updatedAtMs': serializer.toJson(updatedAtMs), + 'deleted': serializer.toJson(deleted), + }; + } + + Playlist copyWith({ + String? id, + String? name, + Value description = const Value.absent(), + int? createdAtMs, + int? updatedAtMs, + bool? deleted, + }) => Playlist( + id: id ?? this.id, + name: name ?? this.name, + description: description.present ? description.value : this.description, + createdAtMs: createdAtMs ?? this.createdAtMs, + updatedAtMs: updatedAtMs ?? this.updatedAtMs, + deleted: deleted ?? this.deleted, + ); + Playlist copyWithCompanion(PlaylistsCompanion data) { + return Playlist( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + description: data.description.present + ? data.description.value + : this.description, + createdAtMs: data.createdAtMs.present + ? data.createdAtMs.value + : this.createdAtMs, + updatedAtMs: data.updatedAtMs.present + ? data.updatedAtMs.value + : this.updatedAtMs, + deleted: data.deleted.present ? data.deleted.value : this.deleted, + ); + } + + @override + String toString() { + return (StringBuffer('Playlist(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAtMs: $createdAtMs, ') + ..write('updatedAtMs: $updatedAtMs, ') + ..write('deleted: $deleted') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(id, name, description, createdAtMs, updatedAtMs, deleted); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Playlist && + other.id == this.id && + other.name == this.name && + other.description == this.description && + other.createdAtMs == this.createdAtMs && + other.updatedAtMs == this.updatedAtMs && + other.deleted == this.deleted); +} + +class PlaylistsCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value description; + final Value createdAtMs; + final Value updatedAtMs; + final Value deleted; + final Value rowid; + const PlaylistsCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.description = const Value.absent(), + this.createdAtMs = const Value.absent(), + this.updatedAtMs = const Value.absent(), + this.deleted = const Value.absent(), + this.rowid = const Value.absent(), + }); + PlaylistsCompanion.insert({ + required String id, + required String name, + this.description = const Value.absent(), + required int createdAtMs, + required int updatedAtMs, + this.deleted = const Value.absent(), + this.rowid = const Value.absent(), + }) : id = Value(id), + name = Value(name), + createdAtMs = Value(createdAtMs), + updatedAtMs = Value(updatedAtMs); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? description, + Expression? createdAtMs, + Expression? updatedAtMs, + Expression? deleted, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (description != null) 'description': description, + if (createdAtMs != null) 'created_at_ms': createdAtMs, + if (updatedAtMs != null) 'updated_at_ms': updatedAtMs, + if (deleted != null) 'deleted': deleted, + if (rowid != null) 'rowid': rowid, + }); + } + + PlaylistsCompanion copyWith({ + Value? id, + Value? name, + Value? description, + Value? createdAtMs, + Value? updatedAtMs, + Value? deleted, + Value? rowid, + }) { + return PlaylistsCompanion( + id: id ?? this.id, + name: name ?? this.name, + description: description ?? this.description, + createdAtMs: createdAtMs ?? this.createdAtMs, + updatedAtMs: updatedAtMs ?? this.updatedAtMs, + deleted: deleted ?? this.deleted, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (description.present) { + map['description'] = Variable(description.value); + } + if (createdAtMs.present) { + map['created_at_ms'] = Variable(createdAtMs.value); + } + if (updatedAtMs.present) { + map['updated_at_ms'] = Variable(updatedAtMs.value); + } + if (deleted.present) { + map['deleted'] = Variable(deleted.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PlaylistsCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('description: $description, ') + ..write('createdAtMs: $createdAtMs, ') + ..write('updatedAtMs: $updatedAtMs, ') + ..write('deleted: $deleted, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $PlaylistSongsTable extends PlaylistSongs + with TableInfo<$PlaylistSongsTable, PlaylistSong> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $PlaylistSongsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _playlistIdMeta = const VerificationMeta( + 'playlistId', + ); + @override + late final GeneratedColumn playlistId = GeneratedColumn( + 'playlist_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES playlists (id)', + ), + ); + static const VerificationMeta _songIdMeta = const VerificationMeta('songId'); + @override + late final GeneratedColumn songId = GeneratedColumn( + 'song_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES songs (id)', + ), + ); + static const VerificationMeta _positionMeta = const VerificationMeta( + 'position', + ); + @override + late final GeneratedColumn position = GeneratedColumn( + 'position', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _addedAtMsMeta = const VerificationMeta( + 'addedAtMs', + ); + @override + late final GeneratedColumn addedAtMs = GeneratedColumn( + 'added_at_ms', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [ + playlistId, + songId, + position, + addedAtMs, + ]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'playlist_songs'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('playlist_id')) { + context.handle( + _playlistIdMeta, + playlistId.isAcceptableOrUnknown(data['playlist_id']!, _playlistIdMeta), + ); + } else if (isInserting) { + context.missing(_playlistIdMeta); + } + if (data.containsKey('song_id')) { + context.handle( + _songIdMeta, + songId.isAcceptableOrUnknown(data['song_id']!, _songIdMeta), + ); + } else if (isInserting) { + context.missing(_songIdMeta); + } + if (data.containsKey('position')) { + context.handle( + _positionMeta, + position.isAcceptableOrUnknown(data['position']!, _positionMeta), + ); + } else if (isInserting) { + context.missing(_positionMeta); + } + if (data.containsKey('added_at_ms')) { + context.handle( + _addedAtMsMeta, + addedAtMs.isAcceptableOrUnknown(data['added_at_ms']!, _addedAtMsMeta), + ); + } else if (isInserting) { + context.missing(_addedAtMsMeta); + } + return context; + } + + @override + Set get $primaryKey => {playlistId, songId}; + @override + PlaylistSong map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PlaylistSong( + playlistId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}playlist_id'], + )!, + songId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}song_id'], + )!, + position: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}position'], + )!, + addedAtMs: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}added_at_ms'], + )!, + ); + } + + @override + $PlaylistSongsTable createAlias(String alias) { + return $PlaylistSongsTable(attachedDatabase, alias); + } +} + +class PlaylistSong extends DataClass implements Insertable { + final String playlistId; + final String songId; + final int position; + final int addedAtMs; + const PlaylistSong({ + required this.playlistId, + required this.songId, + required this.position, + required this.addedAtMs, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['playlist_id'] = Variable(playlistId); + map['song_id'] = Variable(songId); + map['position'] = Variable(position); + map['added_at_ms'] = Variable(addedAtMs); + return map; + } + + PlaylistSongsCompanion toCompanion(bool nullToAbsent) { + return PlaylistSongsCompanion( + playlistId: Value(playlistId), + songId: Value(songId), + position: Value(position), + addedAtMs: Value(addedAtMs), + ); + } + + factory PlaylistSong.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PlaylistSong( + playlistId: serializer.fromJson(json['playlistId']), + songId: serializer.fromJson(json['songId']), + position: serializer.fromJson(json['position']), + addedAtMs: serializer.fromJson(json['addedAtMs']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'playlistId': serializer.toJson(playlistId), + 'songId': serializer.toJson(songId), + 'position': serializer.toJson(position), + 'addedAtMs': serializer.toJson(addedAtMs), + }; + } + + PlaylistSong copyWith({ + String? playlistId, + String? songId, + int? position, + int? addedAtMs, + }) => PlaylistSong( + playlistId: playlistId ?? this.playlistId, + songId: songId ?? this.songId, + position: position ?? this.position, + addedAtMs: addedAtMs ?? this.addedAtMs, + ); + PlaylistSong copyWithCompanion(PlaylistSongsCompanion data) { + return PlaylistSong( + playlistId: data.playlistId.present + ? data.playlistId.value + : this.playlistId, + songId: data.songId.present ? data.songId.value : this.songId, + position: data.position.present ? data.position.value : this.position, + addedAtMs: data.addedAtMs.present ? data.addedAtMs.value : this.addedAtMs, + ); + } + + @override + String toString() { + return (StringBuffer('PlaylistSong(') + ..write('playlistId: $playlistId, ') + ..write('songId: $songId, ') + ..write('position: $position, ') + ..write('addedAtMs: $addedAtMs') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(playlistId, songId, position, addedAtMs); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PlaylistSong && + other.playlistId == this.playlistId && + other.songId == this.songId && + other.position == this.position && + other.addedAtMs == this.addedAtMs); +} + +class PlaylistSongsCompanion extends UpdateCompanion { + final Value playlistId; + final Value songId; + final Value position; + final Value addedAtMs; + final Value rowid; + const PlaylistSongsCompanion({ + this.playlistId = const Value.absent(), + this.songId = const Value.absent(), + this.position = const Value.absent(), + this.addedAtMs = const Value.absent(), + this.rowid = const Value.absent(), + }); + PlaylistSongsCompanion.insert({ + required String playlistId, + required String songId, + required int position, + required int addedAtMs, + this.rowid = const Value.absent(), + }) : playlistId = Value(playlistId), + songId = Value(songId), + position = Value(position), + addedAtMs = Value(addedAtMs); + static Insertable custom({ + Expression? playlistId, + Expression? songId, + Expression? position, + Expression? addedAtMs, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (playlistId != null) 'playlist_id': playlistId, + if (songId != null) 'song_id': songId, + if (position != null) 'position': position, + if (addedAtMs != null) 'added_at_ms': addedAtMs, + if (rowid != null) 'rowid': rowid, + }); + } + + PlaylistSongsCompanion copyWith({ + Value? playlistId, + Value? songId, + Value? position, + Value? addedAtMs, + Value? rowid, + }) { + return PlaylistSongsCompanion( + playlistId: playlistId ?? this.playlistId, + songId: songId ?? this.songId, + position: position ?? this.position, + addedAtMs: addedAtMs ?? this.addedAtMs, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (playlistId.present) { + map['playlist_id'] = Variable(playlistId.value); + } + if (songId.present) { + map['song_id'] = Variable(songId.value); + } + if (position.present) { + map['position'] = Variable(position.value); + } + if (addedAtMs.present) { + map['added_at_ms'] = Variable(addedAtMs.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PlaylistSongsCompanion(') + ..write('playlistId: $playlistId, ') + ..write('songId: $songId, ') + ..write('position: $position, ') + ..write('addedAtMs: $addedAtMs, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $FavoritesTable extends Favorites + with TableInfo<$FavoritesTable, Favorite> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $FavoritesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _songIdMeta = const VerificationMeta('songId'); + @override + late final GeneratedColumn songId = GeneratedColumn( + 'song_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES songs (id)', + ), + ); + static const VerificationMeta _createdAtMsMeta = const VerificationMeta( + 'createdAtMs', + ); + @override + late final GeneratedColumn createdAtMs = GeneratedColumn( + 'created_at_ms', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [songId, createdAtMs]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'favorites'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('song_id')) { + context.handle( + _songIdMeta, + songId.isAcceptableOrUnknown(data['song_id']!, _songIdMeta), + ); + } else if (isInserting) { + context.missing(_songIdMeta); + } + if (data.containsKey('created_at_ms')) { + context.handle( + _createdAtMsMeta, + createdAtMs.isAcceptableOrUnknown( + data['created_at_ms']!, + _createdAtMsMeta, + ), + ); + } else if (isInserting) { + context.missing(_createdAtMsMeta); + } + return context; + } + + @override + Set get $primaryKey => {songId}; + @override + Favorite map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Favorite( + songId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}song_id'], + )!, + createdAtMs: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}created_at_ms'], + )!, + ); + } + + @override + $FavoritesTable createAlias(String alias) { + return $FavoritesTable(attachedDatabase, alias); + } +} + +class Favorite extends DataClass implements Insertable { + final String songId; + final int createdAtMs; + const Favorite({required this.songId, required this.createdAtMs}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['song_id'] = Variable(songId); + map['created_at_ms'] = Variable(createdAtMs); + return map; + } + + FavoritesCompanion toCompanion(bool nullToAbsent) { + return FavoritesCompanion( + songId: Value(songId), + createdAtMs: Value(createdAtMs), + ); + } + + factory Favorite.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Favorite( + songId: serializer.fromJson(json['songId']), + createdAtMs: serializer.fromJson(json['createdAtMs']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'songId': serializer.toJson(songId), + 'createdAtMs': serializer.toJson(createdAtMs), + }; + } + + Favorite copyWith({String? songId, int? createdAtMs}) => Favorite( + songId: songId ?? this.songId, + createdAtMs: createdAtMs ?? this.createdAtMs, + ); + Favorite copyWithCompanion(FavoritesCompanion data) { + return Favorite( + songId: data.songId.present ? data.songId.value : this.songId, + createdAtMs: data.createdAtMs.present + ? data.createdAtMs.value + : this.createdAtMs, + ); + } + + @override + String toString() { + return (StringBuffer('Favorite(') + ..write('songId: $songId, ') + ..write('createdAtMs: $createdAtMs') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(songId, createdAtMs); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Favorite && + other.songId == this.songId && + other.createdAtMs == this.createdAtMs); +} + +class FavoritesCompanion extends UpdateCompanion { + final Value songId; + final Value createdAtMs; + final Value rowid; + const FavoritesCompanion({ + this.songId = const Value.absent(), + this.createdAtMs = const Value.absent(), + this.rowid = const Value.absent(), + }); + FavoritesCompanion.insert({ + required String songId, + required int createdAtMs, + this.rowid = const Value.absent(), + }) : songId = Value(songId), + createdAtMs = Value(createdAtMs); + static Insertable custom({ + Expression? songId, + Expression? createdAtMs, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (songId != null) 'song_id': songId, + if (createdAtMs != null) 'created_at_ms': createdAtMs, + if (rowid != null) 'rowid': rowid, + }); + } + + FavoritesCompanion copyWith({ + Value? songId, + Value? createdAtMs, + Value? rowid, + }) { + return FavoritesCompanion( + songId: songId ?? this.songId, + createdAtMs: createdAtMs ?? this.createdAtMs, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (songId.present) { + map['song_id'] = Variable(songId.value); + } + if (createdAtMs.present) { + map['created_at_ms'] = Variable(createdAtMs.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('FavoritesCompanion(') + ..write('songId: $songId, ') + ..write('createdAtMs: $createdAtMs, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $PlaybackHistoryTable extends PlaybackHistory + with TableInfo<$PlaybackHistoryTable, PlaybackHistoryData> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $PlaybackHistoryTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _songIdMeta = const VerificationMeta('songId'); + @override + late final GeneratedColumn songId = GeneratedColumn( + 'song_id', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'REFERENCES songs (id)', + ), + ); + static const VerificationMeta _positionMsMeta = const VerificationMeta( + 'positionMs', + ); + @override + late final GeneratedColumn positionMs = GeneratedColumn( + 'position_ms', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + static const VerificationMeta _playedAtMsMeta = const VerificationMeta( + 'playedAtMs', + ); + @override + late final GeneratedColumn playedAtMs = GeneratedColumn( + 'played_at_ms', + aliasedName, + false, + type: DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [songId, positionMs, playedAtMs]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'playback_history'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('song_id')) { + context.handle( + _songIdMeta, + songId.isAcceptableOrUnknown(data['song_id']!, _songIdMeta), + ); + } else if (isInserting) { + context.missing(_songIdMeta); + } + if (data.containsKey('position_ms')) { + context.handle( + _positionMsMeta, + positionMs.isAcceptableOrUnknown(data['position_ms']!, _positionMsMeta), + ); + } else if (isInserting) { + context.missing(_positionMsMeta); + } + if (data.containsKey('played_at_ms')) { + context.handle( + _playedAtMsMeta, + playedAtMs.isAcceptableOrUnknown( + data['played_at_ms']!, + _playedAtMsMeta, + ), + ); + } else if (isInserting) { + context.missing(_playedAtMsMeta); + } + return context; + } + + @override + Set get $primaryKey => {songId, playedAtMs}; + @override + PlaybackHistoryData map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return PlaybackHistoryData( + songId: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}song_id'], + )!, + positionMs: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}position_ms'], + )!, + playedAtMs: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}played_at_ms'], + )!, + ); + } + + @override + $PlaybackHistoryTable createAlias(String alias) { + return $PlaybackHistoryTable(attachedDatabase, alias); + } +} + +class PlaybackHistoryData extends DataClass + implements Insertable { + final String songId; + final int positionMs; + final int playedAtMs; + const PlaybackHistoryData({ + required this.songId, + required this.positionMs, + required this.playedAtMs, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['song_id'] = Variable(songId); + map['position_ms'] = Variable(positionMs); + map['played_at_ms'] = Variable(playedAtMs); + return map; + } + + PlaybackHistoryCompanion toCompanion(bool nullToAbsent) { + return PlaybackHistoryCompanion( + songId: Value(songId), + positionMs: Value(positionMs), + playedAtMs: Value(playedAtMs), + ); + } + + factory PlaybackHistoryData.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return PlaybackHistoryData( + songId: serializer.fromJson(json['songId']), + positionMs: serializer.fromJson(json['positionMs']), + playedAtMs: serializer.fromJson(json['playedAtMs']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'songId': serializer.toJson(songId), + 'positionMs': serializer.toJson(positionMs), + 'playedAtMs': serializer.toJson(playedAtMs), + }; + } + + PlaybackHistoryData copyWith({ + String? songId, + int? positionMs, + int? playedAtMs, + }) => PlaybackHistoryData( + songId: songId ?? this.songId, + positionMs: positionMs ?? this.positionMs, + playedAtMs: playedAtMs ?? this.playedAtMs, + ); + PlaybackHistoryData copyWithCompanion(PlaybackHistoryCompanion data) { + return PlaybackHistoryData( + songId: data.songId.present ? data.songId.value : this.songId, + positionMs: data.positionMs.present + ? data.positionMs.value + : this.positionMs, + playedAtMs: data.playedAtMs.present + ? data.playedAtMs.value + : this.playedAtMs, + ); + } + + @override + String toString() { + return (StringBuffer('PlaybackHistoryData(') + ..write('songId: $songId, ') + ..write('positionMs: $positionMs, ') + ..write('playedAtMs: $playedAtMs') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(songId, positionMs, playedAtMs); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is PlaybackHistoryData && + other.songId == this.songId && + other.positionMs == this.positionMs && + other.playedAtMs == this.playedAtMs); +} + +class PlaybackHistoryCompanion extends UpdateCompanion { + final Value songId; + final Value positionMs; + final Value playedAtMs; + final Value rowid; + const PlaybackHistoryCompanion({ + this.songId = const Value.absent(), + this.positionMs = const Value.absent(), + this.playedAtMs = const Value.absent(), + this.rowid = const Value.absent(), + }); + PlaybackHistoryCompanion.insert({ + required String songId, + required int positionMs, + required int playedAtMs, + this.rowid = const Value.absent(), + }) : songId = Value(songId), + positionMs = Value(positionMs), + playedAtMs = Value(playedAtMs); + static Insertable custom({ + Expression? songId, + Expression? positionMs, + Expression? playedAtMs, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (songId != null) 'song_id': songId, + if (positionMs != null) 'position_ms': positionMs, + if (playedAtMs != null) 'played_at_ms': playedAtMs, + if (rowid != null) 'rowid': rowid, + }); + } + + PlaybackHistoryCompanion copyWith({ + Value? songId, + Value? positionMs, + Value? playedAtMs, + Value? rowid, + }) { + return PlaybackHistoryCompanion( + songId: songId ?? this.songId, + positionMs: positionMs ?? this.positionMs, + playedAtMs: playedAtMs ?? this.playedAtMs, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (songId.present) { + map['song_id'] = Variable(songId.value); + } + if (positionMs.present) { + map['position_ms'] = Variable(positionMs.value); + } + if (playedAtMs.present) { + map['played_at_ms'] = Variable(playedAtMs.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('PlaybackHistoryCompanion(') + ..write('songId: $songId, ') + ..write('positionMs: $positionMs, ') + ..write('playedAtMs: $playedAtMs, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + abstract class _$MeloDb extends GeneratedDatabase { _$MeloDb(QueryExecutor e) : super(e); $MeloDbManager get managers => $MeloDbManager(this); late final $SongsTable songs = $SongsTable(this); late final $FoldersTable folders = $FoldersTable(this); + late final $PlaylistsTable playlists = $PlaylistsTable(this); + late final $PlaylistSongsTable playlistSongs = $PlaylistSongsTable(this); + late final $FavoritesTable favorites = $FavoritesTable(this); + late final $PlaybackHistoryTable playbackHistory = $PlaybackHistoryTable( + this, + ); @override Iterable> get allTables => allSchemaEntities.whereType>(); @override - List get allSchemaEntities => [songs, folders]; + List get allSchemaEntities => [ + songs, + folders, + playlists, + playlistSongs, + favorites, + playbackHistory, + ]; } typedef $$SongsTableCreateCompanionBuilder = @@ -975,6 +2240,67 @@ typedef $$SongsTableUpdateCompanionBuilder = Value rowid, }); +final class $$SongsTableReferences + extends BaseReferences<_$MeloDb, $SongsTable, Song> { + $$SongsTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static MultiTypedResultKey<$PlaylistSongsTable, List> + _playlistSongsRefsTable(_$MeloDb db) => MultiTypedResultKey.fromTable( + db.playlistSongs, + aliasName: 'songs__id__playlist_songs__song_id', + ); + + $$PlaylistSongsTableProcessedTableManager get playlistSongsRefs { + final manager = $$PlaylistSongsTableTableManager( + $_db, + $_db.playlistSongs, + ).filter((f) => f.songId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_playlistSongsRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey<$FavoritesTable, List> + _favoritesRefsTable(_$MeloDb db) => MultiTypedResultKey.fromTable( + db.favorites, + aliasName: 'songs__id__favorites__song_id', + ); + + $$FavoritesTableProcessedTableManager get favoritesRefs { + final manager = $$FavoritesTableTableManager( + $_db, + $_db.favorites, + ).filter((f) => f.songId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_favoritesRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } + + static MultiTypedResultKey<$PlaybackHistoryTable, List> + _playbackHistoryRefsTable(_$MeloDb db) => MultiTypedResultKey.fromTable( + db.playbackHistory, + aliasName: 'songs__id__playback_history__song_id', + ); + + $$PlaybackHistoryTableProcessedTableManager get playbackHistoryRefs { + final manager = $$PlaybackHistoryTableTableManager( + $_db, + $_db.playbackHistory, + ).filter((f) => f.songId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull( + _playbackHistoryRefsTable($_db), + ); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + class $$SongsTableFilterComposer extends Composer<_$MeloDb, $SongsTable> { $$SongsTableFilterComposer({ required super.$db, @@ -1032,6 +2358,81 @@ class $$SongsTableFilterComposer extends Composer<_$MeloDb, $SongsTable> { column: $table.deleted, builder: (column) => ColumnFilters(column), ); + + Expression playlistSongsRefs( + Expression Function($$PlaylistSongsTableFilterComposer f) f, + ) { + final $$PlaylistSongsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playlistSongs, + getReferencedColumn: (t) => t.songId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistSongsTableFilterComposer( + $db: $db, + $table: $db.playlistSongs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression favoritesRefs( + Expression Function($$FavoritesTableFilterComposer f) f, + ) { + final $$FavoritesTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.favorites, + getReferencedColumn: (t) => t.songId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$FavoritesTableFilterComposer( + $db: $db, + $table: $db.favorites, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression playbackHistoryRefs( + Expression Function($$PlaybackHistoryTableFilterComposer f) f, + ) { + final $$PlaybackHistoryTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playbackHistory, + getReferencedColumn: (t) => t.songId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaybackHistoryTableFilterComposer( + $db: $db, + $table: $db.playbackHistory, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$SongsTableOrderingComposer extends Composer<_$MeloDb, $SongsTable> { @@ -1136,6 +2537,81 @@ class $$SongsTableAnnotationComposer extends Composer<_$MeloDb, $SongsTable> { GeneratedColumn get deleted => $composableBuilder(column: $table.deleted, builder: (column) => column); + + Expression playlistSongsRefs( + Expression Function($$PlaylistSongsTableAnnotationComposer a) f, + ) { + final $$PlaylistSongsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playlistSongs, + getReferencedColumn: (t) => t.songId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistSongsTableAnnotationComposer( + $db: $db, + $table: $db.playlistSongs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression favoritesRefs( + Expression Function($$FavoritesTableAnnotationComposer a) f, + ) { + final $$FavoritesTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.favorites, + getReferencedColumn: (t) => t.songId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$FavoritesTableAnnotationComposer( + $db: $db, + $table: $db.favorites, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } + + Expression playbackHistoryRefs( + Expression Function($$PlaybackHistoryTableAnnotationComposer a) f, + ) { + final $$PlaybackHistoryTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playbackHistory, + getReferencedColumn: (t) => t.songId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaybackHistoryTableAnnotationComposer( + $db: $db, + $table: $db.playbackHistory, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } } class $$SongsTableTableManager @@ -1149,9 +2625,13 @@ class $$SongsTableTableManager $$SongsTableAnnotationComposer, $$SongsTableCreateCompanionBuilder, $$SongsTableUpdateCompanionBuilder, - (Song, BaseReferences<_$MeloDb, $SongsTable, Song>), + (Song, $$SongsTableReferences), Song, - PrefetchHooks Function() + PrefetchHooks Function({ + bool playlistSongsRefs, + bool favoritesRefs, + bool playbackHistoryRefs, + }) > { $$SongsTableTableManager(_$MeloDb db, $SongsTable table) : super( @@ -1217,9 +2697,90 @@ class $$SongsTableTableManager rowid: rowid, ), withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .map( + (e) => + (e.readTable(table), $$SongsTableReferences(db, table, e)), + ) .toList(), - prefetchHooksCallback: null, + prefetchHooksCallback: + ({ + playlistSongsRefs = false, + favoritesRefs = false, + playbackHistoryRefs = false, + }) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playlistSongsRefs) db.playlistSongs, + if (favoritesRefs) db.favorites, + if (playbackHistoryRefs) db.playbackHistory, + ], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (playlistSongsRefs) + await $_getPrefetchedData< + Song, + $SongsTable, + PlaylistSong + >( + currentTable: table, + referencedTable: $$SongsTableReferences + ._playlistSongsRefsTable(db), + managerFromTypedResult: (p0) => + $$SongsTableReferences( + db, + table, + p0, + ).playlistSongsRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.songId == item.id, + ), + typedResults: items, + ), + if (favoritesRefs) + await $_getPrefetchedData( + currentTable: table, + referencedTable: $$SongsTableReferences + ._favoritesRefsTable(db), + managerFromTypedResult: (p0) => + $$SongsTableReferences( + db, + table, + p0, + ).favoritesRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.songId == item.id, + ), + typedResults: items, + ), + if (playbackHistoryRefs) + await $_getPrefetchedData< + Song, + $SongsTable, + PlaybackHistoryData + >( + currentTable: table, + referencedTable: $$SongsTableReferences + ._playbackHistoryRefsTable(db), + managerFromTypedResult: (p0) => + $$SongsTableReferences( + db, + table, + p0, + ).playbackHistoryRefs, + referencedItemsForCurrentItem: + (item, referencedItems) => referencedItems.where( + (e) => e.songId == item.id, + ), + typedResults: items, + ), + ]; + }, + ); + }, ), ); } @@ -1234,9 +2795,13 @@ typedef $$SongsTableProcessedTableManager = $$SongsTableAnnotationComposer, $$SongsTableCreateCompanionBuilder, $$SongsTableUpdateCompanionBuilder, - (Song, BaseReferences<_$MeloDb, $SongsTable, Song>), + (Song, $$SongsTableReferences), Song, - PrefetchHooks Function() + PrefetchHooks Function({ + bool playlistSongsRefs, + bool favoritesRefs, + bool playbackHistoryRefs, + }) >; typedef $$FoldersTableCreateCompanionBuilder = FoldersCompanion Function({ @@ -1413,6 +2978,1274 @@ typedef $$FoldersTableProcessedTableManager = Folder, PrefetchHooks Function() >; +typedef $$PlaylistsTableCreateCompanionBuilder = + PlaylistsCompanion Function({ + required String id, + required String name, + Value description, + required int createdAtMs, + required int updatedAtMs, + Value deleted, + Value rowid, + }); +typedef $$PlaylistsTableUpdateCompanionBuilder = + PlaylistsCompanion Function({ + Value id, + Value name, + Value description, + Value createdAtMs, + Value updatedAtMs, + Value deleted, + Value rowid, + }); + +final class $$PlaylistsTableReferences + extends BaseReferences<_$MeloDb, $PlaylistsTable, Playlist> { + $$PlaylistsTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static MultiTypedResultKey<$PlaylistSongsTable, List> + _playlistSongsRefsTable(_$MeloDb db) => MultiTypedResultKey.fromTable( + db.playlistSongs, + aliasName: 'playlists__id__playlist_songs__playlist_id', + ); + + $$PlaylistSongsTableProcessedTableManager get playlistSongsRefs { + final manager = $$PlaylistSongsTableTableManager( + $_db, + $_db.playlistSongs, + ).filter((f) => f.playlistId.id.sqlEquals($_itemColumn('id')!)); + + final cache = $_typedResult.readTableOrNull(_playlistSongsRefsTable($_db)); + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: cache), + ); + } +} + +class $$PlaylistsTableFilterComposer + extends Composer<_$MeloDb, $PlaylistsTable> { + $$PlaylistsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get description => $composableBuilder( + column: $table.description, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get createdAtMs => $composableBuilder( + column: $table.createdAtMs, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get updatedAtMs => $composableBuilder( + column: $table.updatedAtMs, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get deleted => $composableBuilder( + column: $table.deleted, + builder: (column) => ColumnFilters(column), + ); + + Expression playlistSongsRefs( + Expression Function($$PlaylistSongsTableFilterComposer f) f, + ) { + final $$PlaylistSongsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playlistSongs, + getReferencedColumn: (t) => t.playlistId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistSongsTableFilterComposer( + $db: $db, + $table: $db.playlistSongs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$PlaylistsTableOrderingComposer + extends Composer<_$MeloDb, $PlaylistsTable> { + $$PlaylistsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get name => $composableBuilder( + column: $table.name, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get description => $composableBuilder( + column: $table.description, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get createdAtMs => $composableBuilder( + column: $table.createdAtMs, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get updatedAtMs => $composableBuilder( + column: $table.updatedAtMs, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get deleted => $composableBuilder( + column: $table.deleted, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$PlaylistsTableAnnotationComposer + extends Composer<_$MeloDb, $PlaylistsTable> { + $$PlaylistsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + GeneratedColumn get description => $composableBuilder( + column: $table.description, + builder: (column) => column, + ); + + GeneratedColumn get createdAtMs => $composableBuilder( + column: $table.createdAtMs, + builder: (column) => column, + ); + + GeneratedColumn get updatedAtMs => $composableBuilder( + column: $table.updatedAtMs, + builder: (column) => column, + ); + + GeneratedColumn get deleted => + $composableBuilder(column: $table.deleted, builder: (column) => column); + + Expression playlistSongsRefs( + Expression Function($$PlaylistSongsTableAnnotationComposer a) f, + ) { + final $$PlaylistSongsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.id, + referencedTable: $db.playlistSongs, + getReferencedColumn: (t) => t.playlistId, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistSongsTableAnnotationComposer( + $db: $db, + $table: $db.playlistSongs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return f(composer); + } +} + +class $$PlaylistsTableTableManager + extends + RootTableManager< + _$MeloDb, + $PlaylistsTable, + Playlist, + $$PlaylistsTableFilterComposer, + $$PlaylistsTableOrderingComposer, + $$PlaylistsTableAnnotationComposer, + $$PlaylistsTableCreateCompanionBuilder, + $$PlaylistsTableUpdateCompanionBuilder, + (Playlist, $$PlaylistsTableReferences), + Playlist, + PrefetchHooks Function({bool playlistSongsRefs}) + > { + $$PlaylistsTableTableManager(_$MeloDb db, $PlaylistsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$PlaylistsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$PlaylistsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$PlaylistsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value name = const Value.absent(), + Value description = const Value.absent(), + Value createdAtMs = const Value.absent(), + Value updatedAtMs = const Value.absent(), + Value deleted = const Value.absent(), + Value rowid = const Value.absent(), + }) => PlaylistsCompanion( + id: id, + name: name, + description: description, + createdAtMs: createdAtMs, + updatedAtMs: updatedAtMs, + deleted: deleted, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String id, + required String name, + Value description = const Value.absent(), + required int createdAtMs, + required int updatedAtMs, + Value deleted = const Value.absent(), + Value rowid = const Value.absent(), + }) => PlaylistsCompanion.insert( + id: id, + name: name, + description: description, + createdAtMs: createdAtMs, + updatedAtMs: updatedAtMs, + deleted: deleted, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$PlaylistsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({playlistSongsRefs = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [ + if (playlistSongsRefs) db.playlistSongs, + ], + addJoins: null, + getPrefetchedDataCallback: (items) async { + return [ + if (playlistSongsRefs) + await $_getPrefetchedData< + Playlist, + $PlaylistsTable, + PlaylistSong + >( + currentTable: table, + referencedTable: $$PlaylistsTableReferences + ._playlistSongsRefsTable(db), + managerFromTypedResult: (p0) => + $$PlaylistsTableReferences( + db, + table, + p0, + ).playlistSongsRefs, + referencedItemsForCurrentItem: (item, referencedItems) => + referencedItems.where((e) => e.playlistId == item.id), + typedResults: items, + ), + ]; + }, + ); + }, + ), + ); +} + +typedef $$PlaylistsTableProcessedTableManager = + ProcessedTableManager< + _$MeloDb, + $PlaylistsTable, + Playlist, + $$PlaylistsTableFilterComposer, + $$PlaylistsTableOrderingComposer, + $$PlaylistsTableAnnotationComposer, + $$PlaylistsTableCreateCompanionBuilder, + $$PlaylistsTableUpdateCompanionBuilder, + (Playlist, $$PlaylistsTableReferences), + Playlist, + PrefetchHooks Function({bool playlistSongsRefs}) + >; +typedef $$PlaylistSongsTableCreateCompanionBuilder = + PlaylistSongsCompanion Function({ + required String playlistId, + required String songId, + required int position, + required int addedAtMs, + Value rowid, + }); +typedef $$PlaylistSongsTableUpdateCompanionBuilder = + PlaylistSongsCompanion Function({ + Value playlistId, + Value songId, + Value position, + Value addedAtMs, + Value rowid, + }); + +final class $$PlaylistSongsTableReferences + extends BaseReferences<_$MeloDb, $PlaylistSongsTable, PlaylistSong> { + $$PlaylistSongsTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $PlaylistsTable _playlistIdTable(_$MeloDb db) => + db.playlists.createAlias('playlist_songs__playlist_id__playlists__id'); + + $$PlaylistsTableProcessedTableManager get playlistId { + final $_column = $_itemColumn('playlist_id')!; + + final manager = $$PlaylistsTableTableManager( + $_db, + $_db.playlists, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_playlistIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } + + static $SongsTable _songIdTable(_$MeloDb db) => + db.songs.createAlias('playlist_songs__song_id__songs__id'); + + $$SongsTableProcessedTableManager get songId { + final $_column = $_itemColumn('song_id')!; + + final manager = $$SongsTableTableManager( + $_db, + $_db.songs, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_songIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$PlaylistSongsTableFilterComposer + extends Composer<_$MeloDb, $PlaylistSongsTable> { + $$PlaylistSongsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get position => $composableBuilder( + column: $table.position, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get addedAtMs => $composableBuilder( + column: $table.addedAtMs, + builder: (column) => ColumnFilters(column), + ); + + $$PlaylistsTableFilterComposer get playlistId { + final $$PlaylistsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.playlistId, + referencedTable: $db.playlists, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistsTableFilterComposer( + $db: $db, + $table: $db.playlists, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$SongsTableFilterComposer get songId { + final $$SongsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableFilterComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$PlaylistSongsTableOrderingComposer + extends Composer<_$MeloDb, $PlaylistSongsTable> { + $$PlaylistSongsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get position => $composableBuilder( + column: $table.position, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get addedAtMs => $composableBuilder( + column: $table.addedAtMs, + builder: (column) => ColumnOrderings(column), + ); + + $$PlaylistsTableOrderingComposer get playlistId { + final $$PlaylistsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.playlistId, + referencedTable: $db.playlists, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistsTableOrderingComposer( + $db: $db, + $table: $db.playlists, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$SongsTableOrderingComposer get songId { + final $$SongsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableOrderingComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$PlaylistSongsTableAnnotationComposer + extends Composer<_$MeloDb, $PlaylistSongsTable> { + $$PlaylistSongsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get position => + $composableBuilder(column: $table.position, builder: (column) => column); + + GeneratedColumn get addedAtMs => + $composableBuilder(column: $table.addedAtMs, builder: (column) => column); + + $$PlaylistsTableAnnotationComposer get playlistId { + final $$PlaylistsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.playlistId, + referencedTable: $db.playlists, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$PlaylistsTableAnnotationComposer( + $db: $db, + $table: $db.playlists, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } + + $$SongsTableAnnotationComposer get songId { + final $$SongsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableAnnotationComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$PlaylistSongsTableTableManager + extends + RootTableManager< + _$MeloDb, + $PlaylistSongsTable, + PlaylistSong, + $$PlaylistSongsTableFilterComposer, + $$PlaylistSongsTableOrderingComposer, + $$PlaylistSongsTableAnnotationComposer, + $$PlaylistSongsTableCreateCompanionBuilder, + $$PlaylistSongsTableUpdateCompanionBuilder, + (PlaylistSong, $$PlaylistSongsTableReferences), + PlaylistSong, + PrefetchHooks Function({bool playlistId, bool songId}) + > { + $$PlaylistSongsTableTableManager(_$MeloDb db, $PlaylistSongsTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$PlaylistSongsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$PlaylistSongsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$PlaylistSongsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value playlistId = const Value.absent(), + Value songId = const Value.absent(), + Value position = const Value.absent(), + Value addedAtMs = const Value.absent(), + Value rowid = const Value.absent(), + }) => PlaylistSongsCompanion( + playlistId: playlistId, + songId: songId, + position: position, + addedAtMs: addedAtMs, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String playlistId, + required String songId, + required int position, + required int addedAtMs, + Value rowid = const Value.absent(), + }) => PlaylistSongsCompanion.insert( + playlistId: playlistId, + songId: songId, + position: position, + addedAtMs: addedAtMs, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$PlaylistSongsTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({playlistId = false, songId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (playlistId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.playlistId, + referencedTable: $$PlaylistSongsTableReferences + ._playlistIdTable(db), + referencedColumn: $$PlaylistSongsTableReferences + ._playlistIdTable(db) + .id, + ) + as T; + } + if (songId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.songId, + referencedTable: $$PlaylistSongsTableReferences + ._songIdTable(db), + referencedColumn: $$PlaylistSongsTableReferences + ._songIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$PlaylistSongsTableProcessedTableManager = + ProcessedTableManager< + _$MeloDb, + $PlaylistSongsTable, + PlaylistSong, + $$PlaylistSongsTableFilterComposer, + $$PlaylistSongsTableOrderingComposer, + $$PlaylistSongsTableAnnotationComposer, + $$PlaylistSongsTableCreateCompanionBuilder, + $$PlaylistSongsTableUpdateCompanionBuilder, + (PlaylistSong, $$PlaylistSongsTableReferences), + PlaylistSong, + PrefetchHooks Function({bool playlistId, bool songId}) + >; +typedef $$FavoritesTableCreateCompanionBuilder = + FavoritesCompanion Function({ + required String songId, + required int createdAtMs, + Value rowid, + }); +typedef $$FavoritesTableUpdateCompanionBuilder = + FavoritesCompanion Function({ + Value songId, + Value createdAtMs, + Value rowid, + }); + +final class $$FavoritesTableReferences + extends BaseReferences<_$MeloDb, $FavoritesTable, Favorite> { + $$FavoritesTableReferences(super.$_db, super.$_table, super.$_typedResult); + + static $SongsTable _songIdTable(_$MeloDb db) => + db.songs.createAlias('favorites__song_id__songs__id'); + + $$SongsTableProcessedTableManager get songId { + final $_column = $_itemColumn('song_id')!; + + final manager = $$SongsTableTableManager( + $_db, + $_db.songs, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_songIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$FavoritesTableFilterComposer + extends Composer<_$MeloDb, $FavoritesTable> { + $$FavoritesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get createdAtMs => $composableBuilder( + column: $table.createdAtMs, + builder: (column) => ColumnFilters(column), + ); + + $$SongsTableFilterComposer get songId { + final $$SongsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableFilterComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$FavoritesTableOrderingComposer + extends Composer<_$MeloDb, $FavoritesTable> { + $$FavoritesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get createdAtMs => $composableBuilder( + column: $table.createdAtMs, + builder: (column) => ColumnOrderings(column), + ); + + $$SongsTableOrderingComposer get songId { + final $$SongsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableOrderingComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$FavoritesTableAnnotationComposer + extends Composer<_$MeloDb, $FavoritesTable> { + $$FavoritesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get createdAtMs => $composableBuilder( + column: $table.createdAtMs, + builder: (column) => column, + ); + + $$SongsTableAnnotationComposer get songId { + final $$SongsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableAnnotationComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$FavoritesTableTableManager + extends + RootTableManager< + _$MeloDb, + $FavoritesTable, + Favorite, + $$FavoritesTableFilterComposer, + $$FavoritesTableOrderingComposer, + $$FavoritesTableAnnotationComposer, + $$FavoritesTableCreateCompanionBuilder, + $$FavoritesTableUpdateCompanionBuilder, + (Favorite, $$FavoritesTableReferences), + Favorite, + PrefetchHooks Function({bool songId}) + > { + $$FavoritesTableTableManager(_$MeloDb db, $FavoritesTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$FavoritesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$FavoritesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$FavoritesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value songId = const Value.absent(), + Value createdAtMs = const Value.absent(), + Value rowid = const Value.absent(), + }) => FavoritesCompanion( + songId: songId, + createdAtMs: createdAtMs, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String songId, + required int createdAtMs, + Value rowid = const Value.absent(), + }) => FavoritesCompanion.insert( + songId: songId, + createdAtMs: createdAtMs, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$FavoritesTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({songId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (songId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.songId, + referencedTable: $$FavoritesTableReferences + ._songIdTable(db), + referencedColumn: $$FavoritesTableReferences + ._songIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$FavoritesTableProcessedTableManager = + ProcessedTableManager< + _$MeloDb, + $FavoritesTable, + Favorite, + $$FavoritesTableFilterComposer, + $$FavoritesTableOrderingComposer, + $$FavoritesTableAnnotationComposer, + $$FavoritesTableCreateCompanionBuilder, + $$FavoritesTableUpdateCompanionBuilder, + (Favorite, $$FavoritesTableReferences), + Favorite, + PrefetchHooks Function({bool songId}) + >; +typedef $$PlaybackHistoryTableCreateCompanionBuilder = + PlaybackHistoryCompanion Function({ + required String songId, + required int positionMs, + required int playedAtMs, + Value rowid, + }); +typedef $$PlaybackHistoryTableUpdateCompanionBuilder = + PlaybackHistoryCompanion Function({ + Value songId, + Value positionMs, + Value playedAtMs, + Value rowid, + }); + +final class $$PlaybackHistoryTableReferences + extends + BaseReferences<_$MeloDb, $PlaybackHistoryTable, PlaybackHistoryData> { + $$PlaybackHistoryTableReferences( + super.$_db, + super.$_table, + super.$_typedResult, + ); + + static $SongsTable _songIdTable(_$MeloDb db) => + db.songs.createAlias('playback_history__song_id__songs__id'); + + $$SongsTableProcessedTableManager get songId { + final $_column = $_itemColumn('song_id')!; + + final manager = $$SongsTableTableManager( + $_db, + $_db.songs, + ).filter((f) => f.id.sqlEquals($_column)); + final item = $_typedResult.readTableOrNull(_songIdTable($_db)); + if (item == null) return manager; + return ProcessedTableManager( + manager.$state.copyWith(prefetchedData: [item]), + ); + } +} + +class $$PlaybackHistoryTableFilterComposer + extends Composer<_$MeloDb, $PlaybackHistoryTable> { + $$PlaybackHistoryTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get positionMs => $composableBuilder( + column: $table.positionMs, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get playedAtMs => $composableBuilder( + column: $table.playedAtMs, + builder: (column) => ColumnFilters(column), + ); + + $$SongsTableFilterComposer get songId { + final $$SongsTableFilterComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableFilterComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$PlaybackHistoryTableOrderingComposer + extends Composer<_$MeloDb, $PlaybackHistoryTable> { + $$PlaybackHistoryTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get positionMs => $composableBuilder( + column: $table.positionMs, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get playedAtMs => $composableBuilder( + column: $table.playedAtMs, + builder: (column) => ColumnOrderings(column), + ); + + $$SongsTableOrderingComposer get songId { + final $$SongsTableOrderingComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableOrderingComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$PlaybackHistoryTableAnnotationComposer + extends Composer<_$MeloDb, $PlaybackHistoryTable> { + $$PlaybackHistoryTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get positionMs => $composableBuilder( + column: $table.positionMs, + builder: (column) => column, + ); + + GeneratedColumn get playedAtMs => $composableBuilder( + column: $table.playedAtMs, + builder: (column) => column, + ); + + $$SongsTableAnnotationComposer get songId { + final $$SongsTableAnnotationComposer composer = $composerBuilder( + composer: this, + getCurrentColumn: (t) => t.songId, + referencedTable: $db.songs, + getReferencedColumn: (t) => t.id, + builder: + ( + joinBuilder, { + $addJoinBuilderToRootComposer, + $removeJoinBuilderFromRootComposer, + }) => $$SongsTableAnnotationComposer( + $db: $db, + $table: $db.songs, + $addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer, + joinBuilder: joinBuilder, + $removeJoinBuilderFromRootComposer: + $removeJoinBuilderFromRootComposer, + ), + ); + return composer; + } +} + +class $$PlaybackHistoryTableTableManager + extends + RootTableManager< + _$MeloDb, + $PlaybackHistoryTable, + PlaybackHistoryData, + $$PlaybackHistoryTableFilterComposer, + $$PlaybackHistoryTableOrderingComposer, + $$PlaybackHistoryTableAnnotationComposer, + $$PlaybackHistoryTableCreateCompanionBuilder, + $$PlaybackHistoryTableUpdateCompanionBuilder, + (PlaybackHistoryData, $$PlaybackHistoryTableReferences), + PlaybackHistoryData, + PrefetchHooks Function({bool songId}) + > { + $$PlaybackHistoryTableTableManager(_$MeloDb db, $PlaybackHistoryTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$PlaybackHistoryTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$PlaybackHistoryTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$PlaybackHistoryTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value songId = const Value.absent(), + Value positionMs = const Value.absent(), + Value playedAtMs = const Value.absent(), + Value rowid = const Value.absent(), + }) => PlaybackHistoryCompanion( + songId: songId, + positionMs: positionMs, + playedAtMs: playedAtMs, + rowid: rowid, + ), + createCompanionCallback: + ({ + required String songId, + required int positionMs, + required int playedAtMs, + Value rowid = const Value.absent(), + }) => PlaybackHistoryCompanion.insert( + songId: songId, + positionMs: positionMs, + playedAtMs: playedAtMs, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map( + (e) => ( + e.readTable(table), + $$PlaybackHistoryTableReferences(db, table, e), + ), + ) + .toList(), + prefetchHooksCallback: ({songId = false}) { + return PrefetchHooks( + db: db, + explicitlyWatchedTables: [], + addJoins: + < + T extends TableManagerState< + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic, + dynamic + > + >(state) { + if (songId) { + state = + state.withJoin( + currentTable: table, + currentColumn: table.songId, + referencedTable: + $$PlaybackHistoryTableReferences + ._songIdTable(db), + referencedColumn: + $$PlaybackHistoryTableReferences + ._songIdTable(db) + .id, + ) + as T; + } + + return state; + }, + getPrefetchedDataCallback: (items) async { + return []; + }, + ); + }, + ), + ); +} + +typedef $$PlaybackHistoryTableProcessedTableManager = + ProcessedTableManager< + _$MeloDb, + $PlaybackHistoryTable, + PlaybackHistoryData, + $$PlaybackHistoryTableFilterComposer, + $$PlaybackHistoryTableOrderingComposer, + $$PlaybackHistoryTableAnnotationComposer, + $$PlaybackHistoryTableCreateCompanionBuilder, + $$PlaybackHistoryTableUpdateCompanionBuilder, + (PlaybackHistoryData, $$PlaybackHistoryTableReferences), + PlaybackHistoryData, + PrefetchHooks Function({bool songId}) + >; class $MeloDbManager { final _$MeloDb _db; @@ -1421,4 +4254,12 @@ class $MeloDbManager { $$SongsTableTableManager(_db, _db.songs); $$FoldersTableTableManager get folders => $$FoldersTableTableManager(_db, _db.folders); + $$PlaylistsTableTableManager get playlists => + $$PlaylistsTableTableManager(_db, _db.playlists); + $$PlaylistSongsTableTableManager get playlistSongs => + $$PlaylistSongsTableTableManager(_db, _db.playlistSongs); + $$FavoritesTableTableManager get favorites => + $$FavoritesTableTableManager(_db, _db.favorites); + $$PlaybackHistoryTableTableManager get playbackHistory => + $$PlaybackHistoryTableTableManager(_db, _db.playbackHistory); } diff --git a/test/library/database_playlists_test.dart b/test/library/database_playlists_test.dart new file mode 100644 index 0000000..b9d010d --- /dev/null +++ b/test/library/database_playlists_test.dart @@ -0,0 +1,110 @@ +import 'package:drift/native.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:melo/library/database.dart'; + +void main() { + late MeloDb db; + + setUp(() { + db = MeloDb(NativeDatabase.memory()); + }); + + tearDown(() async { + await db.close(); + }); + + group('Playlists', () { + test('createPlaylist inserts and watchPlaylists emits it', () async { + await db.createPlaylist('Workout'); + final playlists = await db.watchPlaylists().first; + expect(playlists.length, 1); + expect(playlists.first.name, 'Workout'); + }); + + test('deletePlaylist removes it', () async { + final id = await db.createPlaylist('Temp'); + await db.deletePlaylist(id); + final playlists = await db.watchPlaylists().first; + expect(playlists, isEmpty); + }); + }); + + group('PlaylistSongs', () { + test('addSongToPlaylist + watchPlaylistSongs returns song in order', () async { + final playlistId = await db.createPlaylist('My List'); + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-1', + path: '/a.mp3', + title: 'Song A', + dateAddedMs: 0, + updatedAtMs: 0, + )); + + await db.addSongToPlaylist(playlistId, 'song-1', 0); + final songs = await db.watchPlaylistSongs(playlistId).first; + expect(songs.length, 1); + expect(songs.first.title, 'Song A'); + }); + + test('removeSongFromPlaylist removes it', () async { + final playlistId = await db.createPlaylist('My List'); + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-1', + path: '/a.mp3', + title: 'Song A', + dateAddedMs: 0, + updatedAtMs: 0, + )); + await db.addSongToPlaylist(playlistId, 'song-1', 0); + await db.removeSongFromPlaylist(playlistId, 'song-1'); + final songs = await db.watchPlaylistSongs(playlistId).first; + expect(songs, isEmpty); + }); + }); + + group('Favorites', () { + test('toggleFavorite marks then unmarks a song', () async { + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-1', + path: '/a.mp3', + title: 'Song A', + dateAddedMs: 0, + updatedAtMs: 0, + )); + + await db.toggleFavorite('song-1'); + expect(await db.watchIsFavorite('song-1').first, true); + + await db.toggleFavorite('song-1'); + expect(await db.watchIsFavorite('song-1').first, false); + }); + + test('watchFavorites returns favorited songs only', () async { + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-1', path: '/a.mp3', title: 'Fav', dateAddedMs: 0, updatedAtMs: 0, + )); + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-2', path: '/b.mp3', title: 'NotFav', dateAddedMs: 0, updatedAtMs: 0, + )); + await db.toggleFavorite('song-1'); + + final favs = await db.watchFavorites().first; + expect(favs.length, 1); + expect(favs.first.title, 'Fav'); + }); + }); + + group('PlaybackHistory', () { + test('recordPlayback + lastPosition roundtrip', () async { + await db.into(db.songs).insert(SongsCompanion.insert( + id: 'song-1', path: '/a.mp3', title: 'A', dateAddedMs: 0, updatedAtMs: 0, + )); + await db.recordPlayback('song-1', 45000); + expect(await db.lastPosition('song-1'), 45000); + }); + + test('lastPosition returns null when never played', () async { + expect(await db.lastPosition('unknown'), isNull); + }); + }); +}