diff --git a/src/main/java/com/blck/MusicReleaseTracker/Core/ValueStore.java b/src/main/java/com/blck/MusicReleaseTracker/Core/ValueStore.java index 1bcd0ab..b49e48d 100644 --- a/src/main/java/com/blck/MusicReleaseTracker/Core/ValueStore.java +++ b/src/main/java/com/blck/MusicReleaseTracker/Core/ValueStore.java @@ -24,7 +24,8 @@ public class ValueStore { private String appDataPath; - private String DBpath; + private Path DBpath; + private Path DBpathTemplate; private Path configPath; private Path errorLogsPath; private String scrapeDate; @@ -55,11 +56,20 @@ public void setAppDataPath(String appDataPath) { this.appDataPath = appDataPath; } - public void setDBpath(String DBpath) { + public Path getDBpath() { + return DBpath; + } + + public void setDBpath(Path DBpath) { this.DBpath = DBpath; } - public String getDBpathString() { - return DBpath.toString(); + + public Path getDBpathTemplate() { + return DBpathTemplate; + } + + public void setDBpathTemplate(Path DBpathTemplate) { + this.DBpathTemplate = DBpathTemplate; } public Path getConfigPath() { diff --git a/src/main/java/com/blck/MusicReleaseTracker/DB/DBqueries.java b/src/main/java/com/blck/MusicReleaseTracker/DB/DBqueries.java index da955c2..79d130d 100644 --- a/src/main/java/com/blck/MusicReleaseTracker/DB/DBqueries.java +++ b/src/main/java/com/blck/MusicReleaseTracker/DB/DBqueries.java @@ -48,7 +48,7 @@ public DBqueries(ValueStore valueStore, ErrorLogging errorLogging, SettingsIO se public List getArtistList() { List dataList = new ArrayList<>(); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT artist FROM artists ORDER BY artist LIMIT 500"); while (rs.next()) @@ -63,7 +63,7 @@ public List getArtistList() { public List loadTable(TablesEnum source, String name) { List tableContent = new ArrayList<>(); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement( "SELECT song, date FROM " + source + " WHERE artist = ? ORDER BY date DESC, song LIMIT 50"); pstmt.setString(1, name); @@ -92,7 +92,7 @@ public List loadCombviewTable() { public List readCombviewSingles() { List singles = new ArrayList<>(); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery( "SELECT song, artist, date FROM combview WHERE album IS NULL ORDER BY date DESC, song LIMIT 1000" @@ -110,7 +110,7 @@ public List readCombviewSingles() { public List readCombviewAlbums() { List albums = new ArrayList<>(); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { Statement stmt = conn.createStatement(); ResultSet rs1 = stmt.executeQuery( "SELECT DISTINCT album FROM combview WHERE album IS NOT NULL ORDER BY date LIMIT 300" @@ -137,7 +137,7 @@ public List readCombviewAlbums() { } public void insertIntoArtistList(String name) { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement( "INSERT INTO artists (artist) values(?)"); pstmt.setString(1, name); @@ -154,7 +154,7 @@ public void updateArtistSourceID(String name, TablesEnum source, String newID) { sql = "UPDATE artists SET url" + source + " = NULL WHERE artist = ?"; else sql = "UPDATE artists SET url" + source + " = ? WHERE artist = ?"; - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement(sql); if (newID == null) { pstmt.setString(1, name); @@ -170,7 +170,7 @@ public void updateArtistSourceID(String name, TablesEnum source, String newID) { } public Optional getArtistSourceID(String name, TablesEnum source) { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement( "SELECT url" + source + " FROM artists WHERE artist = ?"); pstmt.setString(1, name); @@ -182,7 +182,7 @@ public Optional getArtistSourceID(String name, TablesEnum source) { } public void clearArtistDataFrom(String name, TablesEnum table) { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement( "DELETE FROM " + table + " WHERE artist = ?"); pstmt.setString(1, name); @@ -195,7 +195,7 @@ public void clearArtistDataFrom(String name, TablesEnum table) { public void removeArtistFromAllTables(String name) { for (TablesEnum table : TablesEnum.values()) clearArtistDataFrom(name, table); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement("DELETE FROM artists WHERE artist = ?"); pstmt.setString(1, name); pstmt.executeUpdate(); @@ -205,7 +205,7 @@ public void removeArtistFromAllTables(String name) { } public void truncateAllTables() { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { Statement stmt = conn.createStatement(); for (TablesEnum table : TablesEnum.values()) stmt.addBatch("DELETE FROM " + table); @@ -219,7 +219,7 @@ public void truncateAllTables() { } public void truncateCombview() { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { Statement stmt = conn.createStatement(); stmt.executeUpdate("DELETE FROM combview"); stmt.close(); @@ -231,7 +231,7 @@ public void truncateCombview() { public ArrayList getSourceTablesDataForCombview() { var filterWords = settingsIO.getFilterValues(); ArrayList songObjectList = new ArrayList<>(); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { for (TablesEnum table : TablesEnum.values()) { if (table == TablesEnum.combview) continue; @@ -280,7 +280,7 @@ private String getRealFilterName(String settingName) { public LinkedList getAllScrapers() { // creating a list of scraper objects: one scraper holds one URL LinkedList scrapers = new LinkedList<>(); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement( "SELECT artist FROM artists LIMIT 500"); ResultSet artistResults = pstmt.executeQuery(); @@ -318,7 +318,7 @@ public void batchInsertSongs(List songList, TablesEnum source, int limit) throw new NullPointerException("null table"); if (source == TablesEnum.combview) throw new RuntimeException("use dedicated combview insert method"); - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { String sql; if (songList.getFirst().getType().isPresent()) sql = "insert into " + source + "(song, artist, date, type) values(?, ?, ?, ?)"; @@ -347,7 +347,7 @@ public void batchInsertSongs(List songList, TablesEnum source, int limit) } public void batchInsertCombview(List songList) { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement( "insert into combview (song, artist, date, album) values(?, ?, ?, ?)" ); @@ -372,7 +372,7 @@ public void batchInsertCombview(List songList) { } public void vacuum() { - try (Connection conn = DriverManager.getConnection(store.getDBpathString())) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + store.getDBpath())) { PreparedStatement pstmt = conn.prepareStatement("VACUUM;"); pstmt.execute(); pstmt.close(); diff --git a/src/main/java/com/blck/MusicReleaseTracker/DB/MigrateDB.java b/src/main/java/com/blck/MusicReleaseTracker/DB/MigrateDB.java index 74fa2ba..2bfcd35 100644 --- a/src/main/java/com/blck/MusicReleaseTracker/DB/MigrateDB.java +++ b/src/main/java/com/blck/MusicReleaseTracker/DB/MigrateDB.java @@ -20,9 +20,12 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class MigrateDB { @@ -36,67 +39,62 @@ public MigrateDB(ValueStore valueStore, ErrorLogging errorLogging) { this.log = errorLogging; } - public void createDBandSourceTables(String path) { + public void createDBandTables(Path path) { // note: generate by string templates after preview - try (Connection conn = DriverManager.getConnection(path)) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { Statement stmt = conn.createStatement(); - String sql = """ + + stmt.addBatch(""" + CREATE TABLE IF NOT EXISTS artists ( + artist text PRIMARY KEY, + urlmusicbrainz text, + urlbeatport text, + urljunodownload text, + urlyoutube text + ); + """); + + stmt.addBatch(""" + CREATE TABLE IF NOT EXISTS combview ( + song text NOT NULL, + artist text NOT NULL, + date text NOT NULL, + album text + ); + """); + + stmt.addBatch(""" CREATE TABLE IF NOT EXISTS musicbrainz ( song text NOT NULL, artist text NOT NULL, date text NOT NULL ); - """; - stmt.addBatch(sql); + """); - sql = """ + stmt.addBatch(""" CREATE TABLE IF NOT EXISTS beatport ( song text NOT NULL, artist text NOT NULL, date text NOT NULL, type text NOT NULL ); - """; - stmt.addBatch(sql); + """); - sql = """ + stmt.addBatch(""" CREATE TABLE IF NOT EXISTS junodownload ( song text NOT NULL, artist text NOT NULL, date text NOT NULL ); - """; - stmt.addBatch(sql); + """); - sql = """ + stmt.addBatch(""" CREATE TABLE IF NOT EXISTS youtube ( song text NOT NULL, artist text NOT NULL, date text NOT NULL ); - """; - stmt.addBatch(sql); - - sql = """ - CREATE TABLE IF NOT EXISTS artists ( - artist text PRIMARY KEY, - urlmusicbrainz text, - urlbeatport text, - urljunodownload text, - urlyoutube text - ); - """; - stmt.addBatch(sql); - - sql = """ - CREATE TABLE IF NOT EXISTS combview ( - song text NOT NULL, - artist text NOT NULL, - date text NOT NULL, - album text - ); - """; - stmt.addBatch(sql); + """); conn.setAutoCommit(false); stmt.executeBatch(); @@ -107,70 +105,46 @@ CREATE TABLE IF NOT EXISTS combview ( } } - public void migrateDB() { - // on start: create DB if not exist, check DB structure, if different -> create new from template and refill with all data possible - final String templateFilePath = store.getAppDataPath() + "DBTemplate.db"; - final String DBtemplatePath = "jdbc:sqlite:" + templateFilePath; - final String DBfilePath = store.getAppDataPath() + "musicdata.db"; - - File templateFile = new File(templateFilePath); - templateFile.delete(); - createDBandSourceTables(store.getDBpathString()); - createDBandSourceTables(DBtemplatePath); - - // if different structure, fill template artist table data from musicdata and then rename/delete, make new template - // this only preserves "artists" data and assumes that the insertion logic will be adjusted after any changes - // made to the "artists" table: change in order of columns, adding/removing a column or changing a column's name - Map> DBMap = getDBStructure(store.getDBpathString()); - Map> DBtemplateMap = getDBStructure(DBtemplatePath); - if (!DBMap.equals(DBtemplateMap)) { - try ( - Connection connDB = DriverManager.getConnection(store.getDBpathString()); - Connection connDBtemplate = DriverManager.getConnection(DBtemplatePath) - ) { - // insert data from musicdata column to template column - String sql = "SELECT * FROM artists LIMIT 1000"; - Statement stmt = connDB.createStatement(); - ResultSet rs = stmt.executeQuery(sql); - - sql = "insert into artists(artist, urlmusicbrainz, urlbeatport, urljunodownload, urlyoutube) values(?, ?, ?, ?, ?)"; - PreparedStatement pstmt = connDBtemplate.prepareStatement(sql); - ArrayList columnList = DBMap.get("artists"); - // cycling table rows - while (rs.next()) { - // construct sql query for every column, add to batch - for (int i = 0; i < columnList.size(); i++) { - String column = columnList.get(i); - pstmt.setString(i + 1, rs.getString(column)); - } - pstmt.addBatch(); - } - connDBtemplate.setAutoCommit(false); - pstmt.executeBatch(); - connDBtemplate.commit(); - connDBtemplate.setAutoCommit(true); - pstmt.close(); - } catch (Exception e) { - log.error(e, ErrorLogging.Severity.SEVERE, "error updating DB file"); - } - try { - File oldFile = new File(DBfilePath); - File newFile = new File(templateFilePath); - // delete old musicdata - oldFile.delete(); - // rename template to musicdata - newFile.renameTo(oldFile); - } catch (Exception e) { - log.error(e, ErrorLogging.Severity.SEVERE, "error renaming/deleting DB files"); + public void migrateDB(Path DB, Path DBtemplate) { + try { + Files.deleteIfExists(DBtemplate); + createDBandTables(DB); + createDBandTables(DBtemplate); + + var DBstructure = getDBStructure(DB); + if (!DBstructure.equals(getDBStructure(DBtemplate))) { + copyArtistsData(DB, DBtemplate); + Files.delete(DB); + new File(String.valueOf(DBtemplate)) + .renameTo(DB.toFile()); } + } catch (Exception e) { + log.error(e, ErrorLogging.Severity.SEVERE, "failed to migrate DB"); } } - public Map> getDBStructure(String path) { - // returns a structure of tables and their columns - HashMap> tableMap = new HashMap<>(); + public void copyArtistsData(Path sourceDB, Path targetDB) { + var DBcolumns = getDBStructure(sourceDB).get("artists"); + var templateColumns = getDBStructure(targetDB).get("artists"); + List sharedColumns = new ArrayList<>(DBcolumns); + sharedColumns.retainAll(templateColumns); + String shared = String.join(", ", sharedColumns); + + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + sourceDB)) { + Statement stmt = conn.createStatement(); + stmt.execute("ATTACH DATABASE '" + targetDB + "' AS target_db"); + stmt.executeUpdate("INSERT INTO target_db.artists (" + shared + ") SELECT " + shared + " FROM artists"); + } catch (SQLException e) { + e.printStackTrace(); + } + } - try (Connection conn = DriverManager.getConnection(path)) { + public Map> getDBStructure(Path path) { + if (Files.notExists(path)) + throw new RuntimeException("file " + path + " does not exist"); + + HashMap> tableMap = new HashMap<>(); + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { String sql = "SELECT name FROM sqlite_master WHERE type='table'"; Statement stmt = conn.createStatement(); ResultSet rsTables = stmt.executeQuery(sql); @@ -198,7 +172,7 @@ public Map> getDBStructure(String path) { public void resetDB() { File musicdata = new File(store.getAppDataPath() + "musicdata.db"); musicdata.delete(); - createDBandSourceTables(store.getDBpathString()); + createDBandTables(store.getDBpath()); } } diff --git a/src/main/java/com/blck/MusicReleaseTracker/Main.java b/src/main/java/com/blck/MusicReleaseTracker/Main.java index db3187e..4c73dc5 100644 --- a/src/main/java/com/blck/MusicReleaseTracker/Main.java +++ b/src/main/java/com/blck/MusicReleaseTracker/Main.java @@ -70,7 +70,6 @@ public class StartupRunner implements CommandLineRunner { // on startup of springboot server @Override public void run(String... args) { - System.out.println("----------LOCAL SERVER STARTED----------"); System.out.println(""" __ __ ____ _____ | \\/ | _ \\_ _| @@ -80,7 +79,7 @@ public void run(String... args) { """); store.setAppVersion(appConfig.version()); startSetup.createPathsAndDirs(); - manageDB.migrateDB(); + manageDB.migrateDB(store.getDBpath(), store.getDBpathTemplate()); settingsIO.updateSettings(); store.setBackendReady(); } diff --git a/src/main/java/com/blck/MusicReleaseTracker/StartSetup.java b/src/main/java/com/blck/MusicReleaseTracker/StartSetup.java index f7d8f90..52345a6 100644 --- a/src/main/java/com/blck/MusicReleaseTracker/StartSetup.java +++ b/src/main/java/com/blck/MusicReleaseTracker/StartSetup.java @@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.File; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; @@ -51,14 +50,20 @@ else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) throw new UnsupportedOperationException("unsupported OS"); String appDataPath = appData + slash + "MusicReleaseTracker" + slash; - String DBpath = "jdbc:sqlite:" + Paths.get(appDataPath, "musicdata.db"); - Path configPath = Paths.get(appDataPath, "MRTsettings.json"); - Path errorLogsPath = Paths.get(appDataPath, "errorlogs.txt"); store.setAppDataPath(appDataPath); - store.setConfigPath(configPath); - store.setDBpath(DBpath); - store.setErrorLogsPath(errorLogsPath); + store.setConfigPath( + Paths.get(appDataPath, "MRTsettings.json") + ); + store.setDBpath( + Paths.get(appDataPath, "musicdata.db") + ); + store.setDBpathTemplate( + Paths.get(appDataPath, "DBTemplate.db") + ); + store.setErrorLogsPath( + Paths.get(appDataPath, "errorlogs.txt") + ); } public void createDirs() { diff --git a/src/test/java/com/blck/MusicReleaseTracker/DBqueriesTest.java b/src/test/java/com/blck/MusicReleaseTracker/DB/DBqueriesTest.java similarity index 85% rename from src/test/java/com/blck/MusicReleaseTracker/DBqueriesTest.java rename to src/test/java/com/blck/MusicReleaseTracker/DB/DBqueriesTest.java index c8fa623..2c17263 100644 --- a/src/test/java/com/blck/MusicReleaseTracker/DBqueriesTest.java +++ b/src/test/java/com/blck/MusicReleaseTracker/DB/DBqueriesTest.java @@ -13,13 +13,11 @@ * along with this program. If not, see . */ -package com.blck.MusicReleaseTracker; +package com.blck.MusicReleaseTracker.DB; import com.blck.MusicReleaseTracker.Core.ErrorLogging; import com.blck.MusicReleaseTracker.Core.TablesEnum; import com.blck.MusicReleaseTracker.Core.ValueStore; -import com.blck.MusicReleaseTracker.DB.DBqueries; -import com.blck.MusicReleaseTracker.DB.MigrateDB; import com.blck.MusicReleaseTracker.DataObjects.Album; import com.blck.MusicReleaseTracker.DataObjects.MediaItem; import com.blck.MusicReleaseTracker.DataObjects.Song; @@ -33,7 +31,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.nio.file.Paths; import java.util.HashMap; import java.util.List; @@ -44,8 +41,6 @@ @ExtendWith(MockitoExtension.class) public class DBqueriesTest { - final static String testDBpath = "jdbc:sqlite:" + Paths.get("src", "test", "testresources", "testdb.db"); - @Mock ValueStore store; @Mock @@ -66,13 +61,13 @@ static void setUpDB() { @AfterAll static void cleanUp() { - HelperDB.redoTestData(); + HelperDB.redoTestData(HelperDB.testDBpath); } @BeforeEach void setUp() { - HelperDB.redoTestData(); - lenient().when(store.getDBpathString()).thenReturn(testDBpath); + HelperDB.redoTestData(HelperDB.testDBpath); + lenient().when(store.getDBpath()).thenReturn(HelperDB.testDBpath); dBqueriesClass = new DBqueries(store, log, settingsIO, migrateDB); songList = List.of( new Song("song1", "artist1", "2022-01-01", "remix"), @@ -84,21 +79,21 @@ void setUp() { void batchInsertIntoSource() { dBqueriesClass.batchInsertSongs(songList, TablesEnum.beatport, 10); - assertEquals(3, HelperDB.getNumEntries("beatport")); + assertEquals(3, HelperDB.getNumEntries(HelperDB.testDBpath, "beatport")); } @Test void batchInsertIntoCombview() { dBqueriesClass.batchInsertCombview(songList); - assertEquals(3, HelperDB.getNumEntries("combview")); + assertEquals(3, HelperDB.getNumEntries(HelperDB.testDBpath, "combview")); } @Test void batchInsertOverLimit() { dBqueriesClass.batchInsertSongs(songList, TablesEnum.beatport, 1); - assertEquals(1, HelperDB.getNumEntries("beatport")); + assertEquals(1, HelperDB.getNumEntries(HelperDB.testDBpath, "beatport")); } @Test @@ -151,7 +146,7 @@ void albumSongsSortedByName() { @Test void mixedSinglesAndAlbumsReadSingles() { - songList.get(0).setAlbumID("album"); + songList.getFirst().setAlbumID("album"); dBqueriesClass.batchInsertCombview(songList); assertEquals(2,dBqueriesClass.readCombviewSingles().size()); @@ -159,7 +154,7 @@ void mixedSinglesAndAlbumsReadSingles() { @Test void mixedSinglesAndAlbumsReadAlbums() { - songList.get(0).setAlbumID("album"); + songList.getFirst().setAlbumID("album"); dBqueriesClass.batchInsertCombview(songList); assertEquals(1,dBqueriesClass.readCombviewAlbums().size()); @@ -167,7 +162,7 @@ void mixedSinglesAndAlbumsReadAlbums() { @Test void getMediaItemsFromCombview() { - songList.get(0).setAlbumID("album"); + songList.getFirst().setAlbumID("album"); dBqueriesClass.batchInsertCombview(songList); List mediaItems = dBqueriesClass.loadCombviewTable(); @@ -300,12 +295,12 @@ void getDataFromSourceTablesForCombviewWithFiltering() { @Test void truncateCombviewTable() { dBqueriesClass.batchInsertCombview(songList); - int entries = HelperDB.getNumEntries("combview", "beatport"); + int entries = HelperDB.getNumEntries(HelperDB.testDBpath, "combview", "beatport"); assertEquals(3, entries); dBqueriesClass.truncateCombview(); - entries = HelperDB.getNumEntries("combview", "beatport"); + entries = HelperDB.getNumEntries(HelperDB.testDBpath, "combview", "beatport"); assertEquals(0, entries); } @@ -317,12 +312,12 @@ void truncateAllScrapeTables() { dBqueriesClass.batchInsertSongs(songList, TablesEnum.musicbrainz, 10); dBqueriesClass.batchInsertSongs(songList, TablesEnum.junodownload, 10); dBqueriesClass.batchInsertCombview(songList); - int entries = HelperDB.getNumEntries("combview", "musicbrainz", "junodownload"); + int entries = HelperDB.getNumEntries(HelperDB.testDBpath, "combview", "musicbrainz", "junodownload"); assertEquals(6, entries); dBqueriesClass.truncateAllTables(); - entries = HelperDB.getNumEntries("combview", "musicbrainz", "junodownload"); + entries = HelperDB.getNumEntries(HelperDB.testDBpath, "combview", "musicbrainz", "junodownload"); assertEquals(0, entries); } @@ -334,27 +329,27 @@ void getScrapersFromIDs() { @Test void clearArtistDataFrom() {; dBqueriesClass.batchInsertSongs(songList, TablesEnum.beatport, 10); - assertEquals(2, HelperDB.getCountOf("beatport", "artist", "artist1")); + assertEquals(2, HelperDB.getCountOf(HelperDB.testDBpath, "beatport", "artist", "artist1")); dBqueriesClass.clearArtistDataFrom("artist1", TablesEnum.beatport); - assertEquals(0, HelperDB.getCountOf("beatport", "artist", "artist1")); - assertEquals(1, HelperDB.getCountOf("beatport", "artist", "artist2")); + assertEquals(0, HelperDB.getCountOf(HelperDB.testDBpath, "beatport", "artist", "artist1")); + assertEquals(1, HelperDB.getCountOf(HelperDB.testDBpath, "beatport", "artist", "artist2")); } @Test void deleteArtistFromAllTables() { dBqueriesClass.batchInsertSongs(songList, TablesEnum.beatport, 10); dBqueriesClass.batchInsertCombview(songList); - assertEquals(1, HelperDB.getCountOf("artists", "artist", "artist1")); - assertEquals(2, HelperDB.getCountOf("beatport", "artist", "artist1")); - assertEquals(2, HelperDB.getCountOf("combview", "artist", "artist1")); + assertEquals(1, HelperDB.getCountOf(HelperDB.testDBpath, "artists", "artist", "artist1")); + assertEquals(2, HelperDB.getCountOf(HelperDB.testDBpath, "beatport", "artist", "artist1")); + assertEquals(2, HelperDB.getCountOf(HelperDB.testDBpath, "combview", "artist", "artist1")); dBqueriesClass.removeArtistFromAllTables("artist1"); - assertEquals(0, HelperDB.getCountOf("artists", "artist", "artist1")); - assertEquals(0, HelperDB.getCountOf("beatport", "artist", "artist1")); - assertEquals(0, HelperDB.getCountOf("combview", "artist", "artist1")); + assertEquals(0, HelperDB.getCountOf(HelperDB.testDBpath, "artists", "artist", "artist1")); + assertEquals(0, HelperDB.getCountOf(HelperDB.testDBpath, "beatport", "artist", "artist1")); + assertEquals(0, HelperDB.getCountOf(HelperDB.testDBpath, "combview", "artist", "artist1")); } diff --git a/src/test/java/com/blck/MusicReleaseTracker/DB/HelperDB.java b/src/test/java/com/blck/MusicReleaseTracker/DB/HelperDB.java new file mode 100644 index 0000000..6f25498 --- /dev/null +++ b/src/test/java/com/blck/MusicReleaseTracker/DB/HelperDB.java @@ -0,0 +1,200 @@ +/* + * MusicReleaseTracker + * Copyright (C) 2023 - 2024 BLCK + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.blck.MusicReleaseTracker.DB; + +import com.blck.MusicReleaseTracker.Core.TablesEnum; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.*; + +public class HelperDB { + + public final static Path testResources = Paths.get("src", "test", "testresources"); + public final static Path testDBpath = Paths.get("src", "test", "testresources", "testdb.db"); + public final static Path testTemplateDBpath = Paths.get("src", "test", "testresources", "DBTemplate.db"); + + public static void deleteDB() { + try { + if (Files.exists(testDBpath)) + Files.delete(testDBpath); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void redoTestDB() { + try { + if (!Files.exists(testResources)) + Files.createDirectory(testResources); + if (Files.exists(testDBpath)) + Files.delete(testDBpath); + } catch (IOException e) { + throw new RuntimeException(e); + } + MigrateDB manageDB = new MigrateDB(null, null); + manageDB.createDBandTables(testDBpath); + } + + public static void redoTestData(Path path) { + clearTables(path); + insertIntoArtists(path, "artist1", "artist2", "artist3"); + } + + public static int getCountOf(Path path, String table, String col, String name) { + int count = 0; + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { + String sql = "SELECT COUNT(*) FROM " + table + " WHERE " + col + " = ?"; + PreparedStatement pstmt = conn.prepareStatement(sql); + pstmt.setString(1, name); + count = pstmt.executeQuery().getInt(1); + } catch (SQLException e) { + throw new RuntimeException(e); + } + return count; + } + + public static int getNumEntries(Path path, String... tables) { + if (tables.length == 0) + throw new RuntimeException("no tables specified"); + int count = 0; + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { + for (String table : tables) { + String sql = "SELECT COUNT(*) FROM " + table; + Statement statement = conn.createStatement(); + count += statement.executeQuery(sql).getInt(1); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + return count; + } + + public static boolean isArtistsColumnNotEmpty(Path path, String column) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { + Statement stmt = conn.createStatement(); + ResultSet resultSet = stmt.executeQuery( + "SELECT 1 FROM artists WHERE " + column + " IS NOT NULL LIMIT 1"); + return resultSet.next(); + } catch (SQLException e) { + throw new RuntimeException("Error checking if column contains data", e); + } + } + + private static void clearTables(Path path) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { + Statement stmt = conn.createStatement(); + for (TablesEnum sourceTable : TablesEnum.values()) + stmt.addBatch("DELETE FROM " + sourceTable); + stmt.addBatch("DELETE FROM artists"); + conn.setAutoCommit(false); + stmt.executeBatch(); + conn.setAutoCommit(true); + stmt.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void insertIntoArtists(Path path, String... artists) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { + String sql = "INSERT INTO artists (artist, urlmusicbrainz, urlbeatport) values(?, ?, ?)"; + PreparedStatement pstmt = conn.prepareStatement(sql); + for (String artist : artists) { + pstmt.setString(1, artist); + pstmt.setString(2, "IDMB"); + pstmt.setString(3, "IDBP"); + pstmt.addBatch(); + } + conn.setAutoCommit(false); + pstmt.executeBatch(); + conn.setAutoCommit(true); + pstmt.close(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public static void deleteTestDBs() { + try { + Files.deleteIfExists(testDBpath); + Files.deleteIfExists(testTemplateDBpath); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static void createArtistsTestDB(String path, int columns) { + try (Connection conn = DriverManager.getConnection(path)) { + Statement stmt = conn.createStatement(); + switch (columns) { + case 1 -> stmt.executeUpdate(""" + CREATE TABLE IF NOT EXISTS artists ( + artist text PRIMARY KEY + ); + """); + case 2 -> stmt.executeUpdate(""" + CREATE TABLE IF NOT EXISTS artists ( + artist text PRIMARY KEY, + urlbeatport text + ); + """); + case 3 -> stmt.executeUpdate(""" + CREATE TABLE IF NOT EXISTS artists ( + artist text PRIMARY KEY, + urlbeatport text, + urlmusicbrainz text + ); + """); + default -> throw new RuntimeException("invalid number"); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public static void fillArtistsTable(Path path, int columns) { + try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + path)) { + PreparedStatement pstmt = conn.prepareStatement( + switch (columns) { + case 1 -> "INSERT INTO artists (artist) values(?)"; + case 2 -> "INSERT INTO artists (artist, urlbeatport) values(?, ?)"; + case 3 -> "INSERT INTO artists (artist, urlbeatport, urlmusicbrainz) values(?, ?, ?)"; + default -> throw new RuntimeException("invalid number"); + } + ); + for (int i = 0; i < 3; ++i) { + switch (columns) { + case 1 -> pstmt.setString(1, Integer.toString(i)); + case 2 -> { + pstmt.setString(1, Integer.toString(i)); + pstmt.setString(2, Integer.toString(i)); + } + case 3 -> { + pstmt.setString(1, Integer.toString(i)); + pstmt.setString(2, Integer.toString(i)); + pstmt.setString(3, Integer.toString(i)); + } + } + pstmt.executeUpdate(); + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/com/blck/MusicReleaseTracker/DB/MigrateDBtest.java b/src/test/java/com/blck/MusicReleaseTracker/DB/MigrateDBtest.java new file mode 100644 index 0000000..6c33de4 --- /dev/null +++ b/src/test/java/com/blck/MusicReleaseTracker/DB/MigrateDBtest.java @@ -0,0 +1,113 @@ +/* + * MusicReleaseTracker + * Copyright (C) 2023 - 2024 BLCK + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.blck.MusicReleaseTracker.DB; + +import com.blck.MusicReleaseTracker.Core.ErrorLogging; +import com.blck.MusicReleaseTracker.Core.ValueStore; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.nio.file.Files; + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +public class MigrateDBtest { + + @Mock + ValueStore store; + @Mock + ErrorLogging log; + @InjectMocks + MigrateDB migrateDB; + + @Test + void createsDBfile() { + HelperDB.deleteDB(); + + migrateDB.createDBandTables(HelperDB.testDBpath); + + assertTrue(Files.exists(HelperDB.testDBpath)); + } + + @Test + void createsTables() { + migrateDB.createDBandTables(HelperDB.testDBpath); + + var structure = migrateDB.getDBStructure(HelperDB.testDBpath); + + assertAll( + () -> assertTrue(structure.containsKey("artists")), + () -> assertTrue(structure.containsKey("combview")), + () -> assertTrue(structure.containsKey("beatport")) + ); + } + + @Test + void structureContainsColumns() { + migrateDB.createDBandTables(HelperDB.testDBpath); + + var structure = migrateDB.getDBStructure(HelperDB.testDBpath); + + assertFalse(structure.get("artists").isEmpty()); + } + + @Test + void copyArtistsDataNoChange() { + HelperDB.deleteTestDBs(); + HelperDB.createArtistsTestDB("jdbc:sqlite:" + HelperDB.testDBpath, 2); + HelperDB.fillArtistsTable(HelperDB.testDBpath, 2); + HelperDB.createArtistsTestDB("jdbc:sqlite:" + HelperDB.testTemplateDBpath, 2); + + migrateDB.copyArtistsData(HelperDB.testDBpath, HelperDB.testTemplateDBpath); + + assertAll( + () -> assertTrue(HelperDB.isArtistsColumnNotEmpty(HelperDB.testTemplateDBpath, "artist")), + () -> assertTrue(HelperDB.isArtistsColumnNotEmpty(HelperDB.testTemplateDBpath, "urlbeatport")) + ); + } + + @Test + void copyArtistsDataRemovedColumns() { + HelperDB.deleteTestDBs(); + HelperDB.createArtistsTestDB("jdbc:sqlite:" + HelperDB.testDBpath, 3); + HelperDB.fillArtistsTable(HelperDB.testDBpath, 3); + HelperDB.createArtistsTestDB("jdbc:sqlite:" + HelperDB.testTemplateDBpath, 1); + + migrateDB.copyArtistsData(HelperDB.testDBpath, HelperDB.testTemplateDBpath); + + assertTrue(HelperDB.isArtistsColumnNotEmpty(HelperDB.testTemplateDBpath, "artist")); + } + + @Test + void copyArtistsDataAddedColumns() { + HelperDB.deleteTestDBs(); + HelperDB.createArtistsTestDB("jdbc:sqlite:" + HelperDB.testDBpath, 1); + HelperDB.fillArtistsTable(HelperDB.testDBpath, 1); + HelperDB.createArtistsTestDB("jdbc:sqlite:" + HelperDB.testTemplateDBpath, 3); + + migrateDB.copyArtistsData(HelperDB.testDBpath, HelperDB.testTemplateDBpath); + + assertAll( + () -> assertTrue(HelperDB.isArtistsColumnNotEmpty(HelperDB.testTemplateDBpath, "artist")), + () -> assertFalse(HelperDB.isArtistsColumnNotEmpty(HelperDB.testTemplateDBpath, "urlbeatport")) + ); + } + +} diff --git a/src/test/java/com/blck/MusicReleaseTracker/HelperDB.java b/src/test/java/com/blck/MusicReleaseTracker/HelperDB.java deleted file mode 100644 index 1a5d96c..0000000 --- a/src/test/java/com/blck/MusicReleaseTracker/HelperDB.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * MusicReleaseTracker - * Copyright (C) 2023 - 2024 BLCK - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.blck.MusicReleaseTracker; - -import com.blck.MusicReleaseTracker.Core.TablesEnum; -import com.blck.MusicReleaseTracker.DB.MigrateDB; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.sql.*; - -public class HelperDB { - - final static Path testResources = Paths.get("src", "test", "testresources"); - final static String testDBpath = "jdbc:sqlite:" + Paths.get("src", "test", "testresources", "testdb.db"); - final static Path DBfilePath = Paths.get("src", "test", "testresources", "testdb.db"); - - public static void redoTestDB() { - try { - if (!Files.exists(testResources)) - Files.createDirectory(testResources); - if (Files.exists(DBfilePath)) - Files.delete(DBfilePath); - } catch (IOException e) { - throw new RuntimeException(e); - } - MigrateDB manageDB = new MigrateDB(null, null); - manageDB.createDBandSourceTables(testDBpath); - } - - public static void redoTestData() { - clearTables(); - insertIntoArtists("artist1", "artist2", "artist3"); - } - - public static int getCountOf(String table, String col, String name) { - int count = 0; - try (Connection conn = DriverManager.getConnection(testDBpath)) { - String sql = "SELECT COUNT(*) FROM " + table + " WHERE " + col + " = ?"; - PreparedStatement pstmt = conn.prepareStatement(sql); - pstmt.setString(1, name); - count = pstmt.executeQuery().getInt(1); - } catch (SQLException e) { - throw new RuntimeException(e); - } - return count; - } - - public static int getNumEntries(String... tables) { - int count = 0; - try (Connection conn = DriverManager.getConnection(testDBpath)) { - for (String table : tables) { - String sql = "SELECT COUNT(*) FROM " + table; - Statement statement = conn.createStatement(); - count += statement.executeQuery(sql).getInt(1); - } - } catch (SQLException e) { - throw new RuntimeException(e); - } - return count; - } - - private static void clearTables() { - try (Connection conn = DriverManager.getConnection(testDBpath)) { - Statement stmt = conn.createStatement(); - for (TablesEnum sourceTable : TablesEnum.values()) - stmt.addBatch("DELETE FROM " + sourceTable); - stmt.addBatch("DELETE FROM artists"); - conn.setAutoCommit(false); - stmt.executeBatch(); - conn.setAutoCommit(true); - stmt.close(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - private static void insertIntoArtists(String... artists) { - try (Connection conn = DriverManager.getConnection(testDBpath)) { - String sql = "INSERT INTO artists (artist, urlmusicbrainz, urlbeatport) values(?, ?, ?)"; - PreparedStatement pstmt = conn.prepareStatement(sql); - for (String artist : artists) { - pstmt.setString(1, artist); - pstmt.setString(2, "IDMB"); - pstmt.setString(3, "IDBP"); - pstmt.addBatch(); - } - conn.setAutoCommit(false); - pstmt.executeBatch(); - conn.setAutoCommit(true); - pstmt.close(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/src/test/java/com/blck/MusicReleaseTracker/StartSetupTest.java b/src/test/java/com/blck/MusicReleaseTracker/StartSetupTest.java index 340f079..9295e71 100644 --- a/src/test/java/com/blck/MusicReleaseTracker/StartSetupTest.java +++ b/src/test/java/com/blck/MusicReleaseTracker/StartSetupTest.java @@ -42,8 +42,6 @@ public class StartSetupTest { @InjectMocks StartSetup startSetup; - @Captor - ArgumentCaptor stringCaptor; @Captor ArgumentCaptor pathCaptor; @@ -53,9 +51,8 @@ void DBpathIntegrity() { startSetup.createPaths(); - verify(store).setDBpath(stringCaptor.capture()); - assertTrue(stringCaptor.getValue().contains(DBpath)); - assertTrue(stringCaptor.getValue().contains("jdbc:sqlite:")); + verify(store).setDBpath(pathCaptor.capture()); + assertTrue(pathCaptor.getValue().toString().contains(DBpath)); } @Test diff --git a/vue/src/components/Bar/SourceMenu.vue b/vue/src/components/Bar/SourceMenu.vue index 9d0db47..3de89dc 100644 --- a/vue/src/components/Bar/SourceMenu.vue +++ b/vue/src/components/Bar/SourceMenu.vue @@ -113,7 +113,7 @@ export default { const currentTime = new Date(); let time = `${currentTime.getDate().toString().padStart(2, "0")}.${(currentTime.getMonth() + 1) .toString() - .padStart(2, "0")}.${currentTime.getHours().toString().padStart(2, "0")}:${currentTime + .padStart(2, "0")} ${currentTime.getHours().toString().padStart(2, "0")}:${currentTime .getMinutes() .toString() .padStart(2, "0")}`; diff --git a/vue/src/components/Content/SourceTable.vue b/vue/src/components/Content/SourceTable.vue index 11168da..60b8e10 100644 --- a/vue/src/components/Content/SourceTable.vue +++ b/vue/src/components/Content/SourceTable.vue @@ -1,5 +1,20 @@ + + @@ -29,10 +44,10 @@ -
+

table empty

-
+

Quickstart guide
1. click "add artist" to insert an artist
@@ -44,7 +59,7 @@