/* 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. 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/simulation/aircraftmodellist.h" #include "blackmisc/simulation/distributorlist.h" #include "blackmisc/aviation/airportlist.h" #include "blackmisc/aviation/liverylist.h" #include "blackmisc/aviation/aircrafticaocodelist.h" #include "blackmisc/aviation/aircraftcategorylist.h" #include "blackmisc/aviation/airlineicaocodelist.h" #include "blackmisc/db/datastoreobjectlist.h" #include "blackmisc/db/dbinfolist.h" #include "blackmisc/db/artifactlist.h" #include "blackmisc/db/distributionlist.h" #include "blackmisc/predicates.h" #include "blackmisc/countrylist.h" #include "blackmisc/json.h" #include "blackmisc/variantprivate.h" #include #include #include #include #include namespace BlackMisc { namespace Db { template IDatastoreObjectList::IDatastoreObjectList() { constexpr bool hasIntegerKey = std::is_base_of::value && std::is_same::value; constexpr bool hasStringKey = std::is_base_of::value && std::is_base_of::value; static_assert(hasIntegerKey || hasStringKey, "ObjectType needs to implement IDatastoreObjectWithXXXXKey and have appropriate KeyType"); } template OBJ IDatastoreObjectList::findByKey(KEYTYPE key, const OBJ ¬Found) const { return this->container().findFirstByOrDefault(&OBJ::getDbKey, key, notFound); } template CONTAINER IDatastoreObjectList::findByKeys(const QSet &keys) const { CONTAINER objects; if (keys.isEmpty()) { return objects; } for (const OBJ &obj : ITimestampObjectList::container()) { if (!keys.contains(obj.getDbKey())) { continue; } objects.push_back(obj); } return objects; } template CONTAINER IDatastoreObjectList::findObjectsWithDbKey() const { CONTAINER objects; for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { continue; } objects.push_back(obj); } return objects; } template CONTAINER IDatastoreObjectList::findObjectsWithoutDbKey() const { CONTAINER objects; for (const OBJ &obj : ITimestampObjectList::container()) { if (obj.hasValidDbKey()) { continue; } objects.push_back(obj); } return objects; } template OBJ IDatastoreObjectList::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 void IDatastoreObjectList::sortByKey() { this->container().sort(BlackMisc::Predicates::MemberLess(&OBJ::getDbKey)); } template QSet IDatastoreObjectList::toDbKeySet() const { QSet keys; for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { continue; } keys.insert(obj.getDbKey()); } return keys; } template QMap IDatastoreObjectList::toDbKeyValueMap() const { QMap map; for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { continue; } map.insert(obj.getDbKey(), obj); } return map; } template QSet IDatastoreObjectList::toDbKeyStringSet() const { QSet keys; for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { continue; } keys.insert(obj.getDbKeyAsString()); } return keys; } template QString IDatastoreObjectList::dbKeysAsString(const QString &separator) const { if (ITimestampObjectList::container().isEmpty()) { return {}; } const QSet keys = IDatastoreObjectList::toDbKeyStringSet(); QString s; for (const QString &k : keys) { if (s.isEmpty()) { s += k; } else { s += separator + k; } } return s; } template KEYTYPE IDatastoreObjectList::getMaxKey(bool *ok) const { QSet keys(this->toDbKeySet()); 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 int IDatastoreObjectList::removeObjectsWithKeys(const QSet &keys) { if (keys.isEmpty()) { return 0; } if (this->container().isEmpty()) { return 0; } CONTAINER newValues; for (const OBJ &obj : ITimestampObjectList::container()) { if (keys.contains(obj.getDbKey())) { continue; } newValues.push_back(obj); } const int delta = this->container().size() - newValues.size(); if (delta > 0) { this->container() = newValues; } return delta; } template int IDatastoreObjectList::removeObjectsWithoutDbKey() { if (this->container().isEmpty()) { return 0; } CONTAINER newValues; for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { continue; } newValues.push_back(obj); } int delta = this->container().size() - newValues.size(); this->container() = newValues; return delta; } template int IDatastoreObjectList::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 QSet keys(container.toDbKeySet()); newValues.removeObjectsWithKeys(keys); int removeSize = newValues.size(); // size after removing data newValues.push_back(container); this->container() = newValues; return newValues.size() - removeSize; } template QDateTime IDatastoreObjectList::oldestDbTimestamp() const { CONTAINER objs(this->container()); objs.removeObjectsWithoutDbKey(); if (objs.isEmpty()) { return QDateTime(); } return objs.oldestDbTimestamp(); } template int IDatastoreObjectList::countWithValidDbKey(bool withKey) const { int count = 0; for (const OBJ &obj : ITimestampObjectList::container()) { if (obj.hasValidDbKey() && withKey) { count++; } } return count; } template int IDatastoreObjectList::countWithValidDbKey() const { return this->countWithValidDbKey(true); } template bool IDatastoreObjectList::containsAnyObjectWithoutKey() const { for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { return true; } } return false; } template bool IDatastoreObjectList::containsDbKey(KEYTYPE key) const { for (const OBJ &obj : ITimestampObjectList::container()) { if (!obj.hasValidDbKey()) { continue; } if (obj.getDbKey() == key) { return true; } } return false; } template CONTAINER IDatastoreObjectList::fromMultipleJsonFormats(const QJsonObject &jsonObject) { // also accept cache format if (jsonObject.isEmpty()) { const CONTAINER c; return c; } // cache or settings format? if (Json::looksLikeSwiftDataObjectJson(jsonObject)) { const QJsonObject cacheObj = Json::swiftDataObjectValue(jsonObject); CONTAINER container; Private::CValueObjectMetaInfoHelper::convertFromMemoizedJson(cacheObj, container, true, 0); // handles both, memoized or "normal" convertFromJson return container; } // plain vanilla container, does not match memoized objects if (Json::looksLikeSwiftContainerJson(jsonObject)) { CONTAINER container; container.convertFromJson(jsonObject); return container; } // still as type/value pair if (Json::looksLikeSwiftTypeValuePairJson(jsonObject)) { const QJsonObject valueObject = jsonObject.value("value").toObject(); CONTAINER container; Private::CValueObjectMetaInfoHelper::convertFromMemoizedJson(valueObject, container, true, 0); // handles both, memoized or "normal" convertFromJson return container; } // DB format, as array if (jsonObject.contains("data")) { return IDatastoreObjectList::fromDatabaseJson(jsonObject.value("data").toArray()); } // no idea what this is throw CJsonException("Unsupported JSON format"); } template CONTAINER IDatastoreObjectList::fromMultipleJsonFormats(const QString &jsonString) { // also accept cache format if (jsonString.isEmpty()) { const CONTAINER c; return c; } const QJsonObject jo = Json::jsonObjectFromString(jsonString, false); return IDatastoreObjectList::fromMultipleJsonFormats(jo); } template QDateTime IDatastoreObjectList::latestDbTimestamp() const { CONTAINER objs(this->container()); objs.removeObjectsWithoutDbKey(); if (objs.isEmpty()) { return QDateTime(); } return objs.latestTimestamp(); } template CONTAINER IDatastoreObjectList::fromDatabaseJson(const QJsonArray &array) { CONTAINER container; for (const QJsonValue &value : array) { container.push_back(OBJ::fromDatabaseJson(value.toObject())); } return container; } template CONTAINER IDatastoreObjectList::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 // https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl //! \cond PRIVATE template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; template class BLACKMISC_EXPORT_DEFINE_TEMPLATE IDatastoreObjectList; //! \endcond } // ns } // ns