From eb4d23c5043bbbae5e2a4a946e42e908cafabc96 Mon Sep 17 00:00:00 2001 From: jbajic <jure.bajic@memgraph.com> Date: Mon, 23 May 2022 13:56:33 +0200 Subject: [PATCH] Implement SchemaTypes --- src/storage/v2/schemas.cpp | 46 +++++++----- src/storage/v2/schemas.hpp | 139 +++++++++++++++++++++++++++++++++---- src/storage/v2/storage.cpp | 6 +- src/storage/v2/storage.hpp | 6 ++ 4 files changed, 164 insertions(+), 33 deletions(-) diff --git a/src/storage/v2/schemas.cpp b/src/storage/v2/schemas.cpp index e92894a96..b74ca698e 100644 --- a/src/storage/v2/schemas.cpp +++ b/src/storage/v2/schemas.cpp @@ -9,7 +9,6 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -#include <tuple> #include <unordered_map> #include <utility> #include <vector> @@ -19,40 +18,53 @@ namespace memgraph::storage { -Schemas::CreationStatus Schemas::CreateSchema( - const LabelId label, const std::vector<std::pair<PropertyId, PropertyValue::Type>> &property_types) { - auto res = schemas_.insert({label, property_types}).second; +SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label) : status{status}, label{label} {} + +SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label, SchemaType violated_type) + : status{status}, label{label}, violated_type{violated_type} {} + +SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label, SchemaType violated_type, + PropertyValue violated_property_value) + : status{status}, label{label}, violated_type{violated_type}, violated_property_value{violated_property_value} {} + +Schemas::CreationStatus Schemas::CreateSchema(const LabelId primary_label, + const std::vector<SchemaType> &schemas_types) { + auto res = schemas_.insert({primary_label, schemas_types}).second; return res ? Schemas::CreationStatus::SUCCESS : Schemas::CreationStatus::FAIL; } -Schemas::DeletionStatus Schemas::DeleteSchema(const LabelId label) { - auto res = schemas_.erase(label); +Schemas::DeletionStatus Schemas::DeleteSchema(const LabelId primary_label) { + auto res = schemas_.erase(primary_label); return res != 0 ? Schemas::DeletionStatus::SUCCESS : Schemas::DeletionStatus::FAIL; } -Schemas::ValidationStatus Schemas::ValidateVertex(const LabelId primary_label, const Vertex &vertex) { +[[nodiscard]] std::optional<SchemaViolation> Schemas::ValidateVertex(const LabelId primary_label, + const Vertex &vertex) { + // TODO Check for multiple defined primary labels + std::vector<std::pair<SchemaType, PropertyValue>> type_violations; if (!schemas_.contains(primary_label)) { - return Schemas::ValidationStatus::NO_SCHEMA_DEFINED_FOR_LABEL; + return SchemaViolation(SchemaViolation::ValidationStatus::NO_SCHEMA_DEFINED_FOR_LABEL, primary_label); } if (!utils::Contains(vertex.labels, primary_label)) { - return Schemas::ValidationStatus::VERTEX_HAS_NO_PRIMARY_LABEL; + return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_HAS_NO_PRIMARY_LABEL, primary_label); } - for (auto &[property_id, property_type] : schemas_[primary_label]) { - // Property existence check - if (!vertex.properties.HasProperty(property_id)) { - return Schemas::ValidationStatus::VERTEX_HAS_NO_PROPERTY; + for (auto &schema_type : schemas_[primary_label]) { + if (!vertex.properties.HasProperty(schema_type.property_id)) { + return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_HAS_NO_PROPERTY, primary_label, schema_type); } // Property type check - if (vertex.properties.GetProperty(property_id).type() != property_type) { - return Schemas::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE; + // TODO Can this be replaced with just property id check? + if (auto vertex_property = vertex.properties.GetProperty(schema_type.property_id); + PropertyValueTypeToSchemaType(vertex_property) != schema_type.type) { + return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, primary_label, schema_type, + vertex_property); } } - // TODO after the introduction of vertex hashing introduce check for vertex // primary key uniqueness - return Schemas::ValidationStatus::SUCCESS; + return std::nullopt; } Schemas::SchemasList Schemas::ListSchemas() const { diff --git a/src/storage/v2/schemas.hpp b/src/storage/v2/schemas.hpp index e2d3da3d3..7d55f5cc2 100644 --- a/src/storage/v2/schemas.hpp +++ b/src/storage/v2/schemas.hpp @@ -11,25 +11,61 @@ #pragma once +#include <memory> +#include <optional> #include <unordered_map> #include <utility> #include <vector> +#include "storage/v2/id_types.hpp" #include "storage/v2/indices.hpp" #include "storage/v2/property_value.hpp" +#include "storage/v2/temporal.hpp" #include "storage/v2/transaction.hpp" #include "storage/v2/vertex.hpp" #include "utils/result.hpp" namespace memgraph::storage { -/// +class SchemaViolationException : public utils::BasicException { + using utils::BasicException::BasicException; +}; + +struct SchemaType { + enum class Type : uint8_t { Bool, Int, Double, String, List, Map, Date, LocalTime, LocalDateTime, Duration }; + + Type type; + PropertyId property_id; + std::shared_ptr<SchemaType> nested_value; +}; + +struct SchemaViolation { + enum class ValidationStatus : uint8_t { + VERTEX_HAS_NO_PRIMARY_LABEL, + VERTEX_HAS_NO_PROPERTY, + NO_SCHEMA_DEFINED_FOR_LABEL, + VERTEX_PROPERTY_WRONG_TYPE + }; + + SchemaViolation(ValidationStatus status, LabelId label); + + SchemaViolation(ValidationStatus status, LabelId label, SchemaType violated_type); + + SchemaViolation(ValidationStatus status, LabelId label, SchemaType violated_type, + PropertyValue violated_property_value); + + ValidationStatus status; + LabelId label; + std::optional<SchemaType> violated_type; + std::optional<PropertyValue> violated_property_value; +}; + /// Structure that represents a collection of schemas /// Schema can be mapped under only one label => primary label class Schemas { public: - using SchemasStructure = std::unordered_map<LabelId, std::vector<std::pair<PropertyId, PropertyValue::Type>>>; - using SchemasList = std::vector<std::pair<LabelId, std::vector<std::pair<PropertyId, PropertyValue::Type>>>>; + using SchemasStructure = std::unordered_map<LabelId, std::vector<SchemaType>>; + using SchemasList = std::vector<std::pair<LabelId, std::vector<SchemaType>>>; Schemas() = default; Schemas(const Schemas &) = delete; @@ -40,21 +76,12 @@ class Schemas { enum class CreationStatus : uint8_t { SUCCESS, FAIL }; enum class DeletionStatus : uint8_t { SUCCESS, FAIL }; - enum class ValidationStatus : uint8_t { - SUCCESS, - VERTEX_DELETED, - VERTEX_HAS_NO_PRIMARY_LABEL, - VERTEX_HAS_NO_PROPERTY, - NO_SCHEMA_DEFINED_FOR_LABEL, - VERTEX_PROPERTY_WRONG_TYPE - }; - CreationStatus CreateSchema(LabelId label, - const std::vector<std::pair<PropertyId, PropertyValue::Type>> &property_types); + CreationStatus CreateSchema(LabelId label, const std::vector<SchemaType> &schemas_types); DeletionStatus DeleteSchema(LabelId label); - ValidationStatus ValidateVertex(LabelId primary_label, const Vertex &vertex); + std::optional<SchemaViolation> ValidateVertex(LabelId primary_label, const Vertex &vertex); SchemasList ListSchemas() const; @@ -62,4 +89,88 @@ class Schemas { SchemasStructure schemas_; }; +inline std::optional<SchemaType::Type> PropertyValueTypeToSchemaType(const PropertyValue &property_value) { + switch (property_value.type()) { + case PropertyValue::Type::Bool: { + return SchemaType::Type::Bool; + } + case PropertyValue::Type::Int: { + return SchemaType::Type::Int; + } + case PropertyValue::Type::Double: { + return SchemaType::Type::Double; + } + case PropertyValue::Type::String: { + return SchemaType::Type::String; + } + case PropertyValue::Type::List: { + return SchemaType::Type::List; + } + case PropertyValue::Type::Map: { + return SchemaType::Type::Map; + } + case PropertyValue::Type::TemporalData: { + switch (property_value.ValueTemporalData().type) { + case TemporalType::Date: { + return SchemaType::Type::Date; + } + case TemporalType::LocalDateTime: { + return SchemaType::Type::LocalDateTime; + } + case TemporalType::LocalTime: { + return SchemaType::Type::LocalTime; + } + case TemporalType::Duration: { + return SchemaType::Type::Duration; + } + } + } + default: { + return std::nullopt; + } + } +} + +inline std::string SchemaTypeToString(const SchemaType::Type type) { + switch (type) { + case SchemaType::Type::Bool: { + return "Bool"; + } + case SchemaType::Type::Int: { + return "Integer"; + } + case SchemaType::Type::Double: { + return "Double"; + } + case SchemaType::Type::String: { + return "String"; + } + case SchemaType::Type::List: { + return "List"; + } + case SchemaType::Type::Map: { + return "Map"; + } + case SchemaType::Type::Date: { + return "Date"; + } + case SchemaType::Type::LocalTime: { + return "LocalTime"; + } + case SchemaType::Type::LocalDateTime: { + return "LocalDateTime"; + } + case SchemaType::Type::Duration: { + return "Duration"; + } + } +} + +inline std::string PropertyTypeToString(const PropertyValue &property_value) { + if (const auto schema_type = PropertyValueTypeToSchemaType(property_value); schema_type) { + return SchemaTypeToString(*schema_type); + } + return "Unknown"; +} + } // namespace memgraph::storage diff --git a/src/storage/v2/storage.cpp b/src/storage/v2/storage.cpp index f5064fadc..4b6e46709 100644 --- a/src/storage/v2/storage.cpp +++ b/src/storage/v2/storage.cpp @@ -28,6 +28,7 @@ #include "storage/v2/indices.hpp" #include "storage/v2/mvcc.hpp" #include "storage/v2/replication/config.hpp" +#include "storage/v2/schemas.hpp" #include "storage/v2/transaction.hpp" #include "storage/v2/vertex_accessor.hpp" #include "utils/file.hpp" @@ -456,12 +457,13 @@ VertexAccessor Storage::Accessor::CreateVertex() { OOMExceptionEnabler oom_exception; auto gid = storage_->vertex_id_.fetch_add(1, std::memory_order_acq_rel); auto acc = storage_->vertices_.access(); - auto delta = CreateDeleteObjectDelta(&transaction_); + auto *delta = CreateDeleteObjectDelta(&transaction_); auto [it, inserted] = acc.insert(Vertex{storage::Gid::FromUint(gid), delta}); MG_ASSERT(inserted, "The vertex must be inserted here!"); MG_ASSERT(it != acc.end(), "Invalid Vertex accessor!"); + delta->prev.Set(&*it); - return VertexAccessor(&*it, &transaction_, &storage_->indices_, &storage_->constraints_, config_); + return {&*it, &transaction_, &storage_->indices_, &storage_->constraints_, config_}; } VertexAccessor Storage::Accessor::CreateVertex(storage::Gid gid) { diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp index 7e55b22ca..1f38697a5 100644 --- a/src/storage/v2/storage.hpp +++ b/src/storage/v2/storage.hpp @@ -414,6 +414,12 @@ class Storage final { ConstraintsInfo ListAllConstraints() const; + /// @throw std::bad_alloc + bool CreateSchema(LabelId primary_label, std::vector<SchemaType> &schemas_types); + + /// @throw std::bad_alloc + bool DeleteSchema(LabelId primary_label); + SchemasInfo ListAllSchemas() const; StorageInfo GetInfo() const;