mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-14 08:37:03 +08:00
205
src/blackmisc/db/datastore.cpp
Normal file
205
src/blackmisc/db/datastore.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/db/datastore.h"
|
||||
#include "blackmisc/comparefunctions.h"
|
||||
#include "blackmisc/db/datastoreutility.h"
|
||||
#include "blackmisc/icon.h"
|
||||
#include "blackmisc/iconlist.h"
|
||||
#include "blackmisc/icons.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QtGlobal>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
QString IDatastoreObjectWithIntegerKey::getDbKeyAsString() const
|
||||
{
|
||||
if (this->m_dbKey < 0) { return ""; }
|
||||
return QString::number(this->m_dbKey);
|
||||
}
|
||||
|
||||
QString IDatastoreObjectWithIntegerKey::getDbKeyAsStringInParentheses() const
|
||||
{
|
||||
if (this->m_dbKey < 0) { return ""; }
|
||||
return "(" + QString::number(this->m_dbKey) + ")";
|
||||
}
|
||||
|
||||
void IDatastoreObjectWithIntegerKey::setDbKey(const QString &key)
|
||||
{
|
||||
bool ok;
|
||||
int k = key.toInt(&ok);
|
||||
if (!ok) { k = -1; }
|
||||
this->m_dbKey = k;
|
||||
}
|
||||
|
||||
const CIcon &IDatastoreObjectWithIntegerKey::toDatabaseIcon() const
|
||||
{
|
||||
static const CIcon empty;
|
||||
if (this->hasValidDbKey()) { return CIconList::iconByIndex(CIcons::StandardIconDatabaseKey16); }
|
||||
return empty;
|
||||
}
|
||||
|
||||
int IDatastoreObjectWithIntegerKey::stringToDbKey(const QString &candidate)
|
||||
{
|
||||
if (candidate.isEmpty()) { return invalidDbKey(); }
|
||||
bool ok;
|
||||
int k = candidate.toInt(&ok);
|
||||
return ok ? k : invalidDbKey();
|
||||
}
|
||||
|
||||
QJsonValue IDatastoreObjectWithIntegerKey::getDbKeyAsJsonValue() const
|
||||
{
|
||||
if (this->hasValidDbKey()) { return QJsonValue(this->m_dbKey); }
|
||||
return QJsonValue();
|
||||
}
|
||||
|
||||
void IDatastoreObjectWithIntegerKey::setKeyAndTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix)
|
||||
{
|
||||
int dbKey = json.value(prefix + "id").toInt(-1);
|
||||
const QString timestampString(json.value(prefix + "lastupdated").toString());
|
||||
const QDateTime ts(CDatastoreUtility::parseTimestamp(timestampString));
|
||||
this->setDbKey(dbKey);
|
||||
this->setUtcTimestamp(ts);
|
||||
}
|
||||
|
||||
bool IDatastoreObjectWithIntegerKey::existsKey(const QJsonObject &json, const QString &prefix)
|
||||
{
|
||||
return !json.value(prefix + "id").isNull();
|
||||
}
|
||||
|
||||
CVariant IDatastoreObjectWithIntegerKey::propertyByIndex(const CPropertyIndex &index) const
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { return ITimestampBased::propertyByIndex(index); }
|
||||
ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexDbIntegerKey: return CVariant::from(this->m_dbKey);
|
||||
case IndexDatabaseIcon: return CVariant::from(this->toDatabaseIcon());
|
||||
default: break;
|
||||
}
|
||||
return CVariant();
|
||||
}
|
||||
|
||||
void IDatastoreObjectWithIntegerKey::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant)
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { ITimestampBased::setPropertyByIndex(index, variant); return; }
|
||||
ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexDbIntegerKey:
|
||||
this->m_dbKey = variant.toInt();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int IDatastoreObjectWithIntegerKey::comparePropertyByIndex(const CPropertyIndex &index, const IDatastoreObjectWithIntegerKey &compareValue) const
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { return ITimestampBased::comparePropertyByIndex(index, compareValue); }
|
||||
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexDbIntegerKey: return Compare::compare(this->m_dbKey, compareValue.getDbKey());
|
||||
case IndexDatabaseIcon: return Compare::compare(this->hasValidDbKey(), compareValue.hasValidDbKey());
|
||||
default: break;
|
||||
}
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Compare failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IDatastoreObjectWithIntegerKey::canHandleIndex(const BlackMisc::CPropertyIndex &index)
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { return true;}
|
||||
int i = index.frontCasted<int>();
|
||||
return (i >= static_cast<int>(IndexDbIntegerKey)) && (i <= static_cast<int>(IndexDatabaseIcon));
|
||||
}
|
||||
|
||||
QJsonValue IDatastoreObjectWithStringKey::getDbKeyAsJsonValue() const
|
||||
{
|
||||
if (this->hasValidDbKey()) { return QJsonValue(this->m_dbKey); }
|
||||
static const QJsonValue null;
|
||||
return null;
|
||||
}
|
||||
|
||||
const CIcon &IDatastoreObjectWithStringKey::toDatabaseIcon() const
|
||||
{
|
||||
static const CIcon empty;
|
||||
if (this->hasValidDbKey()) { return CIconList::iconByIndex(CIcons::StandardIconDatabaseKey16); }
|
||||
return empty;
|
||||
}
|
||||
|
||||
void IDatastoreObjectWithStringKey::setKeyAndTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix)
|
||||
{
|
||||
QString dbKey = json.value(prefix + "id").toString();
|
||||
QDateTime ts(CDatastoreUtility::parseTimestamp(json.value(prefix + "lastupdated").toString()));
|
||||
this->setDbKey(dbKey);
|
||||
this->setUtcTimestamp(ts);
|
||||
}
|
||||
|
||||
bool IDatastoreObjectWithStringKey::existsKey(const QJsonObject &json, const QString &prefix)
|
||||
{
|
||||
return !json.value(prefix + "id").isNull();
|
||||
}
|
||||
|
||||
CVariant IDatastoreObjectWithStringKey::propertyByIndex(const CPropertyIndex &index) const
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { return ITimestampBased::propertyByIndex(index); }
|
||||
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexDbStringKey: return CVariant::from(this->m_dbKey);
|
||||
case IndexDatabaseIcon: return CVariant::from(this->toDatabaseIcon());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return CVariant();
|
||||
}
|
||||
|
||||
void IDatastoreObjectWithStringKey::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant)
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { ITimestampBased::setPropertyByIndex(index, variant); return; }
|
||||
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexDbStringKey:
|
||||
this->m_dbKey = variant.value<QString>();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int IDatastoreObjectWithStringKey::comparePropertyByIndex(const CPropertyIndex &index, const IDatastoreObjectWithStringKey &compareValue) const
|
||||
{
|
||||
if (ITimestampBased::canHandleIndex(index)) { return ITimestampBased::comparePropertyByIndex(index, compareValue); }
|
||||
const ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexDbStringKey: return this->m_dbKey.compare(compareValue.getDbKey());
|
||||
case IndexDatabaseIcon: return Compare::compare(this->hasValidDbKey(), compareValue.hasValidDbKey());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Compare failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IDatastoreObjectWithStringKey::canHandleIndex(const CPropertyIndex &index)
|
||||
{
|
||||
if (index.isEmpty()) { return false; }
|
||||
if (ITimestampBased::canHandleIndex(index)) { return true;}
|
||||
int i = index.frontCasted<int>();
|
||||
return (i >= static_cast<int>(IndexDbStringKey)) && (i <= static_cast<int>(IndexDatabaseIcon));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
166
src/blackmisc/db/datastore.h
Normal file
166
src/blackmisc/db/datastore.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_DB_DATASTORE_H
|
||||
#define BLACKMISC_DB_DATASTORE_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/timestampbased.h"
|
||||
#include "blackmisc/variant.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CIcon;
|
||||
|
||||
namespace Db
|
||||
{
|
||||
/*!
|
||||
* Class from which a derived class can inherit datastore-related functions.
|
||||
*/
|
||||
class BLACKMISC_EXPORT IDatastoreObjectWithIntegerKey : public ITimestampBased
|
||||
{
|
||||
public:
|
||||
//! Property index
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexDbIntegerKey = CPropertyIndex::GlobalIndexIDatastoreInteger,
|
||||
IndexDatabaseIcon
|
||||
};
|
||||
|
||||
//! Get DB key.
|
||||
int getDbKey() const { return m_dbKey; }
|
||||
|
||||
//! DB key as string
|
||||
QString getDbKeyAsString() const;
|
||||
|
||||
//! Key as JSON value, or null
|
||||
QJsonValue getDbKeyAsJsonValue() const;
|
||||
|
||||
//! Db ley in parentheses, e.g. "(3)"
|
||||
QString getDbKeyAsStringInParentheses() const;
|
||||
|
||||
//! Set the DB key
|
||||
void setDbKey(int key) { m_dbKey = key; }
|
||||
|
||||
//! DB key passed as string
|
||||
void setDbKey(const QString &key);
|
||||
|
||||
//! Has valid DB key
|
||||
bool hasValidDbKey() const { return m_dbKey >= 0; }
|
||||
|
||||
//! Database icon if this has valid key, otherwise empty
|
||||
const CIcon &toDatabaseIcon() const;
|
||||
|
||||
//! Invalid key
|
||||
static int invalidDbKey() { return -1; }
|
||||
|
||||
//! Convert string to DB key
|
||||
static int stringToDbKey(const QString &candidate);
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
IDatastoreObjectWithIntegerKey() {}
|
||||
|
||||
//! Constructor
|
||||
IDatastoreObjectWithIntegerKey(int key) : m_dbKey(key) {}
|
||||
|
||||
//! Set key and timestamp values
|
||||
void setKeyAndTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix = QString());
|
||||
|
||||
//! Is a key available?
|
||||
static bool existsKey(const QJsonObject &json, const QString &prefix = QString());
|
||||
|
||||
//! \copydoc BlackMisc::Mixin::Index::propertyByIndex
|
||||
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
|
||||
|
||||
//! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex
|
||||
void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const CVariant &variant);
|
||||
|
||||
//! Compare by index
|
||||
int comparePropertyByIndex(const CPropertyIndex &index, const IDatastoreObjectWithIntegerKey &compareValue) const;
|
||||
|
||||
//! Can given index be handled?
|
||||
static bool canHandleIndex(const BlackMisc::CPropertyIndex &index);
|
||||
|
||||
int m_dbKey = -1; //!< key
|
||||
};
|
||||
|
||||
/*!
|
||||
* Class from which a derived class can inherit datastore-related functions.
|
||||
*/
|
||||
class BLACKMISC_EXPORT IDatastoreObjectWithStringKey : public ITimestampBased
|
||||
{
|
||||
public:
|
||||
//! Property index
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexDbStringKey = CPropertyIndex::GlobalIndexIDatastoreString,
|
||||
IndexDatabaseIcon
|
||||
};
|
||||
|
||||
//! Get DB key.
|
||||
const QString &getDbKey() const { return m_dbKey; }
|
||||
|
||||
//! Key as JSON value, or null
|
||||
QJsonValue getDbKeyAsJsonValue() const;
|
||||
|
||||
//! Set the DB key
|
||||
void setDbKey(const QString &key) { m_dbKey = key.trimmed().toUpper(); }
|
||||
|
||||
//! Has valid DB key
|
||||
bool hasValidDbKey() const { return !m_dbKey.isEmpty(); }
|
||||
|
||||
//! Database icon if this has valid key, otherwise empty
|
||||
const CIcon &toDatabaseIcon() const;
|
||||
|
||||
//! Invalid key
|
||||
static QString invalidDbKey() { return ""; }
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
IDatastoreObjectWithStringKey() {}
|
||||
|
||||
//! Constructor
|
||||
IDatastoreObjectWithStringKey(const QString &key) : m_dbKey(key) {}
|
||||
|
||||
//! Set key and timestamp values
|
||||
void setKeyAndTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix = QString());
|
||||
|
||||
//! Is a key available?
|
||||
static bool existsKey(const QJsonObject &json, const QString &prefix = QString());
|
||||
|
||||
//! \copydoc BlackMisc::Mixin::Index::propertyByIndex
|
||||
CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
|
||||
|
||||
//! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex
|
||||
void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const CVariant &variant);
|
||||
|
||||
//! Compare by index
|
||||
int comparePropertyByIndex(const BlackMisc::CPropertyIndex &index, const IDatastoreObjectWithStringKey &compareValue) const;
|
||||
|
||||
//! Can given index be handled
|
||||
static bool canHandleIndex(const BlackMisc::CPropertyIndex &index);
|
||||
|
||||
QString m_dbKey; //!< key
|
||||
};
|
||||
} // ns
|
||||
} // ns
|
||||
|
||||
Q_DECLARE_INTERFACE(BlackMisc::Db::IDatastoreObjectWithIntegerKey, "org.swift-project.blackmisc.db.idatastoreobjectwithintegerkey")
|
||||
Q_DECLARE_INTERFACE(BlackMisc::Db::IDatastoreObjectWithStringKey, "org.swift-project.blackmisc.db.idatastoreobjectwithstringkey")
|
||||
|
||||
#endif // guard
|
||||
175
src/blackmisc/db/datastoreobjectlist.cpp
Normal file
175
src/blackmisc/db/datastoreobjectlist.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/db/datastoreobjectlist.h"
|
||||
#include "blackmisc/predicates.h"
|
||||
#include "blackmisc/countrylist.h"
|
||||
#include "blackmisc/aviation/liverylist.h"
|
||||
#include "blackmisc/aviation/aircrafticaocodelist.h"
|
||||
#include "blackmisc/aviation/airlineicaocodelist.h"
|
||||
#include "blackmisc/db/dbinfolist.h"
|
||||
#include "blackmisc/simulation/aircraftmodellist.h"
|
||||
#include "blackmisc/simulation/distributorlist.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::IDatastoreObjectList()
|
||||
{
|
||||
constexpr bool hasIntegerKey = std::is_base_of<IDatastoreObjectWithIntegerKey, OBJ>::value && std::is_same<int, KEYTYPE>::value;
|
||||
constexpr bool hasStringKey = std::is_base_of<IDatastoreObjectWithStringKey, OBJ>::value && std::is_base_of<QString, KEYTYPE>::value;
|
||||
static_assert(hasIntegerKey || hasStringKey, "ObjectType needs to implement IDatastoreObjectWithXXXXKey and have appropriate KeyType");
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
OBJ IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::findByKey(KEYTYPE key, const OBJ ¬Found) const
|
||||
{
|
||||
return this->container().findFirstByOrDefault(&OBJ::getDbKey, key, notFound);
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
OBJ IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::maxKeyObject() const
|
||||
{
|
||||
if (this->container().isEmpty()) { return OBJ(); }
|
||||
const OBJ max = *std::max_element(this->container().begin(), this->container().end(), [](const OBJ & obj1, const OBJ & obj2)
|
||||
{
|
||||
bool v1 = obj1.hasValidDbKey();
|
||||
bool v2 = obj2.hasValidDbKey();
|
||||
if (v1 && v2)
|
||||
{
|
||||
return obj1.getDbKey() < obj2.getDbKey();
|
||||
}
|
||||
return v2;
|
||||
});
|
||||
return max;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
void IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::sortByKey()
|
||||
{
|
||||
this->container().sort(BlackMisc::Predicates::MemberLess(&OBJ::getDbKey));
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
QList<KEYTYPE> IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::toDbKeyList() const
|
||||
{
|
||||
QList<KEYTYPE> keys;
|
||||
for (const OBJ &obj : ITimestampObjectList<OBJ, CONTAINER>::container())
|
||||
{
|
||||
if (!obj.hasValidDbKey()) { continue; }
|
||||
keys.append(obj.getDbKey());
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
KEYTYPE IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::getMaxKey(bool *ok) const
|
||||
{
|
||||
QList<KEYTYPE> keys(this->toDbKeyList());
|
||||
if (keys.isEmpty())
|
||||
{
|
||||
if (ok) { *ok = false; }
|
||||
return KEYTYPE();
|
||||
}
|
||||
KEYTYPE max = *std::max_element(keys.begin(), keys.end());
|
||||
if (ok) { *ok = true; }
|
||||
return max;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
int IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::removeObjectsWithKeys(const QList<KEYTYPE> &keys)
|
||||
{
|
||||
if (keys.isEmpty()) { return 0; }
|
||||
if (this->container().isEmpty()) { return 0; }
|
||||
CONTAINER newValues;
|
||||
for (const OBJ &obj : ITimestampObjectList<OBJ, CONTAINER>::container())
|
||||
{
|
||||
if (keys.contains(obj.getDbKey())) { continue; }
|
||||
newValues.push_back(obj);
|
||||
}
|
||||
int delta = this->container().size() - newValues.size();
|
||||
this->container() = newValues;
|
||||
return delta;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
int IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::removeObjectsWithoutDbKey()
|
||||
{
|
||||
if (this->container().isEmpty()) { return 0; }
|
||||
CONTAINER newValues;
|
||||
for (const OBJ &obj : ITimestampObjectList<OBJ, CONTAINER>::container())
|
||||
{
|
||||
if (!obj.hasValidDbKey()) { continue; }
|
||||
newValues.push_back(obj);
|
||||
}
|
||||
int delta = this->container().size() - newValues.size();
|
||||
this->container() = newValues;
|
||||
return delta;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
int IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::replaceOrAddObjectsByKey(const CONTAINER &container)
|
||||
{
|
||||
if (container.isEmpty()) { return 0; }
|
||||
if (this->container().isEmpty())
|
||||
{
|
||||
this->container() = container;
|
||||
return this->container().size();
|
||||
}
|
||||
CONTAINER newValues(this->container());
|
||||
const QList<KEYTYPE> keys(container.toDbKeyList());
|
||||
newValues.removeObjectsWithKeys(keys);
|
||||
int removeSize = newValues.size(); // size after removing data
|
||||
newValues.push_back(container);
|
||||
this->container() = newValues;
|
||||
return newValues.size() - removeSize;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
CONTAINER IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::fromDatabaseJson(const QJsonArray &array)
|
||||
{
|
||||
CONTAINER container;
|
||||
for (const QJsonValue &value : array)
|
||||
{
|
||||
container.push_back(OBJ::fromDatabaseJson(value.toObject()));
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER, typename KEYTYPE>
|
||||
CONTAINER IDatastoreObjectList<OBJ, CONTAINER, KEYTYPE>::fromDatabaseJson(const QJsonArray &array, const QString &prefix)
|
||||
{
|
||||
CONTAINER container;
|
||||
for (const QJsonValue &value : array)
|
||||
{
|
||||
container.push_back(OBJ::fromDatabaseJson(value.toObject(), prefix));
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
|
||||
template class IDatastoreObjectList<BlackMisc::Aviation::CLivery, BlackMisc::Aviation::CLiveryList, int>;
|
||||
template class IDatastoreObjectList<BlackMisc::Aviation::CAircraftIcaoCode, BlackMisc::Aviation::CAircraftIcaoCodeList, int>;
|
||||
template class IDatastoreObjectList<BlackMisc::Aviation::CAirlineIcaoCode, BlackMisc::Aviation::CAirlineIcaoCodeList, int>;
|
||||
template class IDatastoreObjectList<BlackMisc::Db::CDbInfo, BlackMisc::Db::CDbInfoList, int>;
|
||||
template class IDatastoreObjectList<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList, int>;
|
||||
template class IDatastoreObjectList<BlackMisc::Simulation::CDistributor, BlackMisc::Simulation::CDistributorList, QString>;
|
||||
template class IDatastoreObjectList<BlackMisc::CCountry, BlackMisc::CCountryList, QString>;
|
||||
|
||||
} // ns
|
||||
} // ns
|
||||
95
src/blackmisc/db/datastoreobjectlist.h
Normal file
95
src/blackmisc/db/datastoreobjectlist.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_DB_DATABASEOBJECTLIST_H
|
||||
#define BLACKMISC_DB_DATABASEOBJECTLIST_H
|
||||
|
||||
#include "blackmisc/timestampobjectlist.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
//! List of objects read from database.
|
||||
//! Such objects should implement \sa ITimestampBased and \sa IDatastoreObjectWithIntegerKey or \sa IDatastoreObjectWithStringKey
|
||||
template<class OBJ, class CONTAINER, typename KEYTYPE> class IDatastoreObjectList : public ITimestampObjectList<OBJ, CONTAINER>
|
||||
{
|
||||
public:
|
||||
//! Object with key, notFound otherwise
|
||||
OBJ findByKey(KEYTYPE key, const OBJ ¬Found = OBJ()) const;
|
||||
|
||||
//! Object with max.key
|
||||
OBJ maxKeyObject() const;
|
||||
|
||||
//! Sort by timestamp
|
||||
void sortByKey();
|
||||
|
||||
//! All keys as list
|
||||
QList<KEYTYPE> toDbKeyList() const;
|
||||
|
||||
//! Max.key value (making sense with integer key)
|
||||
KEYTYPE getMaxKey(bool *ok = nullptr) const;
|
||||
|
||||
//! Remove objects with key
|
||||
int removeObjectsWithKeys(const QList<KEYTYPE> &keys);
|
||||
|
||||
//! Remove objects without key
|
||||
int removeObjectsWithoutDbKey();
|
||||
|
||||
//! Update or insert data (based on DB key)
|
||||
int replaceOrAddObjectsByKey(const CONTAINER &container);
|
||||
|
||||
//! From DB JSON with default prefixes
|
||||
static CONTAINER fromDatabaseJson(const QJsonArray &array);
|
||||
|
||||
//! From DB JSON
|
||||
static CONTAINER fromDatabaseJson(const QJsonArray &array, const QString &prefix);
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
IDatastoreObjectList();
|
||||
};
|
||||
|
||||
//! \cond PRIVATE
|
||||
class CDbInfo;
|
||||
class CDbInfoList;
|
||||
|
||||
namespace Aviation
|
||||
{
|
||||
class CLivery;
|
||||
class CLiveryList;
|
||||
}
|
||||
|
||||
namespace Simulation
|
||||
{
|
||||
class CDistributor;
|
||||
class CDistributorList;
|
||||
class CAircraftModel;
|
||||
class CAircraftModelList;
|
||||
}
|
||||
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::Aviation::CLivery, BlackMisc::Aviation::CLiveryList, int>;
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::Aviation::CAircraftIcaoCode, BlackMisc::Aviation::CAircraftIcaoCodeList, int>;
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::Aviation::CAirlineIcaoCode, BlackMisc::Aviation::CAirlineIcaoCodeList, int>;
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::Db::CDbInfo, BlackMisc::Db::CDbInfoList, int>;
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::Simulation::CAircraftModel, BlackMisc::Simulation::CAircraftModelList, int>;
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::Simulation::CDistributor, BlackMisc::Simulation::CDistributorList, QString>;
|
||||
extern template class BLACKMISC_EXPORT_TEMPLATE IDatastoreObjectList<BlackMisc::CCountry, BlackMisc::CCountryList, QString>;
|
||||
//! \endcond
|
||||
|
||||
} // ns
|
||||
} //ns
|
||||
|
||||
#endif //guard
|
||||
150
src/blackmisc/db/datastoreutility.cpp
Normal file
150
src/blackmisc/db/datastoreutility.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/db/datastoreutility.h"
|
||||
#include "blackmisc/logcategory.h"
|
||||
#include "blackmisc/logcategorylist.h"
|
||||
#include "blackmisc/simulation/aircraftmodellist.h"
|
||||
#include "blackmisc/statusmessage.h"
|
||||
#include "blackmisc/statusmessagelist.h"
|
||||
#include "blackmisc/stringutils.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QRegExp>
|
||||
#include <QTimeZone>
|
||||
|
||||
using namespace BlackMisc;
|
||||
using namespace BlackMisc::Simulation;
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
bool CDatastoreUtility::dbBoolStringToBool(const QString &dbBool)
|
||||
{
|
||||
return BlackMisc::stringToBool(dbBool);
|
||||
}
|
||||
|
||||
const QString &CDatastoreUtility::boolToDbYN(bool v)
|
||||
{
|
||||
static const QString y("Y");
|
||||
static const QString n("N");
|
||||
return v ? y : n;
|
||||
}
|
||||
|
||||
int CDatastoreUtility::extractIntegerKey(const QString &stringWithKey)
|
||||
{
|
||||
QString ks(stringWithKey.trimmed());
|
||||
if (ks.isEmpty()) { return -1; }
|
||||
bool ok = false;
|
||||
int key = ks.toInt(&ok);
|
||||
if (ok) { return key; } // only a number
|
||||
|
||||
// key in string with ()
|
||||
int i1 = ks.lastIndexOf('(');
|
||||
if (i1 < 0) { return -1; }
|
||||
int i2 = ks.lastIndexOf(')');
|
||||
if (i2 <= i1 + 1) { return -1;}
|
||||
QString n(ks.mid(i1 + 1, i2 - i1 - 1));
|
||||
ok = false;
|
||||
key = n.toInt(&ok);
|
||||
return ok ? key : -1;
|
||||
}
|
||||
|
||||
QDateTime CDatastoreUtility::parseTimestamp(const QString ×tamp)
|
||||
{
|
||||
if (!timestamp.isEmpty())
|
||||
{
|
||||
QString ts(timestamp.trimmed().remove(' ').remove('-').remove(':')); // normalize
|
||||
QDateTime dt = QDateTime::fromString(ts, "yyyyMMddHHmmss");
|
||||
dt.setTimeZone(QTimeZone::utc());
|
||||
return dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
return QDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
bool CDatastoreUtility::parseSwiftPublishResponse(const QString &jsonResponse, CAircraftModelList &publishedModels, CAircraftModelList &skippedModels, CStatusMessageList &messages)
|
||||
{
|
||||
static const CLogCategoryList cats({ CLogCategory::swiftDbWebservice()});
|
||||
if (jsonResponse.isEmpty())
|
||||
{
|
||||
messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Empty JSON data"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonResponse.toUtf8()));
|
||||
|
||||
// array of messages
|
||||
if (jsonDoc.isArray())
|
||||
{
|
||||
CStatusMessageList msgs(CStatusMessageList::fromDatabaseJson(jsonDoc.array()));
|
||||
messages.push_back(msgs);
|
||||
return true;
|
||||
}
|
||||
|
||||
// no object -> most likely some fucked up HTML string with the PHP error
|
||||
if (!jsonDoc.isObject())
|
||||
{
|
||||
QString phpError(jsonResponse);
|
||||
phpError.remove(QRegExp("<[^>]*>"));
|
||||
messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, phpError));
|
||||
return false;
|
||||
}
|
||||
|
||||
// fully blown object
|
||||
QJsonObject json(jsonDoc.object());
|
||||
bool data = false;
|
||||
if (json.contains("msgs"))
|
||||
{
|
||||
QJsonValue msgJson(json.take("msgs"));
|
||||
CStatusMessageList msgs(CStatusMessageList::fromDatabaseJson(msgJson.toArray()));
|
||||
if (!msgs.isEmpty())
|
||||
{
|
||||
messages.push_back(msgs);
|
||||
data = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains("publishedModels"))
|
||||
{
|
||||
QJsonValue publishedJson(json.take("publishedModels"));
|
||||
CAircraftModelList published = CAircraftModelList::fromDatabaseJson(publishedJson.toArray(), "");
|
||||
if (!published.isEmpty())
|
||||
{
|
||||
publishedModels.push_back(published);
|
||||
data = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains("skippedModels"))
|
||||
{
|
||||
QJsonValue skippedJson(json.take("skippedModels"));
|
||||
CAircraftModelList skipped = CAircraftModelList::fromDatabaseJson(skippedJson.toArray(), "");
|
||||
if (!skipped.isEmpty())
|
||||
{
|
||||
skippedModels.push_back(skipped);
|
||||
data = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data)
|
||||
{
|
||||
messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Received response, but no JSON data"));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
} // ns
|
||||
} // ns
|
||||
54
src/blackmisc/db/datastoreutility.h
Normal file
54
src/blackmisc/db/datastoreutility.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_DB_DATASTOREUTILITY_H
|
||||
#define BLACKMISC_DB_DATASTOREUTILITY_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QString>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
class CStatusMessageList;
|
||||
namespace Simulation { class CAircraftModelList; }
|
||||
|
||||
namespace Db
|
||||
{
|
||||
/*!
|
||||
* Class with datastore related utilities
|
||||
*/
|
||||
class BLACKMISC_EXPORT CDatastoreUtility
|
||||
{
|
||||
public:
|
||||
//! No constructor
|
||||
CDatastoreUtility() = delete;
|
||||
|
||||
//! DB Bool value to bool
|
||||
static bool dbBoolStringToBool(const QString &dbBool);
|
||||
|
||||
//! Bool to DB yes/no
|
||||
static const QString &boolToDbYN(bool v);
|
||||
|
||||
//! Extract key from string like "MyAircraft (33)"
|
||||
static int extractIntegerKey(const QString &stringWithKey);
|
||||
|
||||
//! Parse a timestamp object
|
||||
static QDateTime parseTimestamp(const QString ×tamp);
|
||||
|
||||
//! Get data from a DB response
|
||||
static bool parseSwiftPublishResponse(const QString &jsonResponse, BlackMisc::Simulation::CAircraftModelList &publishedModels, BlackMisc::Simulation::CAircraftModelList &skippedModels, BlackMisc::CStatusMessageList &messages);
|
||||
};
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#endif // guard
|
||||
Reference in New Issue
Block a user