Files
qt-creator/src/libs/sqlite/sqlitevalue.h
Marco Bubke acf5329422 Sqlite: Fix null handling
Most of it is only silencing a warning but one is fixing a faulty test. So
writing null values should now be working.

Change-Id: If702e1fc8176a9e0ae82a5589c719d567929202b
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
2020-06-10 09:05:00 +00:00

336 lines
9.1 KiB
C++

/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sqliteexception.h"
#include <utils/smallstring.h>
#include <utils/variant.h>
#include <QVariant>
#include <cstddef>
#pragma once
namespace Sqlite {
enum class ValueType : unsigned char { Null, Integer, Float, String };
class NullValue
{
friend bool operator==(NullValue, NullValue) { return false; }
};
template<typename StringType>
class ValueBase
{
public:
using VariantType = Utils::variant<NullValue, long long, double, StringType>;
ValueBase() = default;
explicit ValueBase(NullValue) {}
explicit ValueBase(VariantType &&value)
: value(value)
{}
explicit ValueBase(const char *value)
: value(Utils::SmallStringView{value})
{}
explicit ValueBase(long long value)
: value(value)
{}
explicit ValueBase(int value)
: value(static_cast<long long>(value))
{}
explicit ValueBase(uint value)
: value(static_cast<long long>(value))
{}
explicit ValueBase(double value)
: value(value)
{}
explicit ValueBase(Utils::SmallStringView value)
: value(value)
{}
bool isNull() const { return value.index() == 0; }
long long toInteger() const { return Utils::get<int(ValueType::Integer)>(value); }
double toFloat() const { return Utils::get<int(ValueType::Float)>(value); }
Utils::SmallStringView toStringView() const
{
return Utils::get<int(ValueType::String)>(value);
}
explicit operator QVariant() const
{
switch (type()) {
case ValueType::Integer:
return QVariant(toInteger());
case ValueType::Float:
return QVariant(toFloat());
case ValueType::String:
return QVariant(QString(toStringView()));
case ValueType::Null:
break;
}
return {};
}
friend bool operator==(const ValueBase &first, std::nullptr_t) { return first.isNull(); }
friend bool operator==(const ValueBase &first, long long second)
{
auto maybeInteger = Utils::get_if<int(ValueType::Integer)>(&first.value);
return maybeInteger && *maybeInteger == second;
}
friend bool operator==(long long first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, double second)
{
auto maybeInteger = Utils::get_if<int(ValueType::Float)>(&first.value);
return maybeInteger && *maybeInteger == second;
}
friend bool operator==(const ValueBase &first, int second)
{
return first == static_cast<long long>(second);
}
friend bool operator==(int first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, uint second)
{
return first == static_cast<long long>(second);
}
friend bool operator==(uint first, const ValueBase &second) { return second == first; }
friend bool operator==(double first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, Utils::SmallStringView second)
{
auto maybeInteger = Utils::get_if<int(ValueType::String)>(&first.value);
return maybeInteger && *maybeInteger == second;
}
friend bool operator==(Utils::SmallStringView first, const ValueBase &second)
{
return second == first;
}
friend bool operator==(const ValueBase &first, const QString &second)
{
auto maybeInteger = Utils::get_if<int(ValueType::String)>(&first.value);
return maybeInteger
&& second == QLatin1String{maybeInteger->data(), int(maybeInteger->size())};
}
friend bool operator==(const QString &first, const ValueBase &second)
{
return second == first;
}
friend bool operator==(const ValueBase &first, const char *second)
{
return first == Utils::SmallStringView{second};
}
friend bool operator==(const char *first, const ValueBase &second) { return second == first; }
friend bool operator==(const ValueBase &first, const ValueBase &second)
{
return first.value == second.value;
}
friend bool operator!=(const ValueBase &first, const ValueBase &second)
{
return !(first.value == second.value);
}
ValueType type() const
{
switch (value.index()) {
case 0:
return ValueType::Null;
case 1:
return ValueType::Integer;
case 2:
return ValueType::Float;
case 3:
return ValueType::String;
}
return {};
}
public:
VariantType value;
};
class ValueView : public ValueBase<Utils::SmallStringView>
{
public:
explicit ValueView(ValueBase &&base)
: ValueBase(std::move(base))
{}
template<typename Type>
static ValueView create(Type &&value)
{
return ValueView{ValueBase{value}};
}
};
class Value : public ValueBase<Utils::SmallString>
{
using Base = ValueBase<Utils::SmallString>;
public:
using Base::Base;
Value() = default;
explicit Value(NullValue) {}
explicit Value(ValueView view)
: ValueBase(convert(view))
{}
explicit Value(const QVariant &value)
: ValueBase(convert(value))
{}
explicit Value(Utils::SmallString &&value)
: ValueBase(VariantType{std::move(value)})
{}
explicit Value(const Utils::SmallString &value)
: ValueBase(Utils::SmallStringView(value))
{}
explicit Value(const QString &value)
: ValueBase(VariantType{Utils::SmallString(value)})
{}
explicit Value(const std::string &value)
: ValueBase(VariantType{Utils::SmallString(value)})
{}
friend bool operator!=(const Value &first, const Value &second)
{
return !(first.value == second.value);
}
template<typename Type>
friend bool operator!=(const Value &first, const Type &second)
{
return !(first == second);
}
template<typename Type>
friend bool operator!=(const Type &first, const Value &second)
{
return !(first == second);
}
friend bool operator==(const Value &first, const ValueView &second)
{
if (first.type() != second.type())
return false;
switch (first.type()) {
case ValueType::Integer:
return first.toInteger() == second.toInteger();
case ValueType::Float:
return first.toFloat() == second.toFloat();
case ValueType::String:
return first.toStringView() == second.toStringView();
case ValueType::Null:
return false;
}
return false;
}
friend bool operator==(const ValueView &first, const Value &second) { return second == first; }
private:
static Base::VariantType convert(const QVariant &value)
{
if (value.isNull())
return VariantType{NullValue{}};
switch (value.type()) {
case QVariant::Int:
return VariantType{static_cast<long long>(value.toInt())};
case QVariant::LongLong:
return VariantType{value.toLongLong()};
case QVariant::UInt:
return VariantType{static_cast<long long>(value.toUInt())};
case QVariant::Double:
return VariantType{value.toFloat()};
case QVariant::String:
return VariantType{value.toString()};
default:
throw CannotConvert("Cannot convert this QVariant to a ValueBase");
}
}
static Base::VariantType convert(ValueView view)
{
switch (view.type()) {
case ValueType::Null:
return VariantType(NullValue{});
case ValueType::Integer:
return VariantType{view.toInteger()};
case ValueType::Float:
return VariantType{view.toFloat()};
case ValueType::String:
return VariantType{view.toStringView()};
default:
throw CannotConvert("Cannot convert this QVariant to a ValueBase");
}
}
};
using Values = std::vector<Value>;
} // namespace Sqlite