Skip to content

Commit

Permalink
Add StatusDB to keep state of ROM set between runs (not used yet).
Browse files Browse the repository at this point in the history
  • Loading branch information
dillof committed Jun 26, 2024
1 parent ad60ef5 commit 94db695
Show file tree
Hide file tree
Showing 3 changed files with 359 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ set(COMMON_SOURCES
RomDB.cc
SharedFile.cc
Stats.cc
StatusDB.cc
superfluous.cc
TomlSchema.cc
Tree.cc
Expand Down
247 changes: 247 additions & 0 deletions src/StatusDB.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
/*
StatusDB.cc -- sqlite3 data base for status of last runs.
Copyright (C) 2024 Dieter Baron and Thomas Klausner
This file is part of ckmame, a program to check rom sets for MAME.
The authors can be contacted at <[email protected]>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "StatusDB.h"
#include "Exception.h"

const std::string StatusDB::db_name = ".ckmame-status.db";

const DB::DBFormat StatusDB::format = {
0x3,
1,
"\
create table run (\n\
run_id integer primary key autoincrement,\n\
date integer not null\n\
);\n\
create table dat (\n\
dat_id integer primary key,\n\
name text,\n\
version text\n\
);\n\
create table game (\n\
run_id integer not null\n\
dat_id integer not null\n\
name text not null\n\
checksum binary not null\n\
status integer not null\n\
);",
{}
};

std::unordered_map<int, std::string> StatusDB::queries = {
{ CLEANUP_DAT, "delete from dat where dat_id not in (select distinct(dat_id) from file)"},
{ CLEANUP_GAME, "delete from game where run_id not in (select run_id from run)" },
{ DELETE_RUN, "delete from run where date < :date and run_id not in (select run_id from run order by date descending limit :count"},
{ FIND_DAT, "select dat_id from dat where name = :name and version = :version" },
{ INSERT_DAT, "inesrt into dat (name, version) values (:name, :version)" },
{ INSERT_GAME, "insert into game (run_id, dat_id, name, checksum, status) values (:run_id, :dat_id, :name, :checksum, :status" },
{ INSERT_RUN, "insert into run (date) values (:date)" },
{ LIST_RUNS, "select run_id, date from run order by date descending" },
{ QUERY_GAME, "select dat_id, name, checksum, status from game where run_id = :run_id" },
{ QUERY_GAME_BY_STATUS, "select name from game where run_id = :run, status = :status order by name"},
{ QUERY_GAME_STATI, "select name, status from game where run_id = :run order by name"},
{ QUERY_RUN_STATUS_COUNTS, "select status, count(*) as status_count from game where run_id = :run_id group by status" },
};

std::string StatusDB::get_query(int name, bool parameterized) const {
if (parameterized) {
return "";
}
else {
auto it = queries.find(static_cast<Statement>(name));
if (it == queries.end()) {
return "";
}
return it->second;
}
}

void StatusDB::delete_runs(time_t oldest, int count) {
auto stmt = get_statement(DELETE_RUN);

stmt->set_int64("oldest", static_cast<int64_t>(oldest));
stmt->set_int("count", count);

if (!stmt->step()) {
return;
}

stmt = get_statement(CLEANUP_GAME);
if (!stmt->step()) {
return;
}

stmt = get_statement(CLEANUP_DAT);
stmt->step();
}

std::vector<StatusDB::Game> StatusDB::get_games(int64_t run_id) {
auto stmt = get_statement(QUERY_GAME);

stmt->set_int64("run_id", run_id);

std::vector<Game> games;

while (stmt->step()) {
Game game;

game.dat_id = stmt->get_int("dat_id");
game.name = stmt->get_string("name");
game.checksum = stmt->get_blob("checksum");
game.status = static_cast<GameStatus>(stmt->get_int("status"));

games.push_back(game);
}

return games;
}

std::vector<StatusDB::Run> StatusDB::list_runs() {
auto stmt = get_statement(QUERY_GAME);

std::vector<Run> runs;

while (stmt->step()) {
Run run;

run.run_id = stmt->get_int64("run_id");
run.date = static_cast<time_t>(stmt->get_int64("date"));

runs.push_back(run);
}

return runs;
}

std::vector<std::string> StatusDB::get_games_by_status(int64_t run_id, GameStatus status) {
auto stmt = get_statement(QUERY_GAME_BY_STATUS);

stmt->set_int64("run_id", run_id);
stmt->set_int("status", status);

std::vector<std::string> games;

while (stmt->step()) {
games.push_back(stmt->get_string("name"));
}

return games;
}

std::vector<StatusDB::Status> StatusDB::get_game_stati(int64_t run_id) {
auto stmt = get_statement(QUERY_GAME_STATI);

stmt->set_int64("run_id", run_id);

std::vector<Status> stati;

while (stmt->step()) {
Status status;

status.name = stmt->get_string("name");
status.status = static_cast<GameStatus>(stmt->get_int("status"));

stati.push_back(status);
}

return stati;
}

std::vector<StatusDB::StatusCount> StatusDB::get_run_status_counts(int64_t run_id) {
auto stmt = get_statement(QUERY_RUN_STATUS_COUNTS);

stmt->set_int64("run_id", run_id);

std::vector<StatusCount> counts;

while (stmt->step()) {
StatusCount count;

count.status = static_cast<GameStatus>(stmt->get_int("status"));
count.count = stmt->get_int("status_count");

counts.push_back(count);
}

return counts;
}

int64_t StatusDB::insert_dat(const DatEntry& dat) {
auto stmt = get_statement(FIND_DAT);

stmt->set_string("name", dat.name);
stmt->set_string("version", dat.version);

if (stmt->step()) {
return stmt->get_int64("dat_id");
}

stmt = get_statement(INSERT_DAT);

stmt->set_string("name", dat.name);
stmt->set_string("version", dat.version);

if (stmt->step()) {
return stmt->get_rowid();
}
else {
throw Exception("can't insert dat"); // TODO: details
}
}


void StatusDB::insert_game(int64_t run_id, const StatusDB::Game& game) {
auto stmt = get_statement(INSERT_GAME);

stmt->set_int64("run_id", run_id);
stmt->set_string("name", game.name);
stmt->set_int("status", static_cast<int>(game.status));

if (!stmt->step()) {
throw Exception("can't insert game");
}
}

int64_t StatusDB::insert_run(time_t date) {
auto stmt = get_statement(INSERT_RUN);

stmt->set_int64("date", static_cast<int64_t>(date));

if (stmt->step()) {
return stmt->get_rowid();
}
else {
throw Exception("can't insert run");
}
}
111 changes: 111 additions & 0 deletions src/StatusDB.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#ifndef HAD_STATUS_DB_H
#define HAD_STATUS_DB_H

/*
StatusDB.h -- sqlite3 data base for status of last runs.
Copyright (C) 2024 Dieter Baron and Thomas Klausner
This file is part of ckmame, a program to check rom sets for MAME.
The authors can be contacted at <[email protected]>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "DB.h"
#include "DatEntry.h"
#include "Result.h"

class StatusDB: public DB {
public:
enum Statement {
CLEANUP_DAT,
CLEANUP_GAME,
DELETE_RUN,
FIND_DAT,
INSERT_DAT,
INSERT_GAME,
INSERT_RUN,
LIST_RUNS,
QUERY_GAME,
QUERY_GAME_BY_STATUS,
QUERY_GAME_STATI,
QUERY_RUN_STATUS_COUNTS
};

class Run {
public:
int64_t run_id{};
time_t date{};
};

class Game {
public:
int64_t dat_id{};
std::string name;
std::vector<uint8_t> checksum;
GameStatus status;
};

class Status {
public:
std::string name;
GameStatus status;
};

class StatusCount {
public:
GameStatus status;
int count;
};

static const DBFormat format;
static const std::string db_name;

StatusDB(const std::string &name, int mode) : DB(format, name, mode) {}
~StatusDB() override = default;

void delete_runs(time_t oldest, int count);
[[nodiscard]] std::vector<Run> list_runs();
[[nodiscard]] std::vector<Game> get_games(int64_t run_id);
[[nodiscard]] std::vector<std::string> get_games_by_status(int64_t run_id, GameStatus status);
[[nodiscard]] std::vector<Status> get_game_stati(int64_t run_id);
[[nodiscard]] std::vector<StatusCount> get_run_status_counts(int64_t run_id);
[[nodiscard]] int64_t insert_dat(const DatEntry& dat);
void insert_game(int64_t run_id, const Game& game);
[[nodiscard]] int64_t insert_run(time_t date);

protected:
[[nodiscard]] std::string get_query(int name, bool parameterized) const override;

private:
static std::unordered_map<int, std::string> queries;

DBStatement *get_statement(Statement name) { return get_statement_internal(name); }

};


#endif // HAD_STATUS_DB_H

0 comments on commit 94db695

Please sign in to comment.