summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorhaslersn <sebastian.hasler@gmx.net>2019-07-03 01:59:50 +0200
committerhaslersn <sebastian.hasler@gmx.net>2019-07-08 00:39:01 +0200
commitca1c35317a6da26b8903e4db450ba213746fa4a8 (patch)
treed325c6f0fbc71c2dfd63db05873635ebbbf21272 /src
parentd246cfdb8e7bc75761c7972b4e1203bdbc6ca44b (diff)
treewide: Make database/crate/track polymorphic
NOTE: The pimpl is polymorphic. This way, the user facing objects can still be passed by value.
Diffstat (limited to 'src')
-rw-r--r--src/djinterop/crate.cpp94
-rw-r--r--src/djinterop/database.cpp130
-rw-r--r--src/djinterop/enginelibrary.cpp73
-rw-r--r--src/djinterop/enginelibrary/el_crate_impl.cpp237
-rw-r--r--src/djinterop/enginelibrary/el_crate_impl.hpp36
-rw-r--r--src/djinterop/enginelibrary/el_database_impl.cpp281
-rw-r--r--src/djinterop/enginelibrary/el_database_impl.hpp68
-rw-r--r--src/djinterop/enginelibrary/el_storage.cpp0
-rw-r--r--src/djinterop/enginelibrary/el_storage.hpp32
-rw-r--r--src/djinterop/enginelibrary/el_track_impl.cpp795
-rw-r--r--src/djinterop/enginelibrary/el_track_impl.hpp274
-rw-r--r--src/djinterop/enginelibrary/encode_decode_utils.cpp (renamed from src/enginelibrary/encode_decode_utils.cpp)2
-rw-r--r--src/djinterop/enginelibrary/encode_decode_utils.hpp (renamed from src/enginelibrary/encode_decode_utils.hpp)0
-rw-r--r--src/djinterop/enginelibrary/performance_data_format.cpp (renamed from src/enginelibrary/performance_data_format.cpp)4
-rw-r--r--src/djinterop/enginelibrary/performance_data_format.hpp (renamed from src/enginelibrary/performance_data_format.hpp)2
-rw-r--r--src/djinterop/enginelibrary/schema.cpp (renamed from src/enginelibrary/schema.cpp)28
-rw-r--r--src/djinterop/enginelibrary/schema.hpp (renamed from src/enginelibrary/schema.hpp)15
-rw-r--r--src/djinterop/enginelibrary/schema_1_6_0.cpp (renamed from src/enginelibrary/schema_1_6_0.cpp)11
-rw-r--r--src/djinterop/enginelibrary/schema_1_6_0.hpp (renamed from src/enginelibrary/schema_1_6_0.hpp)2
-rw-r--r--src/djinterop/enginelibrary/schema_1_7_1.cpp (renamed from src/enginelibrary/schema_1_7_1.cpp)11
-rw-r--r--src/djinterop/enginelibrary/schema_1_7_1.hpp (renamed from src/enginelibrary/schema_1_7_1.hpp)2
-rw-r--r--src/djinterop/enginelibrary/schema_validate_utils.hpp (renamed from src/enginelibrary/schema_validate_utils.hpp)5
-rw-r--r--src/djinterop/impl/crate_impl.cpp13
-rw-r--r--src/djinterop/impl/crate_impl.hpp44
-rw-r--r--src/djinterop/impl/database_impl.cpp0
-rw-r--r--src/djinterop/impl/database_impl.hpp40
-rw-r--r--src/djinterop/impl/track_impl.cpp13
-rw-r--r--src/djinterop/impl/track_impl.hpp112
-rw-r--r--src/djinterop/impl/util.cpp (renamed from src/enginelibrary/util.cpp)5
-rw-r--r--src/djinterop/impl/util.hpp (renamed from src/enginelibrary/util.hpp)3
-rw-r--r--src/djinterop/performance_data.cpp (renamed from src/enginelibrary/performance_data.cpp)14
-rw-r--r--src/djinterop/track.cpp522
-rw-r--r--src/enginelibrary/crate.cpp267
-rw-r--r--src/enginelibrary/database.cpp345
-rw-r--r--src/enginelibrary/database_impl.cpp35
-rw-r--r--src/enginelibrary/database_impl.hpp47
-rw-r--r--src/enginelibrary/track.cpp1107
-rw-r--r--src/meson.build29
38 files changed, 2830 insertions, 1868 deletions
diff --git a/src/djinterop/crate.cpp b/src/djinterop/crate.cpp
new file mode 100644
index 0000000..3cda722
--- /dev/null
+++ b/src/djinterop/crate.cpp
@@ -0,0 +1,94 @@
+/*
+ This file is part of libdjinterop.
+
+ libdjinterop is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ libdjinterop 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libdjinterop. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string>
+#include <vector>
+
+#include <djinterop/djinterop.hpp>
+#include <djinterop/impl/crate_impl.hpp>
+
+namespace djinterop
+{
+crate::crate(const crate& other) noexcept = default;
+
+crate::~crate() = default;
+
+crate& crate::operator=(const crate& other) noexcept = default;
+
+void crate::add_track(track tr) const
+{
+ pimpl_->add_track(tr);
+}
+
+std::vector<crate> crate::children() const
+{
+ return pimpl_->children();
+}
+
+void crate::clear_tracks() const
+{
+ pimpl_->clear_tracks();
+}
+
+std::vector<crate> crate::descendants() const
+{
+ return pimpl_->descendants();
+}
+
+int64_t crate::id() const
+{
+ return pimpl_->id();
+}
+
+bool crate::is_valid() const
+{
+ return pimpl_->is_valid();
+}
+
+std::string crate::name() const
+{
+ return pimpl_->name();
+}
+
+boost::optional<crate> crate::parent() const
+{
+ return pimpl_->parent();
+}
+
+void crate::remove_track(track tr) const
+{
+ pimpl_->remove_track(tr);
+}
+
+void crate::set_name(boost::string_view name) const
+{
+ pimpl_->set_name(name);
+}
+
+void crate::set_parent(boost::optional<crate> parent) const
+{
+ pimpl_->set_parent(parent);
+}
+
+std::vector<track> crate::tracks() const
+{
+ return pimpl_->tracks();
+}
+
+crate::crate(std::shared_ptr<crate_impl> pimpl) : pimpl_{std::move(pimpl)} {}
+
+} // namespace djinterop
diff --git a/src/djinterop/database.cpp b/src/djinterop/database.cpp
new file mode 100644
index 0000000..4643293
--- /dev/null
+++ b/src/djinterop/database.cpp
@@ -0,0 +1,130 @@
+/*
+ This file is part of libdjinterop.
+
+ libdjinterop is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ libdjinterop 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with libdjinterop. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sqlite_modern_cpp.h>
+
+#include <djinterop/djinterop.hpp>
+#include <djinterop/enginelibrary/el_database_impl.hpp>
+#include <djinterop/enginelibrary/schema.hpp>
+#include <djinterop/impl/database_impl.hpp>
+#include <djinterop/impl/util.hpp>
+
+namespace djinterop
+{
+database::database(const database& db) = default;
+
+database::~database() = default;
+
+database& database::operator=(const database& db) = default;
+
+boost::optional<crate> database::crate_by_id(int64_t id) const
+{
+ return pimpl_->crate_by_id(id);
+}
+
+std::vector<crate> database::crates() const
+{
+ return pimpl_->crates();
+}
+
+std::vector<crate> database::crates_by_name(boost::string_view name) const
+{
+ return pimpl_->crates_by_name(name);
+}
+
+crate database::create_crate(boost::string_view name) const
+{
+ return pimpl_->create_crate(name);
+}
+
+track database::create_track(boost::string_view relative_path) const
+{
+ return pimpl_->create_track(relative_path);
+}
+
+std::string database::directory() const
+{
+ return pimpl_->directory();
+}
+
+bool database::is_supported() const
+{
+ return pimpl_->is_supported();
+}
+
+void database::verify() const
+{
+ pimpl_->verify();
+}
+
+std::string database::music_db_path() const
+{
+ return pimpl_->music_db_path();
+}
+
+std::string database::perfdata_db_path() const
+{
+ return pimpl_->perfdata_db_path();
+}
+
+void database::remove_crate(crate cr) const
+{
+ pimpl_->remove_crate(cr);
+}
+
+void database::remove_track(track tr) const
+{
+ pimpl_->remove_track(tr);
+}
+
+std::vector<crate> database::root_crates() const
+{
+ return pimpl_->root_crates();
+}
+
+boost::optional<track> database::track_by_id(int64_t id) const
+{
+ return pimpl_->track_by_id(id);
+}
+
+std::vector<track> database::tracks() const
+{
+ return pimpl_->tracks();
+}
+
+std::vector<track> database::tracks_by_relative_path(
+ boost::string_view relative_path) const
+{
+ return pimpl_->tracks_by_relative_path(relative_path);
+}
+
+std::string database::uuid() const
+{
+ return pimpl_->uuid();
+}
+
+semantic_version database::version() const
+{
+ return pimpl_->version();
+}
+
+database::database(std::shared_ptr<database_impl> pimpl)
+ : pimpl_{std::move(pimpl)}
+{
+}
+
+} // namespace djinterop
diff --git a/src/djinterop/enginelibrary.cpp b/src/djinterop/enginelibrary.cpp
new file mode 100644
index 0000000..7c5b3d4
--- /dev/null
+++ b/src/djinterop/enginelibrary.cpp
@@ -0,0 +1,73 @@
+#include <sys/stat.h>
+#include <string>
+#if defined(_WIN32)
+#include <direct.h>
+#endif
+
+#include <djinterop/djinterop.hpp>
+#include <djinterop/enginelibrary/el_database_impl.hpp>
+#include <djinterop/enginelibrary/schema.hpp>
+
+namespace djinterop
+{
+namespace enginelibrary
+{
+database load_database(std::string directory)
+{
+ return database{std::make_shared<el_database_impl>(std::move(directory))};
+}
+
+database make_database(
+ std::string directory, const semantic_version& default_version)
+{
+ if (!is_supported(default_version))
+ {
+ throw unsupported_database_version{"Unsupported database version",
+ default_version};
+ }
+
+ auto music_db_path = directory + "/m.db";
+ auto perfdata_db_path = directory + "/p.db";
+
+ struct stat buf;
+ bool music_db_exists = stat(music_db_path.c_str(), &buf) == 0;
+ bool perfdata_db_exists = stat(perfdata_db_path.c_str(), &buf) == 0;
+
+ switch (music_db_exists + perfdata_db_exists)
+ {
+ case 1:
+ throw std::runtime_error{"Only one of m.db and p.db exist"};
+ break;
+ case 0:
+ {
+ // Ensure the target directory exists
+ if (stat(directory.c_str(), &buf) != 0)
+ {
+ // Create the dir
+#if defined(_WIN32)
+ if (_mkdir(directory.c_str()) != 0)
+#else
+ if (mkdir(directory.c_str(), 0755) != 0)
+#endif
+ {
+ throw std::runtime_error{
+ "Failed to create directory to hold new database"};
+ }
+ }
+ sqlite::database m_db{music_db_path};
+ create_music_schema(m_db, default_version);
+ verify_music_schema(m_db);
+ sqlite::database p_db{perfdata_db_path};
+ create_performance_schema(p_db, default_version);
+ verify_performance_schema(p_db);
+ break;
+ }
+ default: // both exist, so we do nothing
+ break;
+ }
+
+ return load_database(std::move(directory));
+}
+
+} // namespace enginelibrary
+} // namespace djinterop
diff --git a/src/djinterop/enginelibrary/el_crate_impl.cpp b/src/djinterop/enginelibrary/el_crate_impl.cpp
new file mode 100644
index 0000000..4ea8934
--- /dev/null
+++ b/src/djinterop/enginelibrary/el_crate_impl.cpp
@@ -0,0 +1,237 @@
+#include <sqlite_modern_cpp.h>
+
+#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>
+
+namespace djinterop
+{
+namespace enginelibrary
+{
+using djinterop::crate;
+using djinterop::track;
+
+namespace
+{
+void update_path(
+ sqlite::database& music_db, crate cr, const std::string& parent_path)
+{
+ // update path
+ std::string path = parent_path + cr.name() + ';';
+ music_db << "UPDATE Crate SET path = ? WHERE id = ?" << path << cr.id();
+
+ // recursive call in order to update the path of indirect descendants
+ for (crate cr2 : cr.children())
+ {
+ update_path(music_db, cr2, path);
+ }
+}
+
+} // namespace
+
+el_crate_impl::el_crate_impl(std::shared_ptr<el_storage> storage, int64_t id)
+ : crate_impl{id}, storage_{std::move(storage)}
+{
+}
+
+void el_crate_impl::add_track(track tr)
+{
+ storage_->music_db << "BEGIN";
+
+ storage_->music_db
+ << "DELETE FROM CrateTrackList WHERE crateId = ? AND trackId = ?"
+ << id() << tr.id();
+
+ storage_->music_db
+ << "INSERT INTO CrateTrackList (crateId, trackId) VALUES (?, ?)" << id()
+ << tr.id();
+
+ storage_->music_db << "COMMIT";
+}
+
+std::vector<crate> el_crate_impl::children()
+{
+ std::vector<crate> results;
+ storage_->music_db
+ << "SELECT crateIdChild FROM CrateHierarchy WHERE crateId = ?"
+ << id() >>
+ [&](int64_t crate_id_child) {
+ results.emplace_back(
+ std::make_shared<el_crate_impl>(storage_, crate_id_child));
+ };
+ return results;
+}
+
+void el_crate_impl::clear_tracks()
+{
+ storage_->music_db << "DELETE FROM CrateTrackList WHERE crateId = ?"
+ << id();
+}
+
+database el_crate_impl::db()
+{
+ return database{std::make_shared<el_database_impl>(storage_)};
+}
+
+std::vector<crate> el_crate_impl::descendants()
+{
+ std::vector<crate> results;
+ storage_->music_db
+ << "SELECT crateOriginId FROM CrateParentList WHERE crateParentId "
+ "= ? AND crateOriginId <> crateParentId"
+ << id() >>
+ [&](int64_t descendant_id) {
+ results.push_back(crate{
+ std::make_shared<el_crate_impl>(storage_, descendant_id)});
+ };
+ return results;
+}
+
+bool el_crate_impl::is_valid()
+{
+ bool valid = false;
+ storage_->music_db << "SELECT COUNT(*) FROM Crate WHERE id = ?" << id() >>
+ [&](int count) {
+ if (count == 1)
+ {
+ valid = true;
+ }
+ else if (count > 1)
+ {
+ throw crate_database_inconsistency{
+ "More than one crate with the same ID", id()};
+ }
+ };
+ return valid;
+}
+
+std::string el_crate_impl::name()
+{
+ boost::optional<std::string> name;
+ storage_->music_db << "SELECT title FROM Crate WHERE id = ?" << id() >>
+ [&](std::string title) {
+ if (!name)
+ {
+ name = std::move(title);
+ }
+ else
+ {
+ throw crate_database_inconsistency{
+ "More than one crate with the same ID", id()};
+ }
+ };
+ if (!name)
+ {
+ throw crate_deleted{id()};
+ }
+ return *name;
+}
+
+boost::optional<crate> el_crate_impl::parent()
+{
+ boost::optional<crate> parent;
+ storage_->music_db
+ << "SELECT crateParentId FROM CrateParentList WHERE crateOriginId "
+ "= ? AND crateParentId <> crateOriginId"
+ << id() >>
+ [&](int64_t parent_id) {
+ if (!parent)
+ {
+ parent =
+ crate{std::make_shared<el_crate_impl>(storage_, parent_id)};
+ }
+ else
+ {
+ throw crate_database_inconsistency{
+ "More than one parent crate for the same crate", id()};
+ }
+ };
+ return parent;
+}
+
+void el_crate_impl::remove_track(track tr)
+{
+ storage_->music_db
+ << "DELETE FROM CrateTrackList WHERE crateId = ? AND trackId = ?"
+ << id() << tr.id();
+}
+
+void el_crate_impl::set_name(boost::string_view name)
+{
+ storage_->music_db << "BEGIN";
+
+ // obtain parent's `path`
+ std::string parent_path;
+ storage_->music_db
+ << "SELECT path FROM Crate c JOIN CrateParentList cpl ON c.id = "
+ "cpl.crateParentId WHERE cpl.crateOriginId = ? AND "
+ "cpl.crateOriginId <> cpl.crateParentId"
+ << id() >>
+ [&](std::string path) {
+ if (parent_path.empty())
+ {
+ parent_path = std::move(path);
+ }
+ else
+ {
+ throw crate_database_inconsistency{
+ "More than one parent crate for the same crate", id()};
+ }
+ };
+
+ // update name and path
+ std::string path = std::move(parent_path) + name.data() + ';';
+ storage_->music_db << "UPDATE Crate SET title = ?, path = ? WHERE id = ?"
+ << name.data() << path << id();
+
+ // call the lambda in order to update the path of direct children
+ for (crate cr : children())
+ {
+ update_path(storage_->music_db, cr, path);
+ }
+
+ storage_->music_db << "COMMIT";
+}
+
+void el_crate_impl::set_parent(boost::optional<crate> parent)
+{
+ storage_->music_db << "BEGIN";
+
+ storage_->music_db << "DELETE FROM CrateParentList WHERE crateOriginId = ?"
+ << id();
+
+ storage_->music_db << "INSERT INTO CrateParentList (crateOriginId, "
+ "crateParentId) VALUES (?, ?)"
+ << id() << (parent ? parent->id() : id());
+
+ storage_->music_db << "DELETE FROM CrateHierarchy WHERE crateIdChild = ?"
+ << id();
+
+ if (parent)
+ {
+ storage_->music_db
+ << "INSERT INTO CrateHierarchy (crateId, crateIdChild) SELECT "
+ "crateId, ? FROM CrateHierarchy WHERE crateIdChild = ? UNION "
+ "SELECT ? AS crateId, ? AS crateIdChild"
+ << id() << parent->id() << parent->id() << id();
+ }
+
+ storage_->music_db << "COMMIT";
+}
+
+std::vector<track> el_crate_impl::tracks()
+{
+ std::vector<track> results;
+ storage_->music_db << "SELECT trackId FROM CrateTrackList WHERE crateId = ?"
+ << id() >>
+ [&](int64_t track_id) {
+ results.emplace_back(
+ std::make_shared<el_track_impl>(storage_, track_id));
+ };
+ return results;
+}
+
+} // namespace enginelibrary
+} // namespace djinterop \ No newline at end of file
diff --git a/src/djinterop/enginelibrary/el_crate_impl.hpp b/src/djinterop/enginelibrary/el_crate_impl.hpp
new file mode 100644
index 0000000..7381f0a
--- /dev/null
+++ b/src/djinterop/enginelibrary/el_crate_impl.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <djinterop/impl/crate_impl.hpp>
+
+namespace djinterop
+{
+class track;
+
+namespace enginelibrary
+{
+class el_storage;
+
+class el_crate_impl : public djinterop::crate_impl
+{
+public:
+ el_crate_impl(std::shared_ptr<el_storage> storage, int64_t id);
+
+ void add_track(track tr) override;
+ std::vector<crate> children() override;
+ void clear_tracks() override;
+ database db() override;
+ std::vector<crate> descendants() override;
+ bool is_valid() override;
+ std::string name() override;
+ boost::optional<crate> parent() override;
+ void remove_track(track tr) override;
+ void set_name(boost::string_view name) override;
+ void set_parent(boost::optional<crate> parent) override;
+ std::vector<track> tracks() override;
+
+private:
+ std::shared_ptr<el_storage> storage_;
+};
+
+} // namespace enginelibrary
+} // namespace djinterop
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)
+{