ladybird/Userland/Libraries/LibSQL/ValueImpl.h
Jan de Visser 85a84b0794 LibSQL: Introduce Serializer as a mediator between Heap and client code
Classes reading and writing to the data heap would communicate directly
with the Heap object, and transfer ByteBuffers back and forth with it.
This makes things like caching and locking hard. Therefore all data
persistence activity will be funneled through a Serializer object which
in turn submits it to the Heap.

Introducing this unfortunately resulted in a huge amount of churn, in
which a number of smaller refactorings got caught up as well.
2021-08-21 22:03:30 +02:00

298 lines
8.8 KiB
C++

/*
* Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Badge.h>
#include <AK/ByteBuffer.h>
#include <AK/ScopeGuard.h>
#include <AK/String.h>
#include <AK/Variant.h>
#include <LibSQL/Forward.h>
#include <LibSQL/Serializer.h>
#include <LibSQL/TupleDescriptor.h>
#include <LibSQL/Type.h>
#include <string.h>
namespace SQL {
class Value;
class BaseImpl {
public:
explicit BaseImpl(SQLType type = SQLType::Null)
: m_type(type)
{
}
[[nodiscard]] SQLType type() const { return m_type; }
[[nodiscard]] String type_name() const { return SQLType_name(type()); }
private:
SQLType m_type { SQLType::Null };
};
class NullImpl : public BaseImpl {
public:
explicit NullImpl()
: BaseImpl(SQLType::Null)
{
}
[[nodiscard]] static bool is_null() { return true; }
[[nodiscard]] static String to_string() { return "(null)"; }
[[nodiscard]] static Optional<int> to_int() { return {}; }
[[nodiscard]] static Optional<double> to_double() { return {}; }
[[nodiscard]] static Optional<bool> to_bool() { return {}; }
[[nodiscard]] static bool to_vector(Vector<Value>&) { return false; }
static void assign(Value const&) { }
static void assign_string(String const&) { }
static void assign_int(int) { }
static void assign_double(double) { }
static void assign_bool(bool) { }
static void assign_vector(Vector<Value> const&) { }
[[nodiscard]] static size_t length() { return 0; }
[[nodiscard]] static bool can_cast(Value const&);
[[nodiscard]] static int compare(Value const&);
static void serialize(Serializer&) { }
static void deserialize(Serializer&) { }
[[nodiscard]] static u32 hash() { return 0; }
};
template<typename T>
class Impl : public BaseImpl {
public:
[[nodiscard]] bool is_null() const
{
return !m_value.has_value();
}
[[nodiscard]] T const& value() const
{
VERIFY(m_value.has_value());
return m_value.value();
}
[[nodiscard]] size_t length() const
{
return sizeof(T);
}
void serialize(Serializer& serializer) const
{
serializer.serialize(value());
}
void deserialize(Serializer& serializer)
{
T value;
serializer.deserialize_to(value);
m_value = value;
}
protected:
explicit Impl(SQLType sql_type)
: BaseImpl(sql_type)
{
}
Optional<T> m_value {};
};
class TextImpl : public Impl<String> {
public:
explicit TextImpl()
: Impl(SQLType::Text)
{
}
[[nodiscard]] String to_string() const;
[[nodiscard]] Optional<int> to_int() const;
[[nodiscard]] Optional<double> to_double() const;
[[nodiscard]] Optional<bool> to_bool() const;
[[nodiscard]] static bool to_vector(Vector<Value>&) { return false; }
void assign(Value const&);
void assign_string(String const&);
void assign_int(int);
void assign_double(double);
void assign_bool(bool);
void assign_vector(Vector<Value> const&) { m_value = {}; }
[[nodiscard]] size_t length() const;
[[nodiscard]] static bool can_cast(Value const&) { return true; }
[[nodiscard]] int compare(Value const& other) const;
[[nodiscard]] u32 hash() const;
};
class IntegerImpl : public Impl<int> {
public:
IntegerImpl()
: Impl(SQLType::Integer)
{
}
[[nodiscard]] String to_string() const;
[[nodiscard]] Optional<int> to_int() const;
[[nodiscard]] Optional<double> to_double() const;
[[nodiscard]] Optional<bool> to_bool() const;
[[nodiscard]] static bool to_vector(Vector<Value>&) { return false; }
void assign(Value const&);
void assign_string(String const&);
void assign_int(int);
void assign_double(double);
void assign_bool(bool);
void assign_vector(Vector<Value> const&) { m_value = {}; }
[[nodiscard]] static bool can_cast(Value const&);
[[nodiscard]] int compare(Value const& other) const;
[[nodiscard]] u32 hash() const;
};
class FloatImpl : public Impl<double> {
public:
explicit FloatImpl()
: Impl(SQLType::Float)
{
}
[[nodiscard]] String to_string() const;
[[nodiscard]] Optional<int> to_int() const;
[[nodiscard]] Optional<double> to_double() const;
[[nodiscard]] static Optional<bool> to_bool() { return {}; }
[[nodiscard]] static bool to_vector(Vector<Value>&) { return false; }
void assign(Value const&);
void assign_string(String const&);
void assign_int(int);
void assign_double(double);
void assign_bool(bool) { m_value = {}; }
void assign_vector(Vector<Value> const&) { m_value = {}; }
[[nodiscard]] static bool can_cast(Value const&);
[[nodiscard]] int compare(Value const& other) const;
// Using floats in hash functions is a bad idea. Let's disable that for now.
[[nodiscard]] static u32 hash() { VERIFY_NOT_REACHED(); }
};
class BooleanImpl : public Impl<bool> {
public:
explicit BooleanImpl()
: Impl(SQLType::Boolean)
{
}
[[nodiscard]] String to_string() const;
[[nodiscard]] Optional<int> to_int() const;
[[nodiscard]] static Optional<double> to_double();
[[nodiscard]] Optional<bool> to_bool() const;
[[nodiscard]] static bool to_vector(Vector<Value>&) { return false; }
void assign(Value const&);
void assign_string(String const&);
void assign_int(int);
void assign_double(double);
void assign_bool(bool);
void assign_vector(Vector<Value> const&) { m_value = {}; }
[[nodiscard]] static bool can_cast(Value const&);
[[nodiscard]] int compare(Value const& other) const;
[[nodiscard]] u32 hash() const;
};
using BaseTypeImpl = Variant<NullImpl, TextImpl, IntegerImpl, FloatImpl, BooleanImpl>;
class ContainerValueImpl : public Impl<Vector<BaseTypeImpl>> {
public:
virtual ~ContainerValueImpl() = default;
[[nodiscard]] String to_string() const;
[[nodiscard]] static Optional<int> to_int() { return {}; }
[[nodiscard]] static Optional<double> to_double() { return {}; }
[[nodiscard]] static Optional<bool> to_bool() { return {}; }
[[nodiscard]] bool to_vector(Vector<Value>&) const;
void assign_string(String const&) { m_value = {}; }
void assign_int(int) { m_value = {}; }
void assign_double(double) { m_value = {}; }
void assign_bool(bool) { m_value = {}; }
void assign_vector(Vector<Value> const&);
[[nodiscard]] u32 hash() const;
virtual bool validate_before_assignment(Vector<Value> const&) { return true; }
virtual bool validate(BaseTypeImpl const&) { return true; }
virtual bool validate_after_assignment() { return true; }
[[nodiscard]] Vector<String> to_string_vector() const;
[[nodiscard]] size_t length() const;
[[nodiscard]] size_t size() const { return is_null() ? 0 : value().size(); }
bool append(Value const&);
bool append(BaseTypeImpl const& value);
void serialize_values(Serializer&) const;
void deserialize_values(Serializer&);
protected:
explicit ContainerValueImpl(SQLType sql_type)
: Impl(sql_type)
{
}
};
class TupleImpl : public ContainerValueImpl {
public:
explicit TupleImpl(NonnullRefPtr<TupleDescriptor> const& descriptor)
: ContainerValueImpl(SQLType::Tuple)
, m_descriptor(descriptor)
{
}
explicit TupleImpl()
: ContainerValueImpl(SQLType::Tuple)
{
}
void assign(Value const&);
[[nodiscard]] size_t length() const;
[[nodiscard]] bool can_cast(Value const&) const;
[[nodiscard]] int compare(Value const& other) const;
virtual bool validate_before_assignment(Vector<Value> const&) override;
virtual bool validate(BaseTypeImpl const&) override;
virtual bool validate_after_assignment() override;
void serialize(Serializer&) const;
void deserialize(Serializer&);
private:
void infer_descriptor();
void extend_descriptor(Value const&);
RefPtr<TupleDescriptor> m_descriptor;
bool m_descriptor_inferred { false };
};
class ArrayImpl : public ContainerValueImpl {
public:
explicit ArrayImpl(SQLType element_type, Optional<size_t> const& max_size = {})
: ContainerValueImpl(SQLType::Array)
, m_element_type(element_type)
, m_max_size(max_size)
{
}
explicit ArrayImpl()
: ContainerValueImpl(SQLType::Array)
, m_element_type(SQLType::Null)
{
}
void assign(Value const&);
[[nodiscard]] size_t length() const;
[[nodiscard]] bool can_cast(Value const&) const;
[[nodiscard]] int compare(Value const& other) const;
void serialize(Serializer&) const;
void deserialize(Serializer&);
virtual bool validate(BaseTypeImpl const&) override;
private:
SQLType m_element_type { SQLType::Text };
Optional<size_t> m_max_size {};
};
using ValueTypeImpl = Variant<NullImpl, TextImpl, IntegerImpl, FloatImpl, BooleanImpl, TupleImpl, ArrayImpl>;
}