Skip to content

Commit

Permalink
Create crates in order (#119)
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-smidge authored Apr 4, 2024
1 parent cfa1adb commit f34a8fb
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 20 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(libdjinterop
VERSION 0.20.3
VERSION 0.21.0
DESCRIPTION "C++ library providing access to DJ record libraries")
set(PROJECT_HOMEPAGE_URL "https://github.com/xsco/libdjinterop")

Expand Down
8 changes: 6 additions & 2 deletions include/djinterop/crate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ class DJINTEROP_PUBLIC crate
/// zero crates.
void clear_tracks() const;

/// Creates a new, empty crate as a child of this one, and returns it.
crate create_sub_crate(std::string name);
/// Create a new crate as a child of this one.
crate create_sub_crate(const std::string& name);

/// Create a new crate as a child of this one, after the given crate in
/// order.
crate create_sub_crate_after(const std::string& name, const crate& after);

/// Returns the database containing the crate
database db() const;
Expand Down
9 changes: 5 additions & 4 deletions include/djinterop/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@ class DJINTEROP_PUBLIC database
/// Returns all crates with the given name
std::vector<crate> crates_by_name(const std::string& name) const;

/// Creates a new root crate with the given name.
///
/// The created crate has no parent.
crate create_root_crate(std::string name) const;
/// Create a new root crate with the given name. The created crate has no parent.
crate create_root_crate(const std::string& name);

/// Create a new root crate with the given name, after the given crate in order.
crate create_root_crate_after(const std::string& name, const crate& after);

/// Create a new track in the database, given a pre-populated track
/// snapshot.
Expand Down
8 changes: 7 additions & 1 deletion src/djinterop/crate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <djinterop/djinterop.hpp>

#include "impl/crate_impl.hpp"
#include "djinterop/crate.hpp"

namespace djinterop
{
Expand Down Expand Up @@ -50,11 +51,16 @@ void crate::clear_tracks() const
pimpl_->clear_tracks();
}

crate crate::create_sub_crate(std::string name)
crate crate::create_sub_crate(const std::string& name)
{
return pimpl_->create_sub_crate(name);
}

crate crate::create_sub_crate_after(const std::string& name, const crate& after)
{
return pimpl_-> create_sub_crate_after(name, after);
}

database crate::db() const
{
return pimpl_->db();
Expand Down
9 changes: 8 additions & 1 deletion src/djinterop/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <djinterop/djinterop.hpp>

#include "impl/database_impl.hpp"
#include "djinterop/database.hpp"


namespace djinterop
{
Expand All @@ -44,11 +46,16 @@ std::vector<crate> database::crates_by_name(const std::string& name) const
return pimpl_->crates_by_name(name);
}

crate database::create_root_crate(std::string name) const
crate database::create_root_crate(const std::string& name)
{
return pimpl_->create_root_crate(name);
}

crate database::create_root_crate_after(const std::string &name, const crate &after)
{
return pimpl_->create_root_crate_after(name, after);
}

track database::create_track(const track_snapshot& snapshot)
{
return pimpl_->create_track(snapshot);
Expand Down
9 changes: 8 additions & 1 deletion src/djinterop/engine/v1/engine_crate_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ void engine_crate_impl::clear_tracks()
storage_->db << "DELETE FROM CrateTrackList WHERE crateId = ?" << id();
}

crate engine_crate_impl::create_sub_crate(std::string name)
crate engine_crate_impl::create_sub_crate(const std::string& name)
{
ensure_valid_name(name);
util::sqlite_transaction trans{storage_->db};
Expand Down Expand Up @@ -182,6 +182,13 @@ crate engine_crate_impl::create_sub_crate(std::string name)
return cr;
}

crate engine_crate_impl::create_sub_crate_after(
const std::string& name, [[maybe_unused]] const crate& after)
{
// TODO (mr-smidge): Back-port sorted crate functionality to Engine V1.
return create_sub_crate(name);
}

database engine_crate_impl::db()
{
return database{std::make_shared<engine_database_impl>(storage_)};
Expand Down
4 changes: 3 additions & 1 deletion src/djinterop/engine/v1/engine_crate_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class engine_crate_impl : public djinterop::crate_impl
void add_track(track tr) override;
std::vector<crate> children() override;
void clear_tracks() override;
crate create_sub_crate(std::string name) override;
crate create_sub_crate(const std::string& name) override;
crate create_sub_crate_after(
const std::string& name, const crate& after) override;
database db() override;
std::vector<crate> descendants() override;
bool is_valid() override;
Expand Down
9 changes: 8 additions & 1 deletion src/djinterop/engine/v1/engine_database_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ std::vector<crate> engine_database_impl::crates_by_name(const std::string& name)
return results;
}

crate engine_database_impl::create_root_crate(std::string name)
crate engine_database_impl::create_root_crate(const std::string& name)
{
ensure_valid_crate_name(name);
djinterop::util::sqlite_transaction trans{storage_->db};
Expand Down Expand Up @@ -125,6 +125,13 @@ crate engine_database_impl::create_root_crate(std::string name)
return cr;
}

crate engine_database_impl::create_root_crate_after(
const std::string& name, [[maybe_unused]] const crate& after)
{
// TODO (mr-smidge): Back-port sorted crate functionality to Engine V1.
return create_root_crate(name);
}

track engine_database_impl::create_track(const track_snapshot& snapshot)
{
return djinterop::engine::v1::create_track(storage_, snapshot);
Expand Down
4 changes: 3 additions & 1 deletion src/djinterop/engine/v1/engine_database_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ class engine_database_impl : public database_impl
std::vector<djinterop::crate> crates() override;
std::vector<djinterop::crate> crates_by_name(
const std::string& name) override;
djinterop::crate create_root_crate(std::string name) override;
crate create_root_crate(const std::string& name) override;
crate create_root_crate_after(
const std::string& name, const crate& after) override;
track create_track(const track_snapshot& snapshot) override;
std::string directory() override;
void verify() override;
Expand Down
37 changes: 36 additions & 1 deletion src/djinterop/engine/v2/crate_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ void crate_impl::clear_tracks()
playlist_entity_.clear(id());
}

crate crate_impl::create_sub_crate(std::string name)
crate crate_impl::create_sub_crate(const std::string& name)
{
if (library_->playlist().find_id(id(), name))
{
Expand All @@ -96,6 +96,41 @@ crate crate_impl::create_sub_crate(std::string name)
return crate{std::make_shared<crate_impl>(library_, id)};
}

crate crate_impl::create_sub_crate_after(
const std::string& name, const crate& after)
{
if (library_->playlist().find_id(id(), name))
{
throw crate_already_exists{
"Cannot create a crate with name '" + name +
"' under parent crate '" + this->name() +
"', because a crate with that name already exists"};
}

auto after_row = library_->playlist().get(after.id());
if (after_row->parent_list_id != id())
{
throw crate_invalid_parent{
"Cannot create a crate under parent crate " + this->name() +
" after crate " + after_row->title +
", because it resides under a different parent crate"};
}

// DB triggers will take care of massaging the next-list-id columns. We
// only need to work out what the new "next" list should be.
playlist_row row{
PLAYLIST_ROW_ID_NONE,
name,
id(),
true,
after_row->next_list_id,
std::chrono::system_clock::now(),
true};

auto id = library_->playlist().add(row);
return crate{std::make_shared<crate_impl>(library_, id)};
}

database crate_impl::db()
{
return database{std::make_shared<database_impl>(library_)};
Expand Down
4 changes: 3 additions & 1 deletion src/djinterop/engine/v2/crate_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ class crate_impl : public djinterop::crate_impl
void add_track(track tr) override;
std::vector<crate> children() override;
void clear_tracks() override;
crate create_sub_crate(std::string name) override;
crate create_sub_crate(const std::string& name) override;
crate create_sub_crate_after(
const std::string& name, const crate& after) override;
database db() override;
std::vector<crate> descendants() override;
bool is_valid() override;
Expand Down
42 changes: 41 additions & 1 deletion src/djinterop/engine/v2/database_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,15 @@ std::vector<crate> database_impl::crates_by_name(const std::string& name)
return results;
}

crate database_impl::create_root_crate(std::string name)
crate database_impl::create_root_crate(const std::string& name)
{
if (library_->playlist().find_root_id(name))
{
throw crate_already_exists{
"Cannot create a crate with name '" + name +
"' as a root crate, because a crate with that name already exists"};
}

playlist_row row{
PLAYLIST_ROW_ID_NONE,
name,
Expand All @@ -84,6 +91,39 @@ crate database_impl::create_root_crate(std::string name)
return crate{std::make_shared<crate_impl>(library_, id)};
}

crate database_impl::create_root_crate_after(
const std::string& name, const crate& after)
{
if (library_->playlist().find_root_id(name))
{
throw crate_already_exists{
"Cannot create a crate with name '" + name +
"' as a root crate, because a crate with that name already exists"};
}

auto after_row = library_->playlist().get(after.id());
if (after_row->parent_list_id != PARENT_LIST_ID_NONE)
{
throw crate_invalid_parent{
"Cannot create a root crate after crate " + after_row->title +
", because it is not a root crate"};
}

// DB triggers will take care of massaging the next-list-id columns. We
// only need to work out what the new "next" list should be.
playlist_row row{
PLAYLIST_ROW_ID_NONE,
name,
PARENT_LIST_ID_NONE,
true,
after_row->next_list_id,
std::chrono::system_clock::now(),
true};

auto id = library_->playlist().add(row);
return crate{std::make_shared<crate_impl>(library_, id)};
}

track database_impl::create_track(const track_snapshot& snapshot)
{
return djinterop::engine::v2::create_track(library_, snapshot);
Expand Down
4 changes: 3 additions & 1 deletion src/djinterop/engine/v2/database_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class database_impl : public djinterop::database_impl
std::vector<djinterop::crate> crates() override;
std::vector<djinterop::crate> crates_by_name(
const std::string& name) override;
djinterop::crate create_root_crate(std::string name) override;
crate create_root_crate(const std::string& name) override;
crate create_root_crate_after(
const std::string& name, const crate& after) override;
track create_track(const track_snapshot& snapshot) override;
std::string directory() override;
void verify() override;
Expand Down
4 changes: 3 additions & 1 deletion src/djinterop/impl/crate_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ class crate_impl
virtual void add_track(track tr) = 0;
virtual std::vector<crate> children() = 0;
virtual void clear_tracks() = 0;
virtual crate create_sub_crate(std::string name) = 0;
virtual crate create_sub_crate(const std::string& name) = 0;
virtual crate create_sub_crate_after(
const std::string& name, const crate& after) = 0;
virtual database db() = 0;
virtual std::vector<crate> descendants() = 0;
virtual bool is_valid() = 0;
Expand Down
4 changes: 3 additions & 1 deletion src/djinterop/impl/database_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ class database_impl
virtual stdx::optional<crate> crate_by_id(int64_t id) = 0;
virtual std::vector<crate> crates() = 0;
virtual std::vector<crate> crates_by_name(const std::string& name) = 0;
virtual crate create_root_crate(std::string name) = 0;
virtual crate create_root_crate(const std::string& name) = 0;
virtual crate create_root_crate_after(
const std::string& name, const crate& after) = 0;
virtual track create_track(const track_snapshot& snapshot) = 0;
virtual std::string directory() = 0;
virtual void verify() = 0;
Expand Down
30 changes: 29 additions & 1 deletion test/djinterop/engine/database_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ namespace e = djinterop::engine;
BOOST_TEST_DECORATOR(* utf::description(
"database::create_root_crate() for all supported schema versions"))
BOOST_DATA_TEST_CASE(
create_root_crate__supported_version__creates, e::all_v1_versions, version)
create_root_crate__supported_version__creates, e::all_versions, version)
{
// Arrange
BOOST_TEST_CHECKPOINT("(" << version << ") Creating temporary database...");
Expand All @@ -55,6 +55,34 @@ BOOST_DATA_TEST_CASE(
BOOST_CHECK(crate.parent() == djinterop::stdx::nullopt);
}

BOOST_TEST_DECORATOR(* utf::description(
"database::create_root_crate_after() for all supported schema versions"))
BOOST_DATA_TEST_CASE(
create_root_crate_after__supported_version__creates, e::all_v2_versions,
version)
{
// Arrange
BOOST_TEST_CHECKPOINT("(" << version << ") Creating temporary database...");
auto db = e::create_temporary_database(version);
auto crate_a = db.create_root_crate("Example Root Crate A");
auto crate_b = db.create_root_crate("Example Root Crate B");
auto crate_d = db.create_root_crate("Example Root Crate D");
auto crate_e = db.create_root_crate("Example Root Crate E");

// Act
BOOST_TEST_CHECKPOINT("(" << version << ") Creating root crate after another...");
auto crate = db.create_root_crate_after("Example Root Crate C", crate_b);

// Assert
auto crates = db.root_crates();
BOOST_CHECK_EQUAL(5, crates.size());
BOOST_CHECK(crates[0].id() == crate_a.id());
BOOST_CHECK(crates[1].id() == crate_b.id());
BOOST_CHECK(crates[2].id() == crate.id());
BOOST_CHECK(crates[3].id() == crate_d.id());
BOOST_CHECK(crates[4].id() == crate_e.id());
}

BOOST_TEST_DECORATOR(* utf::description(
"database::create_track() for all supported schema versions"))
BOOST_DATA_TEST_CASE(
Expand Down

0 comments on commit f34a8fb

Please sign in to comment.