Implement SchemaTypes

This commit is contained in:
jbajic 2022-05-23 13:56:33 +02:00
parent 65b8e055a6
commit eb4d23c504
4 changed files with 164 additions and 33 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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) {

View File

@ -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;