Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions src/Wt/Dbo/Field.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ namespace Wt {
template <class C> class collection;

namespace Impl {
const int FKNotNull = 0x01;
const int FKOnUpdateCascade = 0x02;
const int FKOnUpdateSetNull = 0x04;
const int FKOnDeleteCascade = 0x08;
const int FKOnDeleteSetNull = 0x10;
const int FKNotNull = 0x01;
const int FKOnUpdateCascade = 0x02;
const int FKOnUpdateSetNull = 0x04;
const int FKOnUpdateRestrict = 0x08;
const int FKOnDeleteCascade = 0x10;
const int FKOnDeleteSetNull = 0x20;
const int FKOnDeleteRestrict = 0x40;
}

/*! \brief Type that indicates one or more foreign key constraints.
Expand All @@ -31,8 +33,10 @@ const int FKOnDeleteSetNull = 0x10;
* \sa \link Wt::Dbo::NotNull NotNull\endlink
* \sa \link Wt::Dbo::OnUpdateCascade OnUpdateCascade\endlink,
* \link Wt::Dbo::OnUpdateSetNull OnUpdateSetNull\endlink
* \link Wt::Dbo::OnUpdateRestrict OnUpdateRestrict\endlink
* \sa \link Wt::Dbo::OnDeleteCascade OnDeleteCascade\endlink
* \link Wt::Dbo::OnDeleteSetNull OnDeleteSetNull\endlink
* \link Wt::Dbo::OnDeleteRestrict OnDeleteRestrict\endlink
*
* \sa belongsTo(), hasMany()
*
Expand Down Expand Up @@ -105,6 +109,23 @@ const ForeignKeyConstraint OnUpdateSetNull;
const ForeignKeyConstraint OnUpdateSetNull(Impl::FKOnUpdateSetNull);
#endif

/*! \brief A constraint that restricts updates.
*
* A database constraint which restricts updates to the natural primary key
* in the referenced table.
*
* \note This constraint only affects the database schema creation. Currently
* it is not possible to update a natural Id of an already saved object
* through %Dbo itself.
*
* \ingroup dbo
*/
#ifdef DOXYGEN_ONLY
const ForeignKeyConstraint OnUpdateRestrict;
#else
const ForeignKeyConstraint OnUpdateRestrict(Impl::FKOnUpdateRestrict);
#endif

/*! \brief A constraint that cascades deletes.
*
* A database constraint which propagates deletes of the referenced object
Expand Down Expand Up @@ -135,6 +156,21 @@ const ForeignKeyConstraint OnDeleteSetNull;
const ForeignKeyConstraint OnDeleteSetNull(Impl::FKOnDeleteSetNull);
#endif

/*! \brief A constraint that restricts deletes.
*
* A database constraint which restricts deletes of the referenced object
* to also restrict deletion of the objects that reference.
*
* \note This constraint only affects the database schema creation.
*
* \ingroup dbo
*/
#ifdef DOXYGEN_ONLY
const ForeignKeyConstraint OnDeleteRestrict;
#else
const ForeignKeyConstraint OnDeleteRestrict(Impl::FKOnDeleteRestrict);
#endif

class Session;
class SqlStatement;

Expand Down
5 changes: 5 additions & 0 deletions src/Wt/Dbo/Session.C
Original file line number Diff line number Diff line change
Expand Up @@ -908,11 +908,16 @@ std::string Session::constraintString(Impl::MappingInfo *mapping,
else if (field.fkConstraints() & Impl::FKOnUpdateSetNull
&& haveSupportUpdateCascade_)
sql << " on update set null";
else if (field.fkConstraints() & Impl::FKOnUpdateRestrict
&& haveSupportUpdateCascade_)
sql << " on update restrict";

if (field.fkConstraints() & Impl::FKOnDeleteCascade)
sql << " on delete cascade";
else if (field.fkConstraints() & Impl::FKOnDeleteSetNull)
sql << " on delete set null";
else if (field.fkConstraints() & Impl::FKOnDeleteRestrict)
sql << " on delete restrict";

if (connection(false)->supportDeferrableFKConstraint()) //backend condition
sql << " deferrable initially deferred";
Expand Down
74 changes: 74 additions & 0 deletions test/dbo/DboTest8.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#define BOOST_TEST_MODULE Foreign Key Constraint

#include <boost/test/included/unit_test.hpp>
#include <Wt/Dbo/backend/Sqlite3.h>
#include <Wt/Dbo/Dbo.h>
#include <algorithm>

namespace dbo = Wt::Dbo;

class TableSrc1
{
public:

template<typename Action>
void persist([[maybe_unused]] Action &a)
{
}
};

class TableSrc2
{
public:

template<typename Action>
void persist([[maybe_unused]] Action &a)
{
}
};

class TableDst
{
public:
dbo::ptr<TableSrc1> table_src1;
dbo::ptr<TableSrc2> table_src2;

template<typename Action>
void persist(Action &a)
{
dbo::belongsTo(a, table_src1, dbo::OnDeleteRestrict);
dbo::belongsTo(a, table_src2, dbo::OnUpdateRestrict);
}
};

BOOST_AUTO_TEST_CASE(foreign_key_constraints_test)
{
dbo::Session session;
auto conn = std::make_unique<dbo::backend::Sqlite3>(":memory:");
session.setConnection(std::move(conn));

session.mapClass<TableSrc1>("table_src1");
session.mapClass<TableSrc2>("table_src2");
session.mapClass<TableDst>("table_dst");

auto sql = session.tableCreationSql();

std::string needle_del_restrict = "on delete restrict";
const auto it_del_restrict = std::search(begin(sql), end(sql), begin(needle_del_restrict), end(needle_del_restrict));
BOOST_REQUIRE((it_del_restrict != cend(sql)));

std::string needle_update_restrict = "on update restrict";
const auto it_update_restrict = std::search(begin(sql), end(sql), begin(needle_update_restrict), end(needle_update_restrict));
BOOST_REQUIRE((it_update_restrict != cend(sql)));

try
{
session.createTables();
BOOST_REQUIRE(true);
}
catch(...)
{
BOOST_REQUIRE(false);
}

}