diff --git a/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/client/Database.java b/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/client/Database.java index 59113d1..e6c3264 100644 --- a/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/client/Database.java +++ b/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/client/Database.java @@ -2,7 +2,9 @@ package cc.sukazyo.sekai_cli.client; import cc.sukazyo.sekai_cli.ClientMain; import cc.sukazyo.sekai_cli.data_tool.sekai_master_db.Music; +import cc.sukazyo.sekai_cli.data_tool.sekai_master_db.MusicDifficulty; import cc.sukazyo.sekai_db.PostgresSession; +import cc.sukazyo.sekai_db.table.SekaiSongDifficulties; import cc.sukazyo.sekai_db.table.SekaiSongs; import cc.sukazyo.sekai_scores.Song; import com.google.gson.JsonIOException; @@ -65,7 +67,7 @@ public class Database { switch ($args.remove(0)) { case "song" -> { try (final PostgresSession session = ClientMain.config().db().connect()) { - final Song[] songs = Music.toSongArray(Music.readFrom(file.toFile(), charset)); + final Song[] songs = Music.toSong(Music.readFrom(file.toFile(), charset)); for (Song i : songs) { _user(String.format("db_import: start insertion for song #%d (%s)", i.id(), i.name())); try { @@ -88,8 +90,45 @@ public class Database { _debug(e); } } - case "song-difficulty" -> - _user("type song-difficulty: WIP"); + case "song-difficulty" -> { + try (final PostgresSession session = ClientMain.config().db().connect()) { + final List difficultyList = new ArrayList<>(); + for (MusicDifficulty source : MusicDifficulty.readFrom(file.toFile(), charset)) { + try { difficultyList.add(source.toDatabaseStruct()); } + catch (final IllegalArgumentException e) { + _user(String.format(""" + db_import: song-difficulty: failed converting source data to database struct + at source id #%d (song #%d, difficulty %s) + %s + """, + source.id, source.musicId, source.musicDifficulty, + e.getMessage().indent(2) + )); + _debug(e); + } + } + difficultyList.forEach( i -> { + _user(String.format("db_import: start insertion for difficulty #%d.%s", i.songId(), i.difficulty())); + try { + if (SekaiSongDifficulties.as(session).contains(i.songId(), i.difficulty())) + _user(String.format("db_import: #%d.%s already exists, skipped.", i.songId(), i.difficulty())); + else { + final int changes = SekaiSongDifficulties.as(session).insertDatabaseStructData(i); + _user(String.format("db_import: song #%d.%s insert succeed: %d row updated.", i.songId(), i.difficulty(), changes)); + } + } catch (SQLException e) { + _user(String.format("db_import: #%d.%s: data insert failed: %s", i.songId(), i.difficulty(), e.getMessage())); + _debug(e); + } + }); + } catch (IOException | JsonIOException | JsonSyntaxException e) { + _user("db_import: error while parsing difficulty list file: " + e.getMessage()); + _debug(e); + } catch (SQLException e) { + _user("db_import: error while connecting to database: " + e.getMessage()); + _debug(e); + } + } default -> _user("unavailable type.\ncurrently available types:\n song\n song-difficulty"); } diff --git a/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/Music.java b/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/Music.java index c896aa8..fe61016 100644 --- a/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/Music.java +++ b/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/Music.java @@ -52,7 +52,7 @@ public class Music { ); } - public static Song[] toSongArray (Music... musics) { + public static Song[] toSong (Music... musics) { final List songs = new ArrayList<>(); for (Music i : musics) songs.add(i.toSong()); return songs.toArray(new Song[0]); diff --git a/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/MusicDifficulty.java b/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/MusicDifficulty.java index 85afc00..f06d175 100644 --- a/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/MusicDifficulty.java +++ b/sekai-cli/src/main/java/cc/sukazyo/sekai_cli/data_tool/sekai_master_db/MusicDifficulty.java @@ -1,5 +1,7 @@ package cc.sukazyo.sekai_cli.data_tool.sekai_master_db; +import cc.sukazyo.sekai_db.table.SekaiSongDifficulties.DatabaseStruct; +import cc.sukazyo.sekai_db.type.SekaiDifficulties; import com.google.gson.Gson; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; @@ -8,6 +10,8 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; public class MusicDifficulty { @@ -23,4 +27,25 @@ public class MusicDifficulty { return new Gson().fromJson(new FileReader(sekaiMusicDifficultiesFile, charset), MusicDifficulty[].class); } + /** + * @throws IllegalArgumentException no such difficulty in {@link SekaiDifficulties} + */ + public DatabaseStruct toDatabaseStruct () throws IllegalArgumentException { + return new DatabaseStruct( + musicId, SekaiDifficulties.valueOf(musicDifficulty.toUpperCase()), + playLevel, noteCount, + null, null, null + ); + } + + /** + * @throws IllegalArgumentException no such difficulty in {@link SekaiDifficulties} + * @see #toDatabaseStruct() + */ + public static DatabaseStruct[] toDatabaseStruct (MusicDifficulty... source) throws IllegalArgumentException { + final List target = new ArrayList<>(); + for (MusicDifficulty i : source) target.add(i.toDatabaseStruct()); + return target.toArray(DatabaseStruct[]::new); + } + } diff --git a/sekai-database/src/main/java/cc/sukazyo/sekai_db/table/SekaiSongDifficulties.java b/sekai-database/src/main/java/cc/sukazyo/sekai_db/table/SekaiSongDifficulties.java index 08ba5f8..6bd1feb 100644 --- a/sekai-database/src/main/java/cc/sukazyo/sekai_db/table/SekaiSongDifficulties.java +++ b/sekai-database/src/main/java/cc/sukazyo/sekai_db/table/SekaiSongDifficulties.java @@ -4,6 +4,10 @@ import cc.sukazyo.sekai_db.PostgresSession; import cc.sukazyo.sekai_db.type.SekaiDifficulties; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; public class SekaiSongDifficulties { @@ -12,21 +16,52 @@ public class SekaiSongDifficulties { @Nonnull SekaiDifficulties difficulty, int level, int notes, - int lvlp, - int flvlp, - int plvlp + @Nullable Integer lvlp, + @Nullable Integer flvlp, + @Nullable Integer plvlp ) {} private final PostgresSession session; private SekaiSongDifficulties (PostgresSession session) { this.session = session; } - static SekaiSongDifficulties as (PostgresSession session) { return new SekaiSongDifficulties(session); } + public static SekaiSongDifficulties as (PostgresSession session) { return new SekaiSongDifficulties(session); } -// public boolean contains (int songId, SekaiDifficulties difficulty) { -// -// } -// -// public int insertDatabaseStructData (DatabaseStruct data) { -// } -// + public boolean contains (int songId) throws SQLException { + final PreparedStatement check = session.session.prepareStatement(""" + select song_id, difficulty from sekai_song_difficulties + where song_id = ? + """); + check.setInt(1, songId); + return check.executeQuery().next(); + } + + public boolean contains (int songId, SekaiDifficulties difficulty) throws SQLException { + final PreparedStatement check = session.session.prepareStatement(""" + select song_id, difficulty from sekai_song_difficulties + where song_id = ? and difficulty = cast(? as sekai_difficulties) + """); + check.setInt(1, songId); + check.setString(2, difficulty.name()); + return check.executeQuery().next(); + } + + public int insertDatabaseStructData (DatabaseStruct data) throws SQLException { + final PreparedStatement insert = session.session.prepareStatement(""" + insert into sekai_song_difficulties + (song_id, difficulty, level, notes, "lvl+", "flvl+", "plvl+") + values (?, cast(? as sekai_difficulties), ?, ?, ?, ?, ?) + """); + insert.setInt(1, data.songId); + insert.setString(2, data.difficulty.name()); + insert.setInt(3, data.level); + insert.setInt(4, data.notes); + if (data.lvlp == null) insert.setNull(5, Types.SMALLINT); + else insert.setInt(5, data.lvlp); + if (data.flvlp == null) insert.setNull(6, Types.SMALLINT); + else insert.setInt(6, data.flvlp); + if (data.plvlp == null) insert.setNull(7, Types.SMALLINT); + else insert.setInt(7, data.plvlp); + return insert.executeUpdate(); + } + }