Просмотр исходного кода

LibSQL: Rewrite the SQL::Value type to be contained within one class

Currently, the Value class is essentially a "pImpl" wrapper around the
ValueImpl hierarchy of classes. This is a bit difficult to follow and
reason about, as methods jump between the Value class and its impl
classes.

This changes the Variant held by Value to instead store the specified
types (String, int, etc.) directly. In doing so, the ValueImpl classes
are removed, and all methods are now just concise Variant visitors.

As part of this rewrite, support for the "array" type is dropped (or
rather, just not re-implemented) as it was unused. If it's needed in the
future, support can be re-added.

This does retain the ability for non-NULL types to store NULL values
(i.e. an empty Optional). I tried dropping this support as well, but it
is depended upon by the on-disk storage classes in non-trivial ways.
Timothy Flynn 2 лет назад
Родитель
Сommit
1524288127

+ 198 - 191
Tests/LibSQL/TestSqlValueAndTuple.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
+ * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -15,121 +16,170 @@
 TEST_CASE(null_value)
 {
     SQL::Value v(SQL::SQLType::Null);
-    EXPECT(v.type() == SQL::SQLType::Null);
-    EXPECT(v.is_null());
-    v = "Test";
+    EXPECT_EQ(v.type(), SQL::SQLType::Null);
+    EXPECT_EQ(v.to_string(), "(null)"sv);
+    EXPECT(!v.to_bool().has_value());
+    EXPECT(!v.to_int().has_value());
+    EXPECT(!v.to_u32().has_value());
+    EXPECT(!v.to_double().has_value());
+}
+
+TEST_CASE(assign_null)
+{
+    SQL::Value v("Test");
+    EXPECT_EQ(v.type(), SQL::SQLType::Text);
+    EXPECT(!v.is_null());
+
+    v = SQL::Value();
+    EXPECT_EQ(v.type(), SQL::SQLType::Null);
     EXPECT(v.is_null());
-    EXPECT(v.to_string() == "(null)");
 }
 
 TEST_CASE(text_value)
 {
     {
         SQL::Value v(SQL::SQLType::Text);
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
         EXPECT(v.is_null());
-        v = "Test";
-        EXPECT(!v.is_null());
-        EXPECT(v.to_string() == "Test");
-    }
-    {
-        SQL::Value v(SQL::SQLType::Text, String("String Test"));
-        EXPECT(!v.is_null());
-        EXPECT(v.to_string() == "String Test");
-    }
-    {
-        SQL::Value v(SQL::SQLType::Text, "const char * Test");
-        EXPECT(!v.is_null());
-        EXPECT_EQ(v.to_string(), "const char * Test");
+
+        v = "Test"sv;
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+        EXPECT_EQ(v.to_string(), "Test"sv);
     }
     {
-        SQL::Value v(String("String Test"));
-        EXPECT(v.type() == SQL::SQLType::Text);
-        EXPECT(!v.is_null());
-        EXPECT(v.to_string() == "String Test");
+        SQL::Value v(String("String Test"sv));
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+        EXPECT_EQ(v.to_string(), "String Test"sv);
+
+        v = String("String Test 2"sv);
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+        EXPECT_EQ(v.to_string(), "String Test 2"sv);
     }
     {
-        SQL::Value v(SQL::SQLType::Text, SQL::Value(42));
-        EXPECT(v.type() == SQL::SQLType::Text);
-        EXPECT(!v.is_null());
-        EXPECT(v.to_string() == "42");
-    }
-}
+        SQL::Value v("const char * Test");
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+        EXPECT_EQ(v.to_string(), "const char * Test"sv);
 
-TEST_CASE(assign_null)
-{
-    SQL::Value v("Test");
-    EXPECT(!v.is_null());
-    v = SQL::Value::null();
-    EXPECT(v.is_null());
+        v = "const char * Test 2";
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+        EXPECT_EQ(v.to_string(), "const char * Test 2"sv);
+    }
 }
 
 TEST_CASE(text_value_to_other_types)
 {
     {
-        SQL::Value v(SQL::SQLType::Text, "42");
+        SQL::Value v("42");
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+
         EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 42);
+
         EXPECT(v.to_double().has_value());
-        EXPECT(v.to_double().value() - 42.0 < NumericLimits<double>().epsilon());
+        EXPECT((v.to_double().value() - 42.0) < NumericLimits<double>().epsilon());
     }
     {
         SQL::Value v("true");
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+
         EXPECT(v.to_bool().has_value());
         EXPECT(v.to_bool().value());
     }
     {
         SQL::Value v("false");
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+
         EXPECT(v.to_bool().has_value());
         EXPECT(!v.to_bool().value());
     }
+    {
+        SQL::Value v("foo");
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+
+        EXPECT(!v.to_bool().has_value());
+        EXPECT(!v.to_int().has_value());
+        EXPECT(!v.to_u32().has_value());
+        EXPECT(!v.to_double().has_value());
+    }
+    {
+        SQL::Value v("3.14");
+        EXPECT_EQ(v.type(), SQL::SQLType::Text);
+
+        EXPECT(v.to_double().has_value());
+        EXPECT((v.to_double().value() - 3.14) < NumericLimits<double>().epsilon());
+    }
+}
+
+TEST_CASE(assign_int_to_text_value)
+{
+    SQL::Value v(SQL::SQLType::Text);
+    EXPECT_EQ(v.type(), SQL::SQLType::Text);
+    EXPECT(v.is_null());
+
+    v = 42;
+    EXPECT_EQ(v.type(), SQL::SQLType::Integer);
+    EXPECT_EQ(v, 42);
 }
 
 TEST_CASE(serialize_text_value)
 {
     SQL::Value v("Test");
-    EXPECT(v.to_string() == "Test");
+    EXPECT_EQ(v.type(), SQL::SQLType::Text);
+    EXPECT_EQ(v, "Test"sv);
 
     SQL::Serializer serializer;
     serializer.serialize<SQL::Value>(v);
 
     serializer.rewind();
     auto v2 = serializer.deserialize<SQL::Value>();
-    EXPECT(v2.to_string() == "Test");
+    EXPECT_EQ(v2.type(), SQL::SQLType::Text);
+    EXPECT_EQ(v2, "Test"sv);
+    EXPECT_EQ(v2, v);
 }
 
 TEST_CASE(integer_value)
 {
     {
         SQL::Value v(SQL::SQLType::Integer);
+        EXPECT_EQ(v.type(), SQL::SQLType::Integer);
         EXPECT(v.is_null());
+
         v = 42;
-        EXPECT(!v.is_null());
-        EXPECT(v.to_int().value() == 42);
-        EXPECT(v.to_string() == "42");
+        EXPECT_EQ(v.type(), SQL::SQLType::Integer);
+
+        EXPECT(v.to_int().has_value());
+        EXPECT_EQ(v.to_int().value(), 42);
+        EXPECT_EQ(v.to_string(), "42"sv);
+
         EXPECT(v.to_double().has_value());
-        EXPECT(v.to_double().value() - 42.0 < NumericLimits<double>().epsilon());
+        EXPECT((v.to_double().value() - 42.0) < NumericLimits<double>().epsilon());
+
         EXPECT(v.to_bool().has_value());
         EXPECT(v.to_bool().value());
     }
     {
         SQL::Value v(0);
-        EXPECT(!v.is_null());
-        EXPECT(v.to_int().value() == 0);
+        EXPECT_EQ(v.type(), SQL::SQLType::Integer);
+
+        EXPECT(v.to_int().has_value());
+        EXPECT_EQ(v.to_int().value(), 0);
+
         EXPECT(v.to_bool().has_value());
         EXPECT(!v.to_bool().value());
     }
     {
-        SQL::Value v(SQL::SQLType::Integer, "42");
-        EXPECT_EQ(v.to_int().value(), 42);
-    }
-    {
-        SQL::Value v(SQL::SQLType::Integer, SQL::Value("42"));
+        SQL::Value v(42);
+        EXPECT_EQ(v.type(), SQL::SQLType::Integer);
+
+        EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 42);
     }
     {
         SQL::Value text("42");
         SQL::Value integer(SQL::SQLType::Integer);
         integer = text;
+
+        EXPECT(integer.to_int().has_value());
         EXPECT_EQ(integer.to_int().value(), 42);
     }
 }
@@ -138,66 +188,77 @@ TEST_CASE(serialize_int_value)
 {
     SQL::Value v(42);
     EXPECT_EQ(v.type(), SQL::SQLType::Integer);
-    EXPECT_EQ(v.to_int().value(), 42);
+    EXPECT_EQ(v, 42);
 
     SQL::Serializer serializer;
     serializer.serialize<SQL::Value>(v);
 
     serializer.rewind();
     auto v2 = serializer.deserialize<SQL::Value>();
-    EXPECT(!v2.is_null());
     EXPECT_EQ(v2.type(), SQL::SQLType::Integer);
-    EXPECT_EQ(v2.to_int().value(), 42);
-    EXPECT(v2 == v);
+    EXPECT_EQ(v2, 42);
+    EXPECT_EQ(v2, v);
 }
 
 TEST_CASE(float_value)
 {
     {
         SQL::Value v(SQL::SQLType::Float);
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
         EXPECT(v.is_null());
+
         v = 3.14;
-        EXPECT(!v.is_null());
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
+
         EXPECT(v.to_double().has_value());
-        EXPECT(v.to_double().value() - 3.14 < NumericLimits<double>().epsilon());
+        EXPECT((v.to_double().value() - 3.14) < NumericLimits<double>().epsilon());
+
         EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 3);
         EXPECT_EQ(v.to_string(), "3.14");
+
         EXPECT(v.to_bool().has_value());
         EXPECT(v.to_bool().value());
 
         v = 0.0;
-        EXPECT(!v.is_null());
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
+
         EXPECT(v.to_double().has_value());
         EXPECT(v.to_double().value() < NumericLimits<double>().epsilon());
+
         EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 0);
-        EXPECT_EQ(v.to_string(), "0");
+        EXPECT_EQ(v.to_string(), "0"sv);
+
         EXPECT(v.to_bool().has_value());
         EXPECT(!v.to_bool().value());
     }
     {
         SQL::Value v(3.14);
-        EXPECT(!v.is_null());
-        EXPECT(v.to_double().value() - 3.14 < NumericLimits<double>().epsilon());
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
+        EXPECT((v.to_double().value() - 3.14) < NumericLimits<double>().epsilon());
     }
     {
         SQL::Value v(3.51);
-        EXPECT(!v.is_null());
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
+
+        EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 4);
     }
     {
         SQL::Value v(-3.14);
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
+
+        EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), -3);
     }
     {
         SQL::Value v(-3.51);
+        EXPECT_EQ(v.type(), SQL::SQLType::Float);
+
+        EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), -4);
     }
-    {
-        SQL::Value v(SQL::SQLType::Float, "3.14");
-        EXPECT(v.to_double().value() - 3.14 < NumericLimits<double>().epsilon());
-    }
 }
 
 TEST_CASE(serialize_float_value)
@@ -211,63 +272,73 @@ TEST_CASE(serialize_float_value)
 
     serializer.rewind();
     auto v2 = serializer.deserialize<SQL::Value>();
-    EXPECT(!v2.is_null());
     EXPECT_EQ(v2.type(), SQL::SQLType::Float);
-    EXPECT(v.to_double().value() - 3.14 < NumericLimits<double>().epsilon());
-}
-
-TEST_CASE(assign_int_to_text_value)
-{
-    SQL::Value text(SQL::SQLType::Text);
-    text = 42;
-    EXPECT_EQ(text.to_string(), "42");
+    EXPECT((v.to_double().value() - 3.14) < NumericLimits<double>().epsilon());
+    EXPECT_EQ(v2, v);
 }
 
 TEST_CASE(copy_value)
 {
-    SQL::Value text(SQL::SQLType::Text, 42);
+    SQL::Value text("42");
     SQL::Value copy(text);
-    EXPECT_EQ(copy.to_string(), "42");
+    EXPECT_EQ(copy, "42"sv);
 }
 
 TEST_CASE(compare_text_to_int)
 {
-    SQL::Value text(SQL::SQLType::Text);
-    text = 42;
-    SQL::Value integer(SQL::SQLType::Integer);
-    integer = 42;
-    EXPECT(text == integer);
-    EXPECT(integer == text);
+    SQL::Value text("42");
+    SQL::Value integer(42);
+    EXPECT_EQ(text, integer);
+    EXPECT_EQ(integer, text);
 }
 
 TEST_CASE(bool_value)
 {
     {
         SQL::Value v(SQL::SQLType::Boolean);
+        EXPECT_EQ(v.type(), SQL::SQLType::Boolean);
         EXPECT(v.is_null());
+
         v = true;
-        EXPECT(!v.is_null());
+        EXPECT_EQ(v.type(), SQL::SQLType::Boolean);
+
         EXPECT(v.to_bool().has_value());
         EXPECT(v.to_bool().value());
+
+        EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 1);
-        EXPECT_EQ(v.to_string(), "true");
-        EXPECT(!v.to_double().has_value());
+        EXPECT_EQ(v.to_string(), "true"sv);
+
+        EXPECT(v.to_double().has_value());
+        EXPECT((v.to_double().value() - 1.0) < NumericLimits<double>().epsilon());
     }
     {
-        SQL::Value v(SQL::SQLType::Boolean, false);
-        EXPECT(!v.is_null());
+        SQL::Value v(false);
+        EXPECT_EQ(v.type(), SQL::SQLType::Boolean);
+
         EXPECT(v.to_bool().has_value());
         EXPECT(!v.to_bool().value());
+
+        EXPECT(v.to_int().has_value());
         EXPECT_EQ(v.to_int().value(), 0);
-        EXPECT_EQ(v.to_string(), "false");
-        EXPECT(!v.to_double().has_value());
+        EXPECT_EQ(v.to_string(), "false"sv);
+
+        EXPECT(v.to_double().has_value());
+        EXPECT(v.to_double().value() < NumericLimits<double>().epsilon());
     }
     {
         SQL::Value v(true);
         EXPECT_EQ(v.type(), SQL::SQLType::Boolean);
-        EXPECT(!v.is_null());
+
         EXPECT(v.to_bool().has_value());
         EXPECT(v.to_bool().value());
+
+        EXPECT(v.to_int().has_value());
+        EXPECT_EQ(v.to_int().value(), 1);
+        EXPECT_EQ(v.to_string(), "true"sv);
+
+        EXPECT(v.to_double().has_value());
+        EXPECT((v.to_double().value() - 1.0) < NumericLimits<double>().epsilon());
     }
 }
 
@@ -282,7 +353,6 @@ TEST_CASE(serialize_boolean_value)
 
     serializer.rewind();
     auto v2 = serializer.deserialize<SQL::Value>();
-    EXPECT(!v2.is_null());
     EXPECT_EQ(v2.type(), SQL::SQLType::Boolean);
     EXPECT_EQ(v2.to_bool(), true);
     EXPECT_EQ(v, v2);
@@ -293,12 +363,12 @@ TEST_CASE(tuple_value)
     NonnullRefPtr<SQL::TupleDescriptor> descriptor = adopt_ref(*new SQL::TupleDescriptor);
     descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending });
     descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending });
+    auto v = MUST(SQL::Value::create_tuple(move(descriptor)));
 
-    auto v = SQL::Value::create_tuple(descriptor);
     Vector<SQL::Value> values;
-    values.append(SQL::Value("Test"));
-    values.append(SQL::Value(42));
-    v = values;
+    values.empend("Test");
+    values.empend(42);
+    MUST(v.assign_tuple(values));
 
     auto values2 = v.to_vector();
     EXPECT(values2.has_value());
@@ -310,16 +380,16 @@ TEST_CASE(copy_tuple_value)
     NonnullRefPtr<SQL::TupleDescriptor> descriptor = adopt_ref(*new SQL::TupleDescriptor);
     descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending });
     descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending });
+    auto v = MUST(SQL::Value::create_tuple(move(descriptor)));
 
-    auto v = SQL::Value::create_tuple(descriptor);
     Vector<SQL::Value> values;
-    values.append(SQL::Value("Test"));
-    values.append(SQL::Value(42));
-    v = values;
+    values.empend("Test");
+    values.empend(42);
+    MUST(v.assign_tuple(values));
 
     auto values2 = v;
-    EXPECT(values2.type() == v.type());
-    EXPECT(!values2.is_null());
+    EXPECT_EQ(values2.type(), v.type());
+    EXPECT_EQ(v.type(), SQL::SQLType::Tuple);
     EXPECT_EQ(values, values2.to_vector().value());
 }
 
@@ -327,25 +397,27 @@ TEST_CASE(tuple_value_wrong_type)
 {
     NonnullRefPtr<SQL::TupleDescriptor> descriptor = adopt_ref(*new SQL::TupleDescriptor);
     descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending });
+    auto v = MUST(SQL::Value::create_tuple(move(descriptor)));
 
-    auto v = SQL::Value::create_tuple(descriptor);
     Vector<SQL::Value> values;
-    values.append(SQL::Value(42));
-    v = values;
-    EXPECT(v.is_null());
+    values.empend(42);
+
+    auto result = v.assign_tuple(move(values));
+    EXPECT(result.is_error());
 }
 
 TEST_CASE(tuple_value_too_many_values)
 {
     NonnullRefPtr<SQL::TupleDescriptor> descriptor = adopt_ref(*new SQL::TupleDescriptor);
     descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending });
+    auto v = MUST(SQL::Value::create_tuple(move(descriptor)));
 
-    auto v = SQL::Value::create_tuple(descriptor);
     Vector<SQL::Value> values;
-    values.append(SQL::Value("Test"));
-    values.append(SQL::Value(42));
-    v = values;
-    EXPECT(v.is_null());
+    values.empend("Test");
+    values.empend(42);
+
+    auto result = v.assign_tuple(move(values));
+    EXPECT(result.is_error());
 }
 
 TEST_CASE(tuple_value_not_enough_values)
@@ -353,18 +425,20 @@ TEST_CASE(tuple_value_not_enough_values)
     NonnullRefPtr<SQL::TupleDescriptor> descriptor = adopt_ref(*new SQL::TupleDescriptor);
     descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending });
     descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Ascending });
+    auto v = MUST(SQL::Value::create_tuple(move(descriptor)));
 
-    auto v = SQL::Value::create_tuple(descriptor);
     Vector<SQL::Value> values;
-    values.append(SQL::Value("Test"));
-    v = values;
-    EXPECT(!v.is_null());
+    values.empend("Test");
+    MUST(v.assign_tuple(values));
+
+    EXPECT_EQ(v.type(), SQL::SQLType::Tuple);
+
     auto values_opt = v.to_vector();
     EXPECT(values_opt.has_value());
     EXPECT_EQ(values_opt.value().size(), 2u);
+
     auto col2 = values_opt.value()[1];
     EXPECT_EQ(col2.type(), SQL::SQLType::Integer);
-    EXPECT(col2.is_null());
 }
 
 TEST_CASE(serialize_tuple_value)
@@ -372,89 +446,22 @@ TEST_CASE(serialize_tuple_value)
     NonnullRefPtr<SQL::TupleDescriptor> descriptor = adopt_ref(*new SQL::TupleDescriptor);
     descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending });
     descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending });
+    auto v = MUST(SQL::Value::create_tuple(move(descriptor)));
 
-    auto v = SQL::Value::create_tuple(descriptor);
     Vector<SQL::Value> values;
-    values.append(SQL::Value("Test"));
-    values.append(SQL::Value(42));
-    v = values;
+    values.empend("Test");
+    values.empend(42);
+    MUST(v.assign_tuple(values));
 
     SQL::Serializer serializer;
     serializer.serialize<SQL::Value>(v);
 
     serializer.rewind();
     auto v2 = serializer.deserialize<SQL::Value>();
-    EXPECT(!v2.is_null());
     EXPECT_EQ(v2.type(), SQL::SQLType::Tuple);
     EXPECT_EQ(v, v2);
 }
 
-TEST_CASE(array_value)
-{
-    auto v = SQL::Value::create_array(SQL::SQLType::Text, 3);
-    Vector<SQL::Value> values;
-    values.append(SQL::Value("Test 1"));
-    values.append(SQL::Value("Test 2"));
-    v = values;
-
-    auto values2 = v.to_vector();
-    EXPECT(values2.has_value());
-    EXPECT_EQ(values, values2.value());
-}
-
-TEST_CASE(array_value_wrong_type)
-{
-    auto v = SQL::Value::create_array(SQL::SQLType::Text, 2);
-    Vector<SQL::Value> values;
-    values.append(SQL::Value("Test 1"));
-    values.append(SQL::Value(42));
-    v = values;
-    EXPECT(v.is_null());
-}
-
-TEST_CASE(array_value_too_many_values)
-{
-    auto v = SQL::Value::create_array(SQL::SQLType::Text, 2);
-    Vector<SQL::Value> values;
-    values.append(SQL::Value("Test 1"));
-    values.append(SQL::Value("Test 2"));
-    values.append(SQL::Value("Test 3"));
-    v = values;
-    EXPECT(v.is_null());
-}
-
-TEST_CASE(copy_array_value)
-{
-    auto v = SQL::Value::create_array(SQL::SQLType::Text, 3);
-    Vector<SQL::Value> values;
-    values.append(SQL::Value("Test 1"));
-    values.append(SQL::Value("Test 2"));
-    v = values;
-
-    auto values2 = v;
-    EXPECT(values2.type() == v.type());
-    EXPECT(!values2.is_null());
-    EXPECT_EQ(values, values2.to_vector().value());
-}
-
-TEST_CASE(serialize_array_value)
-{
-    auto v = SQL::Value::create_array(SQL::SQLType::Text, 3);
-    Vector<SQL::Value> values;
-    values.append(SQL::Value("Test 1"));
-    values.append(SQL::Value("Test 2"));
-    v = values;
-
-    SQL::Serializer serializer;
-    serializer.serialize<SQL::Value>(v);
-
-    serializer.rewind();
-    auto v2 = serializer.deserialize<SQL::Value>();
-    EXPECT(!v2.is_null());
-    EXPECT_EQ(v2.type(), SQL::SQLType::Array);
-    EXPECT_EQ(v, v2);
-}
-
 TEST_CASE(order_text_values)
 {
     SQL::Value v1(SQL::SQLType::Text);
@@ -488,8 +495,8 @@ TEST_CASE(tuple)
 
     tuple["col1"] = "Test";
     tuple["col2"] = 42;
-    EXPECT(tuple[0] == "Test");
-    EXPECT(tuple[1] == 42);
+    EXPECT_EQ(tuple[0], "Test"sv);
+    EXPECT_EQ(tuple[1], 42);
 }
 
 TEST_CASE(serialize_tuple)
@@ -502,7 +509,7 @@ TEST_CASE(serialize_tuple)
     tuple["col1"] = "Test";
     tuple["col2"] = 42;
 
-    EXPECT_EQ(tuple[0], "Test");
+    EXPECT_EQ(tuple[0], "Test"sv);
     EXPECT_EQ(tuple[1], 42);
 
     SQL::Serializer serializer;
@@ -510,8 +517,8 @@ TEST_CASE(serialize_tuple)
 
     serializer.rewind();
     auto tuple2 = serializer.deserialize<SQL::Tuple>();
-    EXPECT(tuple2[0] == "Test");
-    EXPECT(tuple2[1] == 42);
+    EXPECT_EQ(tuple2[0], "Test"sv);
+    EXPECT_EQ(tuple2[1], 42);
 }
 
 TEST_CASE(copy_tuple)
@@ -526,10 +533,10 @@ TEST_CASE(copy_tuple)
 
     SQL::Tuple copy;
     copy = tuple;
-    EXPECT(tuple == copy);
+    EXPECT_EQ(tuple, copy);
 
     SQL::Tuple copy_2(copy);
-    EXPECT(tuple == copy_2);
+    EXPECT_EQ(tuple, copy_2);
 }
 
 TEST_CASE(compare_tuples)

+ 4 - 8
Userland/Libraries/LibSQL/AST/Expression.cpp

@@ -16,21 +16,17 @@ static constexpr auto s_posix_basic_metacharacters = ".^$*[]+\\"sv;
 
 ResultOr<Value> NumericLiteral::evaluate(ExecutionContext&) const
 {
-    Value ret(SQLType::Float);
-    ret = value();
-    return ret;
+    return Value { value() };
 }
 
 ResultOr<Value> StringLiteral::evaluate(ExecutionContext&) const
 {
-    Value ret(SQLType::Text);
-    ret = value();
-    return ret;
+    return Value { value() };
 }
 
 ResultOr<Value> NullLiteral::evaluate(ExecutionContext&) const
 {
-    return Value::null();
+    return Value {};
 }
 
 ResultOr<Value> NestedExpression::evaluate(ExecutionContext& context) const
@@ -46,7 +42,7 @@ ResultOr<Value> ChainedExpression::evaluate(ExecutionContext& context) const
     for (auto& expression : expressions())
         values.unchecked_append(TRY(expression.evaluate(context)));
 
-    return Value { move(values) };
+    return Value::create_tuple(move(values));
 }
 
 ResultOr<Value> BinaryOperatorExpression::evaluate(ExecutionContext& context) const

+ 1 - 1
Userland/Libraries/LibSQL/AST/Select.cpp

@@ -54,7 +54,7 @@ ResultOr<ResultSet> Select::execute(ExecutionContext& context) const
     Tuple tuple(descriptor);
     Vector<Tuple> rows;
     descriptor->empend("__unity__"sv);
-    tuple.append(Value(SQLType::Boolean, true));
+    tuple.append(Value { true });
     rows.append(tuple);
 
     for (auto& table_descriptor : table_or_subquery_list()) {

+ 1 - 2
Userland/Libraries/LibSQL/Type.h

@@ -18,8 +18,7 @@ namespace SQL {
     S("int", 4, Integer, int, sizeof(int))       \
     S("float", 8, Float, double, sizeof(double)) \
     S("bool", 16, Boolean, bool, sizeof(bool))   \
-    S("tuple", 32, Tuple, int, sizeof(int))      \
-    S("array", 64, Array, int, sizeof(int))
+    S("tuple", 32, Tuple, int, sizeof(int))
 
 enum class SQLType {
 #undef __ENUMERATE_SQL_TYPE

+ 337 - 798
Userland/Libraries/LibSQL/Value.cpp

@@ -1,166 +1,155 @@
 /*
  * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
+ * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/NumericLimits.h>
 #include <LibSQL/AST/AST.h>
 #include <LibSQL/Serializer.h>
+#include <LibSQL/TupleDescriptor.h>
 #include <LibSQL/Value.h>
 #include <math.h>
 #include <string.h>
 
 namespace SQL {
 
-Value::Value(SQLType sql_type)
+Value::Value(SQLType type)
+    : m_type(type)
 {
-    setup(sql_type);
 }
 
-void Value::setup(SQLType type)
+Value::Value(String value)
+    : m_type(SQLType::Text)
+    , m_value(move(value))
 {
-    switch (type) {
-#undef __ENUMERATE_SQL_TYPE
-#define __ENUMERATE_SQL_TYPE(name, cardinal, type, impl, size) \
-    case SQLType::type:                                        \
-        m_impl.set<type##Impl>(type##Impl());                  \
-        break;
-        ENUMERATE_SQL_TYPES(__ENUMERATE_SQL_TYPE)
-#undef __ENUMERATE_SQL_TYPE
-    default:
-        VERIFY_NOT_REACHED();
-    }
-}
-
-Value::Value(SQLType sql_type, Value const& value)
-    : Value(sql_type)
-{
-    assign(value);
 }
 
-Value::Value(SQLType sql_type, String const& string)
-    : Value(sql_type)
+Value::Value(int value)
+    : m_type(SQLType::Integer)
+    , m_value(value)
 {
-    assign(string);
 }
 
-Value::Value(SQLType sql_type, char const* string)
-    : Value(sql_type)
+Value::Value(u32 value)
+    : m_type(SQLType::Integer)
+    , m_value(static_cast<int>(value)) // FIXME: Handle signed overflow.
 {
-    assign(String(string));
 }
 
-Value::Value(SQLType sql_type, int integer)
-    : Value(sql_type)
+Value::Value(double value)
+    : m_type(SQLType::Float)
+    , m_value(value)
 {
-    assign(integer);
 }
 
-Value::Value(SQLType sql_type, double dbl)
-    : Value(sql_type)
+Value::Value(NonnullRefPtr<TupleDescriptor> descriptor, Vector<Value> values)
+    : m_type(SQLType::Tuple)
+    , m_value(TupleValue { move(descriptor), move(values) })
 {
-    assign(dbl);
 }
 
-Value::Value(SQLType sql_type, bool boolean)
-    : Value(sql_type)
+Value::Value(Value const& other)
+    : m_type(other.m_type)
+    , m_value(other.m_value)
 {
-    assign(boolean);
 }
 
-Value::Value(String const& string)
-    : Value(SQLType::Text)
+Value::Value(Value&& other)
+    : m_type(other.m_type)
+    , m_value(move(other.m_value))
 {
-    assign(string);
 }
 
-Value::Value(char const* string)
-    : Value(SQLType::Text)
-{
-    assign(String(string));
-}
-
-Value::Value(int integer)
-    : Value(SQLType::Integer)
-{
-    assign(integer);
-}
+Value::~Value() = default;
 
-Value::Value(u32 unsigned_integer)
-    : Value(SQLType::Integer)
+ResultOr<Value> Value::create_tuple(NonnullRefPtr<TupleDescriptor> descriptor)
 {
-    assign(unsigned_integer);
-}
+    Vector<Value> values;
+    TRY(values.try_resize(descriptor->size()));
 
-Value::Value(double dbl)
-    : Value(SQLType::Float)
-{
-    assign(dbl);
-}
+    for (size_t i = 0; i < descriptor->size(); ++i)
+        values[i].m_type = descriptor->at(i).type;
 
-Value::Value(bool boolean)
-    : Value(SQLType::Boolean)
-{
-    assign(boolean);
+    return Value { move(descriptor), move(values) };
 }
 
-Value Value::create_tuple(NonnullRefPtr<TupleDescriptor> const& tuple_descriptor)
+ResultOr<Value> Value::create_tuple(Vector<Value> values)
 {
-    return Value(Value::SetImplementationSingleton, TupleImpl(tuple_descriptor));
+    auto descriptor = TRY(infer_tuple_descriptor(values));
+    return Value { move(descriptor), move(values) };
 }
 
-Value Value::create_array(SQLType element_type, Optional<size_t> const& max_size)
+SQLType Value::type() const
 {
-    return Value(Value::SetImplementationSingleton, ArrayImpl(element_type, max_size));
+    return m_type;
 }
 
-Value const& Value::null()
+StringView Value::type_name() const
 {
-    static Value s_null(SQLType::Null);
-    return s_null;
+    switch (type()) {
+#undef __ENUMERATE_SQL_TYPE
+#define __ENUMERATE_SQL_TYPE(name, cardinal, type, impl, size) \
+    case SQLType::type:                                        \
+        return name##sv;
+        ENUMERATE_SQL_TYPES(__ENUMERATE_SQL_TYPE)
+#undef __ENUMERATE_SQL_TYPE
+    default:
+        VERIFY_NOT_REACHED();
+    }
 }
 
 bool Value::is_null() const
 {
-    return m_impl.visit([&](auto& impl) { return impl.is_null(); });
+    return !m_value.has_value();
 }
 
-SQLType Value::type() const
+String Value::to_string() const
 {
-    return m_impl.visit([&](auto& impl) { return impl.type(); });
-}
+    if (is_null())
+        return "(null)"sv;
 
-String Value::type_name() const
-{
-    return m_impl.visit([&](auto& impl) { return impl.type_name(); });
-}
+    return m_value->visit(
+        [](String const& value) -> String { return value; },
+        [](int value) -> String { return String::number(value); },
+        [](double value) -> String { return String::number(value); },
+        [](bool value) -> String { return value ? "true"sv : "false"sv; },
+        [](TupleValue const& value) -> String {
+            StringBuilder builder;
 
-BaseTypeImpl Value::downcast_to_basetype() const
-{
-    return m_impl.downcast<NullImpl, TextImpl, IntegerImpl, FloatImpl, BooleanImpl>();
-}
+            builder.append('(');
+            builder.join(',', value.values);
+            builder.append(')');
 
-String Value::to_string() const
-{
-    if (is_null())
-        return "(null)";
-    return m_impl.visit([&](auto& impl) { return impl.to_string(); });
+            return builder.build();
+        });
 }
 
 Optional<int> Value::to_int() const
 {
     if (is_null())
         return {};
-    return m_impl.visit([&](auto& impl) { return impl.to_int(); });
+
+    return m_value->visit(
+        [](String const& value) -> Optional<int> { return value.to_int(); },
+        [](int value) -> Optional<int> { return value; },
+        [](double value) -> Optional<int> {
+            if (value > static_cast<double>(NumericLimits<int>::max()))
+                return {};
+            if (value < static_cast<double>(NumericLimits<int>::min()))
+                return {};
+            return static_cast<int>(round(value));
+        },
+        [](bool value) -> Optional<int> { return static_cast<int>(value); },
+        [](TupleValue const&) -> Optional<int> { return {}; });
 }
 
 Optional<u32> Value::to_u32() const
 {
-    if (is_null())
-        return {};
-    auto ret = to_int();
-    if (ret.has_value())
-        return static_cast<u32>(ret.value());
+    // FIXME: Handle negative values.
+    if (auto result = to_int(); result.has_value())
+        return static_cast<u32>(result.value());
     return {};
 }
 
@@ -168,134 +157,185 @@ Optional<double> Value::to_double() const
 {
     if (is_null())
         return {};
-    return m_impl.visit([&](auto& impl) { return impl.to_double(); });
+
+    return m_value->visit(
+        [](String const& value) -> Optional<double> {
+            char* end = nullptr;
+            double result = strtod(value.characters(), &end);
+
+            if (end == value.characters())
+                return {};
+            return result;
+        },
+        [](int value) -> Optional<double> { return static_cast<double>(value); },
+        [](double value) -> Optional<double> { return value; },
+        [](bool value) -> Optional<double> { return static_cast<double>(value); },
+        [](TupleValue const&) -> Optional<double> { return {}; });
 }
 
 Optional<bool> Value::to_bool() const
 {
     if (is_null())
         return {};
-    return m_impl.visit([&](auto& impl) { return impl.to_bool(); });
+
+    return m_value->visit(
+        [](String const& value) -> Optional<bool> {
+            if (value.equals_ignoring_case("true"sv) || value.equals_ignoring_case("t"sv))
+                return true;
+            if (value.equals_ignoring_case("false"sv) || value.equals_ignoring_case("f"sv))
+                return false;
+            return {};
+        },
+        [](int value) -> Optional<bool> { return static_cast<bool>(value); },
+        [](double value) -> Optional<bool> { return fabs(value) > NumericLimits<double>::epsilon(); },
+        [](bool value) -> Optional<bool> { return value; },
+        [](TupleValue const& value) -> Optional<bool> {
+            for (auto const& element : value.values) {
+                auto as_bool = element.to_bool();
+                if (!as_bool.has_value())
+                    return {};
+                if (!as_bool.value())
+                    return false;
+            }
+
+            return true;
+        });
 }
 
 Optional<Vector<Value>> Value::to_vector() const
 {
-    if (is_null())
+    if (is_null() || (type() != SQLType::Tuple))
         return {};
-    Vector<Value> vector;
-    if (m_impl.visit([&](auto& impl) { return impl.to_vector(vector); }))
-        return vector;
-    else
-        return {};
-}
 
-void Value::assign(Value const& other_value)
-{
-    m_impl.visit([&](auto& impl) { impl.assign(other_value); });
+    auto const& tuple = m_value->get<TupleValue>();
+    return tuple.values;
 }
 
-void Value::assign(String const& string_value)
+Value& Value::operator=(Value value)
 {
-    m_impl.visit([&](auto& impl) { impl.assign_string(string_value); });
+    m_type = value.m_type;
+    m_value = move(value.m_value);
+    return *this;
 }
 
-void Value::assign(int int_value)
+Value& Value::operator=(String value)
 {
-    m_impl.visit([&](auto& impl) { impl.assign_int(int_value); });
+    m_type = SQLType::Text;
+    m_value = move(value);
+    return *this;
 }
 
-void Value::assign(u32 unsigned_int_value)
+Value& Value::operator=(int value)
 {
-    m_impl.visit([&](auto& impl) { impl.assign_int(unsigned_int_value); });
+    m_type = SQLType::Integer;
+    m_value = value;
+    return *this;
 }
 
-void Value::assign(double double_value)
+Value& Value::operator=(u32 value)
 {
-    m_impl.visit([&](auto& impl) { impl.assign_double(double_value); });
+    m_type = SQLType::Integer;
+    m_value = static_cast<int>(value); // FIXME: Handle signed overflow.
+    return *this;
 }
 
-void Value::assign(bool bool_value)
+Value& Value::operator=(double value)
 {
-    m_impl.visit([&](auto& impl) { impl.assign_bool(bool_value); });
+    m_type = SQLType::Float;
+    m_value = value;
+    return *this;
 }
 
-void Value::assign(Vector<Value> const& values)
+ResultOr<void> Value::assign_tuple(NonnullRefPtr<TupleDescriptor> descriptor)
 {
-    m_impl.visit([&](auto& impl) { impl.assign_vector(values); });
-}
+    Vector<Value> values;
+    TRY(values.try_resize(descriptor->size()));
 
-Value& Value::operator=(Value const& other)
-{
-    if (this != &other) {
-        if (other.is_null()) {
-            assign(null());
-        } else if (is_null()) {
-            assign(other);
-        } else {
-            VERIFY(can_cast(other));
-            assign(other);
-        }
-    }
-    return (*this);
-}
+    for (size_t i = 0; i < descriptor->size(); ++i)
+        values[i].m_type = descriptor->at(i).type;
 
-Value& Value::operator=(String const& value)
-{
-    assign(value);
-    return (*this);
-}
+    m_type = SQLType::Tuple;
+    m_value = TupleValue { move(descriptor), move(values) };
 
-Value& Value::operator=(char const* value)
-{
-    assign(String(value));
-    return (*this);
+    return {};
 }
 
-Value& Value::operator=(int value)
+ResultOr<void> Value::assign_tuple(Vector<Value> values)
 {
-    assign(value);
-    return (*this);
-}
+    if (is_null() || (type() != SQLType::Tuple)) {
+        auto descriptor = TRY(infer_tuple_descriptor(values));
 
-Value& Value::operator=(u32 value)
-{
-    assign(static_cast<int>(value));
-    return (*this);
-}
+        m_type = SQLType::Tuple;
+        m_value = TupleValue { move(descriptor), move(values) };
 
-Value& Value::operator=(double value)
-{
-    assign(value);
-    return (*this);
-}
+        return {};
+    }
 
-Value& Value::operator=(bool value)
-{
-    assign(value);
-    return (*this);
-}
+    auto& tuple = m_value->get<TupleValue>();
 
-Value& Value::operator=(Vector<Value> const& vector)
-{
-    assign(vector);
-    return (*this);
+    if (values.size() > tuple.descriptor->size())
+        return Result { SQLCommand::Unknown, SQLErrorCode::InvalidNumberOfValues };
+
+    for (size_t i = 0; i < values.size(); ++i) {
+        if (values[i].type() != tuple.descriptor->at(i).type)
+            return Result { SQLCommand::Unknown, SQLErrorCode::InvalidType, SQLType_name(values[i].type()) };
+    }
+
+    if (values.size() < tuple.descriptor->size()) {
+        size_t original_size = values.size();
+        MUST(values.try_resize(tuple.descriptor->size()));
+
+        for (size_t i = original_size; i < values.size(); ++i)
+            values[i].m_type = tuple.descriptor->at(i).type;
+    }
+
+    m_value = TupleValue { move(tuple.descriptor), move(values) };
+    return {};
 }
 
 size_t Value::length() const
 {
-    return m_impl.visit([&](auto& impl) { return impl.length(); });
+    if (is_null())
+        return 0;
+
+    // FIXME: This seems to be more of an encoded byte size rather than a length.
+    return m_value->visit(
+        [](String const& value) -> size_t { return sizeof(u32) + value.length(); },
+        [](int value) -> size_t { return sizeof(value); },
+        [](double value) -> size_t { return sizeof(value); },
+        [](bool value) -> size_t { return sizeof(value); },
+        [](TupleValue const& value) -> size_t {
+            auto size = value.descriptor->length() + sizeof(u32);
+
+            for (auto const& element : value.values)
+                size += element.length();
+
+            return size;
+        });
 }
 
 u32 Value::hash() const
 {
-    return (is_null()) ? 0u : m_impl.visit([&](auto& impl) { return impl.hash(); });
-}
+    if (is_null())
+        return 0;
 
-bool Value::can_cast(Value const& other_value) const
-{
-    if (type() == other_value.type())
-        return true;
-    return m_impl.visit([&](auto& impl) { return impl.can_cast(other_value); });
+    return m_value->visit(
+        [](String const& value) -> u32 { return value.hash(); },
+        [](int value) -> u32 { return int_hash(value); },
+        [](double) -> u32 { VERIFY_NOT_REACHED(); },
+        [](bool value) -> u32 { return int_hash(value); },
+        [](TupleValue const& value) -> u32 {
+            u32 hash = 0;
+
+            for (auto const& element : value.values) {
+                if (hash == 0)
+                    hash = element.hash();
+                else
+                    hash = pair_int_hash(hash, element.hash());
+            }
+
+            return hash;
+        });
 }
 
 int Value::compare(Value const& other) const
@@ -304,58 +344,105 @@ int Value::compare(Value const& other) const
         return -1;
     if (other.is_null())
         return 1;
-    return m_impl.visit([&](auto& impl) { return impl.compare(other); });
+
+    return m_value->visit(
+        [&](String const& value) -> int { return value.view().compare(other.to_string()); },
+        [&](int value) -> int {
+            auto casted = other.to_int();
+            if (!casted.has_value())
+                return 1;
+
+            if (value == *casted)
+                return 0;
+            return value < *casted ? -1 : 1;
+        },
+        [&](double value) -> int {
+            auto casted = other.to_double();
+            if (!casted.has_value())
+                return 1;
+
+            auto diff = value - *casted;
+            if (fabs(diff) < NumericLimits<double>::epsilon())
+                return 0;
+            return diff < 0 ? -1 : 1;
+        },
+        [&](bool value) -> int {
+            auto casted = other.to_bool();
+            if (!casted.has_value())
+                return 1;
+            return value ^ *casted;
+        },
+        [&](TupleValue const& value) -> int {
+            if (other.is_null() || (other.type() != SQLType::Tuple)) {
+                if (value.values.size() == 1)
+                    return value.values[0].compare(other);
+                return 1;
+            }
+
+            auto const& other_value = other.m_value->get<TupleValue>();
+            if (auto result = value.descriptor->compare_ignoring_names(*other_value.descriptor); result != 0)
+                return 1;
+
+            if (value.values.size() != other_value.values.size())
+                return value.values.size() < other_value.values.size() ? -1 : 1;
+
+            for (size_t i = 0; i < value.values.size(); ++i) {
+                auto result = value.values[i].compare(other_value.values[i]);
+                if (result == 0)
+                    continue;
+
+                if (value.descriptor->at(i).order == Order::Descending)
+                    result = -result;
+                return result;
+            }
+
+            return 0;
+        });
 }
 
-bool Value::operator==(Value const& other) const
+bool Value::operator==(Value const& value) const
 {
-    return compare(other) == 0;
+    return compare(value) == 0;
 }
 
-bool Value::operator==(String const& string_value) const
+bool Value::operator==(StringView value) const
 {
-    return to_string() == string_value;
+    return to_string() == value;
 }
 
-bool Value::operator==(int int_value) const
+bool Value::operator==(int value) const
 {
-    auto i = to_int();
-    if (!i.has_value())
-        return false;
-    return i.value() == int_value;
+    return to_int() == value;
 }
 
-bool Value::operator==(double double_value) const
+bool Value::operator==(double value) const
 {
-    auto d = to_double();
-    if (!d.has_value())
-        return false;
-    return d.value() == double_value;
+    return to_double() == value;
 }
 
-bool Value::operator!=(Value const& other) const
+bool Value::operator!=(Value const& value) const
 {
-    return compare(other) != 0;
+    return compare(value) != 0;
 }
 
-bool Value::operator<(Value const& other) const
+bool Value::operator<(Value const& value) const
 {
-    return compare(other) < 0;
+    return compare(value) < 0;
 }
 
-bool Value::operator<=(Value const& other) const
+bool Value::operator<=(Value const& value) const
 {
-    return compare(other) <= 0;
+    return compare(value) <= 0;
 }
 
-bool Value::operator>(Value const& other) const
+bool Value::operator>(Value const& value) const
 {
-    return compare(other) > 0;
+    return compare(value) > 0;
 }
 
-bool Value::operator>=(Value const& other) const
+bool Value::operator>=(Value const& value) const
 {
-    return compare(other) >= 0;
+    return compare(value) >= 0;
 }
 
 static Result invalid_type_for_numeric_operator(AST::BinaryOperator op)
@@ -472,639 +559,91 @@ ResultOr<Value> Value::bitwise_and(Value const& other) const
     return Value(u32_maybe_1.value() & u32_maybe_2.value());
 }
 
+static constexpr auto sql_type_null_as_flag = static_cast<u8>(SQLType::Null);
+
 void Value::serialize(Serializer& serializer) const
 {
-    u8 type_flags = (u8)type();
+    auto type_flags = static_cast<u8>(type());
     if (is_null())
-        type_flags |= (u8)SQLType::Null;
-    serializer.serialize<u8>(type_flags);
-    if (!is_null())
-        m_impl.visit([&](auto& impl) { serializer.serialize(impl); });
-}
-
-void Value::deserialize(Serializer& serializer)
-{
-    auto type_flags = serializer.deserialize<u8>();
-    bool is_null = false;
-    if ((type_flags & (u8)SQLType::Null) && (type_flags != (u8)SQLType::Null)) {
-        type_flags &= ~((u8)SQLType::Null);
-        is_null = true;
-    }
-    auto type = (SQLType)type_flags;
-    VERIFY(!is_null || (type != SQLType::Tuple && type != SQLType::Array));
-    setup(type);
-    if (!is_null) {
-        m_impl.visit([&](auto& impl) { impl.deserialize(serializer); });
-    }
-}
-
-bool NullImpl::can_cast(Value const& value)
-{
-    return value.is_null();
-}
-
-int NullImpl::compare(Value const& other)
-{
-    return other.type() == SQLType::Null;
-}
-
-String TextImpl::to_string() const
-{
-    return value();
-}
-
-Optional<int> TextImpl::to_int() const
-{
-    if (!m_value.has_value())
-        return {};
-    return value().to_int();
-}
-
-Optional<double> TextImpl::to_double() const
-{
-    if (!m_value.has_value())
-        return {};
-    char* end_ptr;
-    double ret = strtod(value().characters(), &end_ptr);
-    if (end_ptr == value().characters()) {
-        return {};
-    }
-    return ret;
-}
-
-Optional<bool> TextImpl::to_bool() const
-{
-    if (!m_value.has_value())
-        return {};
-    if (value().equals_ignoring_case("true"sv) || value().equals_ignoring_case("t"sv))
-        return true;
-    if (value().equals_ignoring_case("false"sv) || value().equals_ignoring_case("f"sv))
-        return false;
-    return {};
-}
-
-void TextImpl::assign(Value const& other_value)
-{
-    if (other_value.type() == SQLType::Null) {
-        m_value = {};
-    } else {
-        m_value = other_value.to_string();
-    }
-}
+        type_flags |= sql_type_null_as_flag;
 
-void TextImpl::assign_string(String const& string_value)
-{
-    m_value = string_value;
-}
-
-void TextImpl::assign_int(int int_value)
-{
-    m_value = String::number(int_value);
-}
-
-void TextImpl::assign_double(double double_value)
-{
-    m_value = String::number(double_value);
-}
-
-void TextImpl::assign_bool(bool bool_value)
-{
-    m_value = (bool_value) ? "true" : "false";
-}
-
-size_t TextImpl::length() const
-{
-    return (is_null()) ? 0 : sizeof(u32) + value().length();
-}
+    serializer.serialize<u8>(type_flags);
 
-int TextImpl::compare(Value const& other) const
-{
     if (is_null())
-        return -1;
-    auto s1 = value();
-    auto s2 = other.to_string();
-    if (s1 == s2)
-        return 0;
-    return (s1 < s2) ? -1 : 1;
-}
-
-u32 TextImpl::hash() const
-{
-    return value().hash();
-}
-
-String IntegerImpl::to_string() const
-{
-    return String::formatted("{}", value());
-}
-
-Optional<int> IntegerImpl::to_int() const
-{
-    return value();
-}
-
-Optional<double> IntegerImpl::to_double() const
-{
-    return static_cast<double>(value());
-}
-
-Optional<bool> IntegerImpl::to_bool() const
-{
-    return value() != 0;
-}
-
-void IntegerImpl::assign(Value const& other_value)
-{
-    auto i = other_value.to_int();
-    if (!i.has_value())
-        m_value = {};
-    else
-        m_value = i.value();
-}
-
-void IntegerImpl::assign_string(String const& string_value)
-{
-    auto i = string_value.to_int();
-    if (!i.has_value())
-        m_value = {};
-    else
-        m_value = i.value();
-}
-
-void IntegerImpl::assign_int(int int_value)
-{
-    m_value = int_value;
-}
-
-void IntegerImpl::assign_double(double double_value)
-{
-    m_value = static_cast<int>(round(double_value));
-}
-
-void IntegerImpl::assign_bool(bool bool_value)
-{
-    m_value = (bool_value) ? 1 : 0;
-}
-
-bool IntegerImpl::can_cast(Value const& other_value)
-{
-    return other_value.to_int().has_value();
-}
-
-int IntegerImpl::compare(Value const& other) const
-{
-    auto casted = other.to_int();
-    if (!casted.has_value())
-        return 1;
-
-    if (value() == casted.value())
-        return 0;
-
-    return value() < casted.value() ? -1 : 1;
-}
-
-u32 IntegerImpl::hash() const
-{
-    return int_hash(value());
-}
-
-String FloatImpl::to_string() const
-{
-    return String::formatted("{}", value());
-}
-
-Optional<int> FloatImpl::to_int() const
-{
-    return static_cast<int>(round(value()));
-}
-
-Optional<bool> FloatImpl::to_bool() const
-{
-    return fabs(value()) > NumericLimits<double>::epsilon();
-}
-
-Optional<double> FloatImpl::to_double() const
-{
-    return value();
-}
-
-void FloatImpl::assign(Value const& other_value)
-{
-    auto i = other_value.to_double();
-    if (!i.has_value())
-        m_value = {};
-    else
-        m_value = i.value();
-}
-
-void FloatImpl::assign_string(String const& string_value)
-{
-    char* end_ptr;
-    auto dbl = strtod(string_value.characters(), &end_ptr);
-    if (end_ptr == string_value.characters())
-        m_value = {};
-    else
-        m_value = dbl;
-}
-
-void FloatImpl::assign_int(int int_value)
-{
-    m_value = int_value;
-}
-
-void FloatImpl::assign_double(double double_value)
-{
-    m_value = double_value;
-}
-
-bool FloatImpl::can_cast(Value const& other_value)
-{
-    return other_value.to_double().has_value();
-}
-
-int FloatImpl::compare(Value const& other) const
-{
-    auto casted = other.to_double();
-    if (!casted.has_value()) {
-        return 1;
-    }
-
-    auto diff = value() - casted.value();
-    if (fabs(diff) < NumericLimits<double>::epsilon())
-        return 0;
-    return diff < 0 ? -1 : 1;
-}
-
-String BooleanImpl::to_string() const
-{
-    return (value()) ? "true" : "false";
-}
-
-Optional<int> BooleanImpl::to_int() const
-{
-    return (value()) ? 1 : 0;
-}
-
-Optional<double> BooleanImpl::to_double()
-{
-    return {};
-}
-
-Optional<bool> BooleanImpl::to_bool() const
-{
-    return value();
-}
-
-void BooleanImpl::assign(Value const& other_value)
-{
-    auto b = other_value.to_bool();
-    if (!b.has_value())
-        m_value = {};
-    else
-        m_value = b.value();
-}
-
-void BooleanImpl::assign_string(String const& string_value)
-{
-    return assign(Value(string_value));
-}
-
-void BooleanImpl::assign_int(int int_value)
-{
-    m_value = (int_value != 0);
-}
-
-void BooleanImpl::assign_double(double)
-{
-    m_value = {};
-}
-
-void BooleanImpl::assign_bool(bool bool_value)
-{
-    m_value = bool_value;
-}
-
-bool BooleanImpl::can_cast(Value const& other_value)
-{
-    return other_value.to_bool().has_value();
-}
-
-int BooleanImpl::compare(Value const& other) const
-{
-    auto casted = other.to_bool();
-    if (!casted.has_value()) {
-        return 1;
-    }
-    return value() ^ casted.value(); // xor - zero if both true or both false, 1 otherwise.
-}
-
-u32 BooleanImpl::hash() const
-{
-    return int_hash(value());
-}
-
-void ContainerValueImpl::assign_vector(Vector<Value> const& vector_values)
-{
-    if (!validate_before_assignment(vector_values)) {
-        m_value = {};
         return;
-    }
-    m_value = Vector<BaseTypeImpl>();
-    for (auto& value : vector_values) {
-        if (!append(value)) {
-            m_value = {};
-            return;
-        }
-    }
-    if (!validate_after_assignment())
-        m_value = {};
-}
-
-bool ContainerValueImpl::to_vector(Vector<Value>& vector) const
-{
-    vector.clear();
-    for (auto& value : value()) {
-        vector.empend(Value(value));
-    }
-    return true;
-}
-
-Vector<String> ContainerValueImpl::to_string_vector() const
-{
-    Vector<String> ret;
-    for (auto& value : value()) {
-        ret.append(Value(value).to_string());
-    }
-    return ret;
-}
-
-String ContainerValueImpl::to_string() const
-{
-    StringBuilder builder;
-    builder.append('(');
-    StringBuilder joined;
-    joined.join(", "sv, to_string_vector());
-    builder.append(joined.string_view());
-    builder.append(')');
-    return builder.build();
-}
-
-u32 ContainerValueImpl::hash() const
-{
-    u32 ret = 0u;
-    for (auto& value : value()) {
-        Value v(value);
-        // This is an extension of the pair_int_hash function from AK/HashFunctions.h:
-        if (!ret)
-            ret = v.hash();
-        else
-            ret = int_hash((ret * 209) ^ (v.hash() * 413));
-    }
-    return ret;
-}
 
-bool ContainerValueImpl::append(Value const& value)
-{
-    if (value.type() == SQLType::Tuple || value.type() == SQLType::Array)
-        return false;
-    return append(value.downcast_to_basetype());
-}
+    m_value->visit(
+        [&](TupleValue const& value) {
+            serializer.serialize<TupleDescriptor>(*value.descriptor);
+            serializer.serialize(static_cast<u32>(value.values.size()));
 
-bool ContainerValueImpl::append(BaseTypeImpl const& impl)
-{
-    if (!validate(impl))
-        return false;
-    m_value.value().empend(impl);
-    return true;
+            for (auto const& element : value.values)
+                serializer.serialize<Value>(element);
+        },
+        [&](auto const& value) { serializer.serialize(value); });
 }
 
-void ContainerValueImpl::serialize_values(Serializer& serializer) const
+void Value::deserialize(Serializer& serializer)
 {
-    serializer.serialize((u32)size());
-    for (auto& impl : value()) {
-        serializer.serialize<Value>(Value(impl));
-    }
-}
+    auto type_flags = serializer.deserialize<u8>();
+    bool has_value = true;
 
-void ContainerValueImpl::deserialize_values(Serializer& serializer)
-{
-    auto sz = serializer.deserialize<u32>();
-    m_value = Vector<BaseTypeImpl>();
-    for (auto ix = 0u; ix < sz; ix++) {
-        append(serializer.deserialize<Value>());
+    if ((type_flags & sql_type_null_as_flag) && (type_flags != sql_type_null_as_flag)) {
+        type_flags &= ~sql_type_null_as_flag;
+        has_value = false;
     }
-}
 
-size_t ContainerValueImpl::length() const
-{
-    size_t len = sizeof(u32);
-    for (auto& impl : value()) {
-        len += Value(impl).length();
-    }
-    return len;
-}
+    m_type = static_cast<SQLType>(type_flags);
 
-void TupleImpl::assign(Value const& other)
-{
-    if (other.type() != SQLType::Tuple) {
-        m_value = {};
-        return;
-    }
-    auto& other_impl = other.get_impl<TupleImpl>({});
-    auto other_descriptor = other_impl.m_descriptor;
-    if (m_descriptor && other_descriptor && m_descriptor->compare_ignoring_names(*other_descriptor)) {
-        m_value = {};
+    if (!has_value)
         return;
-    }
-    assign_vector(other.to_vector().value());
-}
-
-size_t TupleImpl::length() const
-{
-    return m_descriptor->length() + ContainerValueImpl::length();
-}
-
-bool TupleImpl::can_cast(Value const& other_value) const
-{
-    if (other_value.type() != SQLType::Tuple)
-        return false;
-    return (m_descriptor == other_value.get_impl<TupleImpl>({}).m_descriptor);
-}
-
-int TupleImpl::compare(Value const& other) const
-{
-    if (other.type() != SQLType::Tuple) {
-        if (size() == 1)
-            return Value(value().at(0)).compare(other);
-        return 1;
-    }
-
-    auto& other_impl = other.get_impl<TupleImpl>({});
-    if (m_descriptor && other_impl.m_descriptor && m_descriptor->compare_ignoring_names(*other_impl.m_descriptor))
-        return 1;
-
-    auto other_values = other_impl.value();
-    if (size() != other_impl.size())
-        return (int)value().size() - (int)other_impl.size();
-    for (auto ix = 0u; ix < value().size(); ix++) {
-        auto ret = Value(value()[ix]).compare(Value(other_impl.value()[ix]));
-        if (ret != 0) {
-            if (m_descriptor && (ix < m_descriptor->size()) && (*m_descriptor)[ix].order == Order::Descending)
-                ret = -ret;
-            return ret;
-        }
-    }
-    return 0;
-}
-
-Optional<bool> TupleImpl::to_bool() const
-{
-    for (auto const& value : value()) {
-        auto as_bool = Value(value).to_bool();
-        if (!as_bool.has_value())
-            return {};
-        if (!as_bool.value())
-            return false;
-    }
 
-    return true;
-}
-
-void TupleImpl::serialize(Serializer& serializer) const
-{
-    serializer.serialize<TupleDescriptor>(*m_descriptor);
-    serialize_values(serializer);
-}
-
-void TupleImpl::deserialize(Serializer& serializer)
-{
-    m_descriptor = serializer.adopt_and_deserialize<TupleDescriptor>();
-    deserialize_values(serializer);
-}
-
-void TupleImpl::infer_descriptor()
-{
-    if (!m_descriptor) {
-        m_descriptor = adopt_ref(*new TupleDescriptor);
-        m_descriptor_inferred = true;
-    }
-}
-
-void TupleImpl::extend_descriptor(Value const& value)
-{
-    VERIFY(m_descriptor_inferred);
-    m_descriptor->empend("", "", "", value.type(), Order::Ascending);
-}
-
-bool TupleImpl::validate_before_assignment(Vector<Value> const& values)
-{
-    if (m_descriptor_inferred)
-        m_descriptor = nullptr;
-    if (!m_descriptor) {
-        infer_descriptor();
-        if (values.size() > m_descriptor->size()) {
-            for (auto ix = m_descriptor->size(); ix < values.size(); ix++) {
-                extend_descriptor(values[ix]);
-            }
-        }
-    }
-    return true;
-}
+    switch (m_type) {
+    case SQLType::Null:
+        VERIFY_NOT_REACHED();
+        break;
+    case SQLType::Text:
+        m_value = serializer.deserialize<String>();
+        break;
+    case SQLType::Integer:
+        m_value = serializer.deserialize<int>(0);
+        break;
+    case SQLType::Float:
+        m_value = serializer.deserialize<double>(0.0);
+        break;
+    case SQLType::Boolean:
+        m_value = serializer.deserialize<bool>(false);
+        break;
+    case SQLType::Tuple: {
+        auto descriptor = serializer.adopt_and_deserialize<TupleDescriptor>();
+        auto size = serializer.deserialize<u32>();
 
-bool TupleImpl::validate(BaseTypeImpl const& value)
-{
-    if (!m_descriptor)
-        infer_descriptor();
-    if (m_descriptor_inferred && (this->value().size() == m_descriptor->size()))
-        extend_descriptor(Value(value));
-    if (m_descriptor->size() == this->value().size())
-        return false;
-    auto required_type = (*m_descriptor)[this->value().size()].type;
-    return Value(value).type() == required_type;
-}
+        Vector<Value> values;
+        values.ensure_capacity(size);
 
-bool TupleImpl::validate_after_assignment()
-{
-    for (auto ix = value().size(); ix < m_descriptor->size(); ++ix) {
-        auto required_type = (*m_descriptor)[ix].type;
-        append(Value(required_type));
-    }
-    return true;
-}
+        for (size_t i = 0; i < size; ++i)
+            values.unchecked_append(serializer.deserialize<Value>());
 
-void ArrayImpl::assign(Value const& other)
-{
-    if (other.type() != SQLType::Array) {
-        m_value = {};
-        return;
+        m_value = TupleValue { move(descriptor), move(values) };
+        break;
     }
-    auto& other_impl = other.get_impl<ArrayImpl>({});
-    if (m_max_size != other_impl.m_max_size || m_element_type != other_impl.m_element_type) {
-        m_value = {};
-        return;
     }
-    assign_vector(other.to_vector().value());
 }
 
-size_t ArrayImpl::length() const
+TupleElementDescriptor Value::descriptor() const
 {
-    return sizeof(u8) + sizeof(u32) + ContainerValueImpl::length();
+    return { "", "", "", type(), Order::Ascending };
 }
 
-bool ArrayImpl::can_cast(Value const& other_value) const
+ResultOr<NonnullRefPtr<TupleDescriptor>> Value::infer_tuple_descriptor(Vector<Value> const& values)
 {
-    if (other_value.type() != SQLType::Array)
-        return false;
-    auto& other_impl = other_value.get_impl<ArrayImpl>({});
-    return (m_max_size != other_impl.m_max_size || m_element_type != other_impl.m_element_type);
-}
+    auto descriptor = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) SQL::TupleDescriptor));
+    TRY(descriptor->try_ensure_capacity(values.size()));
 
-int ArrayImpl::compare(Value const& other) const
-{
-    if (other.type() != SQLType::Array)
-        return 1;
-    auto other_impl = other.get_impl<ArrayImpl>({});
-    if (other_impl.m_element_type != m_element_type)
-        return 1;
-    if (other_impl.m_max_size.has_value() && m_max_size.has_value() && other_impl.m_max_size != m_max_size)
-        return (int)m_max_size.value() - (int)other_impl.m_max_size.value();
-    if (size() != other_impl.size())
-        return (int)size() - (int)other_impl.size();
-    for (auto ix = 0u; ix < size(); ix++) {
-        auto ret = Value(value()[ix]).compare(Value(other_impl.value()[ix]));
-        if (ret != 0) {
-            return ret;
-        }
-    }
-    return 0;
-}
+    for (auto const& element : values)
+        descriptor->unchecked_append({ ""sv, ""sv, ""sv, element.type(), Order::Ascending });
 
-void ArrayImpl::serialize(Serializer& serializer) const
-{
-    serializer.serialize((u8)m_element_type);
-    if (m_max_size.has_value())
-        serializer.serialize((u32)m_max_size.value());
-    else
-        serializer.serialize((u32)0);
-    serialize_values(serializer);
-}
-
-void ArrayImpl::deserialize(Serializer& serializer)
-{
-    m_element_type = (SQLType)serializer.deserialize<u8>();
-    auto max_sz = serializer.deserialize<u32>();
-    if (max_sz)
-        m_max_size = max_sz;
-    else
-        m_max_size = {};
-    deserialize_values(serializer);
-}
-
-bool ArrayImpl::validate(BaseTypeImpl const& impl)
-{
-    if (m_max_size.has_value() && (size() >= m_max_size.value()))
-        return false;
-    return Value(impl).type() == m_element_type;
+    return descriptor;
 }
 
 }

+ 57 - 69
Userland/Libraries/LibSQL/Value.h

@@ -1,22 +1,21 @@
 /*
  * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
+ * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
 #pragma once
 
-#include <AK/Badge.h>
-#include <AK/ByteBuffer.h>
-#include <AK/ScopeGuard.h>
+#include <AK/Format.h>
+#include <AK/Optional.h>
 #include <AK/String.h>
+#include <AK/StringView.h>
 #include <AK/Variant.h>
+#include <AK/Vector.h>
 #include <LibSQL/Forward.h>
 #include <LibSQL/Result.h>
-#include <LibSQL/TupleDescriptor.h>
 #include <LibSQL/Type.h>
-#include <LibSQL/ValueImpl.h>
-#include <string.h>
 
 namespace SQL {
 
@@ -27,49 +26,28 @@ namespace SQL {
  */
 class Value {
 public:
-    Value(Value&) = default;
-    Value(Value const&) = default;
-
     explicit Value(SQLType sql_type = SQLType::Null);
-
-    template<typename... Ts>
-    explicit Value(Variant<Ts...> impl)
-        : m_impl(impl)
-    {
-    }
-
-    enum SetImplementation {
-        SetImplementationSingleton
-    };
-
-    template<typename I>
-    Value(SetImplementation, I&& impl)
-    {
-        m_impl.set<I>(forward<I>(impl));
-    }
-
-    Value(SQLType, Value const&);
-    Value(SQLType, String const&);
-    Value(SQLType, char const*);
-    Value(SQLType, int);
-    Value(SQLType, double);
-    Value(SQLType, bool);
-    explicit Value(String const&);
-    explicit Value(char const*);
+    explicit Value(String);
     explicit Value(int);
     explicit Value(u32);
     explicit Value(double);
-    explicit Value(bool);
+    Value(Value const&);
+    Value(Value&&);
+    ~Value();
 
-    ~Value() = default;
+    static ResultOr<Value> create_tuple(NonnullRefPtr<TupleDescriptor>);
+    static ResultOr<Value> create_tuple(Vector<Value>);
 
-    [[nodiscard]] bool is_null() const;
-    [[nodiscard]] SQLType type() const;
-    [[nodiscard]] String type_name() const;
-    [[nodiscard]] BaseTypeImpl downcast_to_basetype() const;
+    template<typename T>
+    requires(SameAs<RemoveCVReference<T>, bool>) explicit Value(T value)
+        : m_type(SQLType::Boolean)
+        , m_value(value)
+    {
+    }
 
-    template<typename Impl>
-    Impl const& get_impl(Badge<Impl>) const { return m_impl.get<Impl>(); }
+    [[nodiscard]] SQLType type() const;
+    [[nodiscard]] StringView type_name() const;
+    [[nodiscard]] bool is_null() const;
 
     [[nodiscard]] String to_string() const;
     [[nodiscard]] Optional<int> to_int() const;
@@ -78,34 +56,33 @@ public:
     [[nodiscard]] Optional<bool> to_bool() const;
     [[nodiscard]] Optional<Vector<Value>> to_vector() const;
 
-    void assign(Value const& other_value);
-    void assign(String const& string_value);
-    void assign(int int_value);
-    void assign(u32 unsigned_int_value);
-    void assign(double double_value);
-    void assign(bool bool_value);
-    void assign(Vector<Value> const& values);
-
-    Value& operator=(Value const& other);
-
-    Value& operator=(String const&);
-    Value& operator=(char const*);
+    Value& operator=(Value);
+    Value& operator=(String);
     Value& operator=(int);
     Value& operator=(u32);
     Value& operator=(double);
-    Value& operator=(bool);
-    Value& operator=(Vector<Value> const&);
+
+    ResultOr<void> assign_tuple(NonnullRefPtr<TupleDescriptor>);
+    ResultOr<void> assign_tuple(Vector<Value>);
+
+    template<typename T>
+    requires(SameAs<RemoveCVReference<T>, bool>) Value& operator=(T value)
+    {
+        m_type = SQLType::Boolean;
+        m_value = value;
+        return *this;
+    }
 
     [[nodiscard]] size_t length() const;
     [[nodiscard]] u32 hash() const;
-    [[nodiscard]] bool can_cast(Value const&) const;
     void serialize(Serializer&) const;
     void deserialize(Serializer&);
 
     [[nodiscard]] int compare(Value const&) const;
     bool operator==(Value const&) const;
-    bool operator==(String const&) const;
+    bool operator==(StringView) const;
     bool operator==(int) const;
+    bool operator==(u32) const;
     bool operator==(double) const;
     bool operator!=(Value const&) const;
     bool operator<(Value const&) const;
@@ -123,20 +100,31 @@ public:
     ResultOr<Value> bitwise_or(Value const&) const;
     ResultOr<Value> bitwise_and(Value const&) const;
 
-    [[nodiscard]] TupleElementDescriptor descriptor() const
-    {
-        return { "", "", "", type(), Order::Ascending };
-    }
-
-    static Value const& null();
-    static Value create_tuple(NonnullRefPtr<TupleDescriptor> const&);
-    static Value create_array(SQLType element_type, Optional<size_t> const& max_size = {});
+    [[nodiscard]] TupleElementDescriptor descriptor() const;
 
 private:
-    void setup(SQLType type);
-
-    ValueTypeImpl m_impl { NullImpl() };
     friend Serializer;
+
+    struct TupleValue {
+        NonnullRefPtr<TupleDescriptor> descriptor;
+        Vector<Value> values;
+    };
+
+    using ValueType = Variant<String, int, double, bool, TupleValue>;
+
+    static ResultOr<NonnullRefPtr<TupleDescriptor>> infer_tuple_descriptor(Vector<Value> const& values);
+    Value(NonnullRefPtr<TupleDescriptor> descriptor, Vector<Value> values);
+
+    SQLType m_type { SQLType::Null };
+    Optional<ValueType> m_value;
 };
 
 }
+
+template<>
+struct AK::Formatter<SQL::Value> : Formatter<StringView> {
+    ErrorOr<void> format(FormatBuilder& builder, SQL::Value const& value)
+    {
+        return Formatter<StringView>::format(builder, value.to_string());
+    }
+};

+ 0 - 298
Userland/Libraries/LibSQL/ValueImpl.h

@@ -1,298 +0,0 @@
-/*
- * 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]] 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) { 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;
-    [[nodiscard]] Optional<bool> to_bool() 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>;
-
-}