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
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(), |
|
]) |
|
}) |
|
} |