You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

211 lines
7.7 KiB

import Knex from "knex";
import { Track, TrackRefs, Id, Name, StoreLinks, Album, AlbumRefs, Artist, ArtistRefs, Tag, TagParentId, isTrackRefs, isAlbumRefs, DBImportResponse, IDMappings } from "../../client/src/api/api";
import * as api from '../../client/src/api/api';
import asJson from "../lib/asJson";
import { createArtist } from "./Artist";
import { createTag } from "./Tag";
import { createAlbum } from "./Album";
import { createTrack } from "./Track";
let _ = require('lodash');
export async function exportDB(userId: number, knex: Knex): Promise<api.DBDataFormat> {
// First, retrieve all the objects without taking linking tables into account.
// Fetch the links separately.
let tracksPromise: Promise<(Track & Id & Name & StoreLinks & TrackRefs)[]> =
knex.select('id', 'name', 'storeLinks', 'album')
.from('tracks')
.where({ 'user': userId })
.then((ts: any[]) => ts.map((t: any) => {
return {
mbApi_typename: 'track',
name: t.name,
id: t.id,
storeLinks: asJson(t.storeLinks),
albumId: t.album,
artistIds: [],
tagIds: [],
}
}));
let albumsPromise: Promise<(Album & Id & Name & StoreLinks & AlbumRefs)[]> =
knex.select('name', 'storeLinks', 'id')
.from('albums')
.where({ 'user': userId })
.then((ts: any[]) => ts.map((t: any) => {
return {
mbApi_typename: 'album',
id: t.id,
name: t.name,
storeLinks: asJson(t.storeLinks),
artistIds: [],
tagIds: [],
trackIds: [],
}
}));
let artistsPromise: Promise<(Artist & Id & Name & ArtistRefs & StoreLinks)[]> =
knex.select('name', 'storeLinks', 'id')
.from('artists')
.where({ 'user': userId })
.then((ts: any[]) => ts.map((t: any) => {
return {
mbApi_typename: 'artist',
id: t.id,
name: t.name,
storeLinks: asJson(t.storeLinks),
albumIds: [],
tagIds: [],
trackIds: [],
}
}));
let tagsPromise: Promise<(Tag & Id & Name & TagParentId)[]> =
knex.select('name', 'parentId', 'id')
.from('tags')
.where({ 'user': userId })
.then((ts: any[]) => ts.map((t: any) => {
return {
mbApi_typename: 'tag',
id: t.id,
name: t.name,
parentId: t.parentId,
}
}));
let tracksArtistsPromise: Promise<[number, number][]> =
knex.select('trackId', 'artistId')
.from('tracks_artists')
.then((rs: any) => rs.map((r: any) => [r.trackId, r.artistId]));
let tracksTagsPromise: Promise<[number, number][]> =
knex.select('trackId', 'tagId')
.from('tracks_tags')
.then((rs: any) => rs.map((r: any) => [r.trackId, r.tagId]));
let artistsTagsPromise: Promise<[number, number][]> =
knex.select('artistId', 'tagId')
.from('artists_tags')
.then((rs: any) => rs.map((r: any) => [r.artistId, r.tagId]));
let albumsTagsPromise: Promise<[number, number][]> =
knex.select('albumId', 'tagId')
.from('albums_tags')
.then((rs: any) => rs.map((r: any) => [r.albumId, r.tagId]));
let artistsAlbumsPromise: Promise<[number, number][]> =
knex.select('albumId', 'artistId')
.from('artists_albums')
.then((rs: any) => rs.map((r: any) => [r.albumId, r.artistId]));
let [
tracks,
albums,
artists,
tags,
tracksArtists,
tracksTags,
artistsTags,
albumsTags,
artistsAlbums,
] = await Promise.all([
tracksPromise,
albumsPromise,
artistsPromise,
tagsPromise,
tracksArtistsPromise,
tracksTagsPromise,
artistsTagsPromise,
albumsTagsPromise,
artistsAlbumsPromise,
]);
// Now store the links inside the resource objects.
tracksArtists.forEach((v: [number, number]) => {
let [trackId, artistId] = v;
tracks.find((t: (Track & Id & TrackRefs)) => t.id === trackId)?.artistIds.push(artistId);
artists.find((a: (Artist & Id & ArtistRefs)) => a.id === artistId)?.trackIds.push(trackId);
})
tracks.forEach((t: (Track & Id & TrackRefs)) => {
albums.find((a: (Album & Id & AlbumRefs)) => t.albumId && a.id === t.albumId)?.trackIds.push(t.id);
})
tracksTags.forEach((v: [number, number]) => {
let [trackId, tagId] = v;
tracks.find((t: (Track & Id & TrackRefs)) => t.id === trackId)?.tagIds.push(tagId);
})
artistsTags.forEach((v: [number, number]) => {
let [artistId, tagId] = v;
artists.find((t: (Artist & Id & ArtistRefs)) => t.id === artistId)?.tagIds.push(tagId);
})
albumsTags.forEach((v: [number, number]) => {
let [albumId, tagId] = v;
albums.find((t: (Album & Id & AlbumRefs)) => t.id === albumId)?.tagIds.push(tagId);
})
artistsAlbums.forEach((v: [number, number]) => {
let [albumId, artistId] = v;
artists.find((t: (Artist & Id & ArtistRefs)) => t.id === artistId)?.albumIds.push(albumId);
albums.find((t: (Album & Id & AlbumRefs)) => t.id === albumId)?.artistIds.push(artistId);
})
return {
tracks: tracks,
albums: albums,
artists: artists,
tags: tags,
}
}
export async function importDB(userId: number, db: api.DBDataFormat, knex: Knex): Promise<DBImportResponse> {
// Store the ID mappings in this record.
let maps: IDMappings = {
tracks: {},
artists: {},
albums: {},
tags: {},
}
// Insert items one by one, remapping the IDs as we go.
for(const tag of db.tags) {
let _tag = {
..._.omit(tag, 'id'),
parentId: tag.parentId ? maps.tags[tag.parentId] : null,
}
maps.tags[tag.id] = await createTag(userId, _tag, knex);
}
for(const artist of db.artists) {
maps.artists[artist.id] = await createArtist(userId, {
..._.omit(artist, 'id'),
tagIds: artist.tagIds.map((id: number) => maps.tags[id]),
trackIds: [],
albumIds: [],
}, knex);
}
for(const album of db.albums) {
maps.albums[album.id] = await createAlbum(userId, {
..._.omit(album, 'id'),
tagIds: album.tagIds.map((id: number) => maps.tags[id]),
artistIds: album.artistIds.map((id: number) => maps.artists[id]),
trackIds: [],
}, knex);
}
for(const track of db.tracks) {
maps.tracks[track.id] = await createTrack(userId, {
..._.omit(track, 'id'),
tagIds: track.tagIds.map((id: number) => maps.tags[id]),
artistIds: track.artistIds.map((id: number) => maps.artists[id]),
albumId: track.albumId ? maps.albums[track.albumId] : null,
}, knex);
}
return maps;
}
export async function wipeDB(userId: number, knex: Knex) {
return await knex.transaction(async (trx) => {
await Promise.all([
trx('tracks').where({ 'user': userId }).del(),
trx('artists').where({ 'user': userId }).del(),
trx('albums').where({ 'user': userId }).del(),
trx('tags').where({ 'user': userId }).del(),
])
})
}