summaryrefslogtreecommitdiffstats
path: root/src/djinterop/enginelibrary/el_database_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/djinterop/enginelibrary/el_database_impl.cpp')
-rw-r--r--src/djinterop/enginelibrary/el_database_impl.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/djinterop/enginelibrary/el_database_impl.cpp b/src/djinterop/enginelibrary/el_database_impl.cpp
new file mode 100644
index 0000000..ab7eaef
--- /dev/null
+++ b/src/djinterop/enginelibrary/el_database_impl.cpp
@@ -0,0 +1,281 @@
+#include <djinterop/djinterop.hpp>
+#include <djinterop/enginelibrary/el_crate_impl.hpp>
+#include <djinterop/enginelibrary/el_database_impl.hpp>
+#include <djinterop/enginelibrary/el_storage.hpp>
+#include <djinterop/enginelibrary/el_track_impl.hpp>
+#include <djinterop/enginelibrary/schema.hpp>
+#include <djinterop/impl/util.hpp>
+
+namespace djinterop
+{
+namespace enginelibrary
+{
+using djinterop::crate;
+using djinterop::track;
+
+el_database_impl::el_database_impl(std::string directory)
+ : storage_{std::make_shared<el_storage>(std::move(directory))}
+{
+}
+
+el_database_impl::el_database_impl(std::shared_ptr<el_storage> storage)
+ : storage_{std::move(storage)}
+{
+}
+
+boost::optional<crate> el_database_impl::crate_by_id(int64_t id)
+{
+ boost::optional<crate> cr;
+ storage_->music_db << "SELECT COUNT(*) FROM Crate WHERE id = ?" << id >>
+ [&](int64_t count) {
+ if (count == 1)
+ {
+ cr = crate{std::make_shared<el_crate_impl>(storage_, id)};
+ }
+ else if (count > 1)
+ {
+ throw crate_database_inconsistency{
+ "More than one crate with the same ID", id};
+ }
+ };
+ return cr;
+}
+
+std::vector<crate> el_database_impl::crates()
+{
+ std::vector<crate> results;
+ storage_->music_db << "SELECT id FROM Crate ORDER BY id" >>
+ [&](int64_t id) {
+ results.push_back(
+ crate{std::make_shared<el_crate_impl>(storage_, id)});
+ };
+ return results;
+}
+
+std::vector<crate> el_database_impl::crates_by_name(boost::string_view name)
+{
+ std::vector<crate> results;
+ storage_->music_db << "SELECT id FROM Crate WHERE title = ? ORDER BY id"
+ << name.data() >>
+ [&](int64_t id) {
+ results.push_back(
+ crate{std::make_shared<el_crate_impl>(storage_, id)});
+ };
+ return results;
+}
+
+crate el_database_impl::create_crate(boost::string_view name)
+{
+ storage_->music_db << "BEGIN";
+
+ storage_->music_db << "INSERT INTO Crate (title, path) VALUES (?, ?)"
+ << name.data() << std::string{name} + ';';
+
+ int64_t id = storage_->music_db.last_insert_rowid();
+
+ storage_->music_db << "INSERT INTO CrateParentList (crateOriginId, "
+ "crateParentId) VALUES (?, ?)"
+ << id << id;
+
+ storage_->music_db << "COMMIT";
+
+ return crate{std::make_shared<el_crate_impl>(storage_, id)};
+}
+
+track el_database_impl::create_track(boost::string_view relative_path)
+{
+ // TODO (haslersn): Should it be allowed to create two tracks with the same
+ // `relative_path`?
+
+ auto filename = get_filename(relative_path);
+
+ storage_->music_db << "BEGIN";
+
+ // Insert a new entry in the track table
+ storage_->music_db << "INSERT INTO Track (path, filename, trackType, "
+ "isExternalTrack, idAlbumArt) VALUES (?,?,?,?,?)"
+ << relative_path.data() //
+ << std::string{filename} //
+ << 1 // trackType
+ << 0 // isExternalTrack
+ << 1; // idAlbumArt
+
+ auto id = storage_->music_db.last_insert_rowid();
+
+ if (version() >= version_1_7_1)
+ {
+ storage_->music_db << "UPDATE Track SET pdbImportKey = 0 WHERE id = ?"
+ << id;
+ }
+
+ {
+ auto extension = get_file_extension(filename);
+ auto metadata_str_inserter =
+ storage_->music_db
+ << "REPLACE INTO MetaData (id, type, text) VALUES (?, ?, ?)";
+ for (int64_t type : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 16})
+ {
+ boost::optional<std::string> text;
+ switch (type)
+ {
+ case 10:
+ // duration in MM:SS
+ // TODO (haslersn)
+ break;
+ case 13:
+ // extension
+ if (extension)
+ {
+ text = extension->to_string();
+ }
+ break;
+ case 15:
+ case 16:
+ // Always 1 to our knowledge
+ text = "1";
+ break;
+ }
+ metadata_str_inserter << id << type << text;
+ metadata_str_inserter++;
+ }
+ }
+
+ {
+ auto metadata_int_inserter = storage_->music_db
+ << "REPLACE INTO MetaDataInteger (id, "
+ "type, value) VALUES (?, ?, ?)";
+ for (int64_t type = 1; type <= 11 /* 12 */; ++type)
+ {
+ boost::optional<int64_t> value;
+ switch (type)
+ {
+ case 5: value = 0; break;
+ case 11:
+ // case 12:
+ value = 1;
+ break;
+ }
+ metadata_int_inserter << id << type << value;
+ metadata_int_inserter++;
+ }
+ }
+
+ storage_->music_db << "COMMIT";
+
+ return track{std::make_shared<el_track_impl>(storage_, id)};
+}
+
+std::string el_database_impl::directory()
+{
+ return storage_->directory;
+}
+
+bool el_database_impl::is_supported()
+{
+ return djinterop::enginelibrary::is_supported(version());
+}
+
+void el_database_impl::verify()
+{
+ // Verify music schema
+ verify_music_schema(storage_->music_db);
+
+ // Verify performance schema
+ verify_performance_schema(storage_->perfdata_db);
+}
+
+std::string el_database_impl::music_db_path()
+{
+ return storage_->music_db_path;
+}
+
+std::string el_database_impl::perfdata_db_path()
+{
+ return storage_->perfdata_db_path;
+}
+
+void el_database_impl::remove_crate(crate cr)
+{
+ storage_->music_db << "DELETE FROM Crate WHERE id = ?" << cr.id();
+}
+
+void el_database_impl::remove_track(track tr)
+{
+ storage_->music_db << "DELETE FROM Track WHERE id = ?" << tr.id();
+ // All other references to the track should automatically be cleared by
+ // "ON DELETE CASCADE"
+}
+
+std::vector<crate> el_database_impl::root_crates()
+{
+ std::vector<crate> results;
+ storage_->music_db
+ << "SELECT crateOriginId FROM CrateParentList WHERE crateParentId "
+ "= crateOriginId ORDER BY crateOriginId" >>
+ [&](int64_t id) {
+ results.push_back(
+ crate{std::make_shared<el_crate_impl>(storage_, id)});
+ };
+ return results;
+}
+
+boost::optional<track> el_database_impl::track_by_id(int64_t id)
+{
+ boost::optional<track> tr;
+ storage_->music_db << "SELECT COUNT(*) FROM Track WHERE id = ?" << id >>
+ [&](int64_t count) {
+ if (count == 1)
+ {
+ tr = track{std::make_shared<el_track_impl>(storage_, id)};
+ }
+ else if (count > 1)
+ {
+ throw track_database_inconsistency{
+ "More than one track with the same ID", id};
+ }
+ };
+ return tr;
+}
+
+std::vector<track> el_database_impl::tracks()
+{
+ std::vector<track> results;
+ storage_->music_db << "SELECT id FROM Track ORDER BY id" >>
+ [&](int64_t id) {
+ results.push_back(
+ track{std::make_shared<el_track_impl>(storage_, id)});
+ };
+ return results;
+}
+
+std::vector<track> el_database_impl::tracks_by_relative_path(
+ boost::string_view relative_path)
+{
+ std::vector<track> results;
+ storage_->music_db << "SELECT id FROM Track WHERE path = ? ORDER BY id"
+ << relative_path.data() >>
+ [&](int64_t id) {
+ results.push_back(
+ track{std::make_shared<el_track_impl>(storage_, id)});
+ };
+ return results;
+}
+
+std::string el_database_impl::uuid()
+{
+ std::string uuid;
+ storage_->music_db << "SELECT uuid FROM Information" >> uuid;
+ return uuid;
+}
+
+semantic_version el_database_impl::version()
+{
+ semantic_version version;
+ storage_->music_db << "SELECT schemaVersionMajor, schemaVersionMinor, "
+ "schemaVersionPatch FROM Information" >>
+ std::tie(version.maj, version.min, version.pat);
+ return version;
+}
+
+} // namespace enginelibrary
+} // namespace djinterop