#include "lock_helpers.h"

namespace maps {
namespace wiki {
namespace sync {

namespace {

bool lockImpl(pqxx::transaction_base& work, common::AdvisoryLockIds lockId, LockType lockType, bool tryLock)
{
    std::string advisoryLockFunctionName = tryLock
        ? "pg_try_advisory_xact_lock"
        : "pg_advisory_xact_lock";
    if (lockType == LockType::Shared) {
        advisoryLockFunctionName += "_shared";
    }
    auto query = "SELECT " + advisoryLockFunctionName
        + "(" + std::to_string(static_cast<int64_t>(lockId)) + ")";
    auto r = work.exec(query);
    ASSERT(r.size() == 1);
    if (tryLock) {
        return r[0][0].as<bool>();
    }
    return true;
}

} // namespace

void lockDb(pqxx::transaction_base& work, common::AdvisoryLockIds lockId, LockType lockType)
{
    lockImpl(work, lockId, lockType, false);
}

bool tryLockDb(pqxx::transaction_base& work, common::AdvisoryLockIds lockId, LockType lockType)
{
    return lockImpl(work, lockId, lockType, true);
}

void lockViews(pqxx::transaction_base& work, LockType lockType)
{
    lockImpl(work, common::AdvisoryLockIds::SYNC_VIEW, lockType, false);
}

bool tryLockViews(pqxx::transaction_base& work, LockType lockType)
{
    return lockImpl(work, common::AdvisoryLockIds::SYNC_VIEW, lockType, true);
}

} // namespace sync
} // namespace wiki
} // namespace maps
