1
0
mirror of https://github.com/Eyre-S/sekai-scores.git synced 2024-11-24 20:17:40 +08:00

complete cli import song from sekai-master-db

- and added database struct can execute some postgres sekai database action
  - now can insert a Song (without its Difficulties)
  - now can search if a Song exists(by id)
  - added a SekaiDifficulties type struct targeting to database type
  - added a struct SekaiSongDifficulties.DatabaseStruct targeting to database its table struct
- added a class PostgresSession for manager a database action flow
  - and reforged PostgresConfig#connect() to implement it
This commit is contained in:
A.C.Sukazyo Eyre 2022-12-07 22:19:16 +08:00
parent 944b57c012
commit 7d503f3723
Signed by: Eyre_S
GPG Key ID: C17CE40291207874
10 changed files with 182 additions and 5 deletions

View File

@ -1,7 +1,7 @@
## Project Configurations
# Proj Metadata
projVersion = 0.7
projVersion = 0.8
# Dependencies

View File

@ -1,7 +1,7 @@
## Project Configurations
# Proj Metadata
moduleVersion = 0.5.3
moduleVersion = 0.5.4
# dependencies
lib_postgres_driver = 42.5.1

View File

@ -1,6 +1,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_db.PostgresSession;
import cc.sukazyo.sekai_db.table.SekaiSongs;
import cc.sukazyo.sekai_scores.Song;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
@ -11,6 +14,7 @@ import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@ -60,10 +64,27 @@ public class Database {
}
switch ($args.remove(0)) {
case "song" -> {
try {
try (final PostgresSession session = ClientMain.config().db().connect()) {
final Song[] songs = Music.toSongArray(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 {
if (SekaiSongs.as(session).hasSong(i.id()))
_user(String.format("db_import: song #%d already exists, skipped.", i.id()));
else {
final int changes = SekaiSongs.as(session).insert(i);
_user(String.format("db_import: song #%d insert succeed: %d row updated.", i.id(), changes));
}
} catch (SQLException e) {
_user("db_import: song #"+i.id()+": data insert failed: " + e.getMessage());
_debug(e);
}
}
} catch (IOException | JsonIOException | JsonSyntaxException e) {
_user("error while parsing song file: " + e.getMessage());
_user("db_import: error while parsing song file: " + e.getMessage());
_debug(e);
} catch (SQLException e) {
_user("db_import: error while connecting to database: " + e.getMessage());
_debug(e);
}
}

View File

@ -0,0 +1,26 @@
package cc.sukazyo.sekai_cli.data_tool.sekai_master_db;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
public class MusicDifficulty {
public int id;
public int musicId;
public String musicDifficulty;
public int playLevel;
public int releaseConditionId;
public int noteCount;
public static MusicDifficulty[] readFrom (File sekaiMusicDifficultiesFile, Charset charset)
throws IOException, JsonIOException, JsonSyntaxException {
return new Gson().fromJson(new FileReader(sekaiMusicDifficultiesFile, charset), MusicDifficulty[].class);
}
}

View File

@ -13,6 +13,8 @@ dependencies {
compileOnly "com.github.spotbugs:spotbugs-annotations:${lib_spotbugs_v}"
implementation rootProject
testImplementation "org.junit.jupiter:junit-jupiter-api:${lib_junit_v}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${lib_junit_v}"

View File

@ -38,7 +38,11 @@ public class PostgresConfig {
return (schema == null ? "" : '"' + schema() + '"' + ".") + '"' + table + '"';
}
public Connection connect () throws SQLException {
public PostgresSession connect () throws SQLException {
return PostgresSession.as(this);
}
Connection getConnection () throws SQLException {
return DriverManager.getConnection(this.toString(), user, token);
}

View File

@ -0,0 +1,28 @@
package cc.sukazyo.sekai_db;
import java.sql.Connection;
import java.sql.SQLException;
public class PostgresSession implements AutoCloseable {
public final Connection session;
private final PostgresConfig config;
private PostgresSession (Connection session, PostgresConfig config) {
this.config = config;
this.session = session;
}
static PostgresSession as (PostgresConfig config) throws SQLException {
final PostgresSession $this = new PostgresSession(config.getConnection(), config);
$this.session.setAutoCommit(false);
$this.session.beginRequest();
$this.session.setSchema($this.config.schema);
return $this;
}
@Override
public void close () throws SQLException {
session.commit();
session.close();
}
}

View File

@ -0,0 +1,32 @@
package cc.sukazyo.sekai_db.table;
import cc.sukazyo.sekai_db.PostgresSession;
import cc.sukazyo.sekai_db.type.SekaiDifficulties;
import javax.annotation.Nonnull;
public class SekaiSongDifficulties {
public record DatabaseStruct (
int songId,
@Nonnull SekaiDifficulties difficulty,
int level,
int notes,
int lvlp,
int flvlp,
int plvlp
) {}
private final PostgresSession session;
private SekaiSongDifficulties (PostgresSession session) { this.session = session; }
static SekaiSongDifficulties as (PostgresSession session) { return new SekaiSongDifficulties(session); }
// public boolean contains (int songId, SekaiDifficulties difficulty) {
//
// }
//
// public int insertDatabaseStructData (DatabaseStruct data) {
// }
//
}

View File

@ -0,0 +1,55 @@
package cc.sukazyo.sekai_db.table;
import cc.sukazyo.sekai_db.PostgresSession;
import cc.sukazyo.sekai_scores.Song;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Arrays;
public class SekaiSongs {
private final PostgresSession session;
private SekaiSongs(PostgresSession session) {
this.session = session;
}
public static SekaiSongs as (PostgresSession session) {
return new SekaiSongs(session);
}
public boolean hasSong(int songId) throws SQLException {
final PreparedStatement statement = session.session.prepareStatement("""
select id from sekai_songs
where id = ?
""");
statement.setInt(1, songId);
return statement.executeQuery().next();
}
public int insert (Song song) throws SQLException {
final PreparedStatement statement = session.session.prepareStatement("""
insert into sekai_songs
(id, unit_seq, name, producer, arranger, composer, lyricist, bpm, duration, release_date, name_alias)
values (?, ?, ?, ?, ?, ?, ?, ?, cast(? AS interval), ?, ?)
""");
statement.setInt(1, song.id());
statement.setInt(2, song.unit().seq);
statement.setString(3, song.name());
statement.setString(4, song.producer());
statement.setString(5, song.arranger());
statement.setString(6, song.composer());
statement.setString(7, song.lyricist());
if (song.bpm() == null) statement.setNull(8, Types.ARRAY);
else statement.setArray(8, session.session.createArrayOf("smallint", Arrays.stream(song.bpm()).boxed().toArray()));
if (song.duration() == null) statement.setNull(9, Types.VARCHAR);
else statement.setString(9, song.duration().toString());
if (song.releaseDate() == null) statement.setNull(10, Types.TIMESTAMP_WITH_TIMEZONE);
else statement.setTimestamp(10, Timestamp.from(song.releaseDate().toInstant()));
statement.setArray(11, session.session.createArrayOf("text", song.nameAlias()));
return statement.executeUpdate();
}
}

View File

@ -0,0 +1,9 @@
package cc.sukazyo.sekai_db.type;
public enum SekaiDifficulties {
EASY,
NORMAL,
HARD,
EXPERT,
MASTER
}