Implement SchemaTypes
This commit is contained in:
parent
65b8e055a6
commit
eb4d23c504
@ -9,7 +9,6 @@
|
|||||||
// by the Apache License, Version 2.0, included in the file
|
// by the Apache License, Version 2.0, included in the file
|
||||||
// licenses/APL.txt.
|
// licenses/APL.txt.
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -19,40 +18,53 @@
|
|||||||
|
|
||||||
namespace memgraph::storage {
|
namespace memgraph::storage {
|
||||||
|
|
||||||
Schemas::CreationStatus Schemas::CreateSchema(
|
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label) : status{status}, label{label} {}
|
||||||
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, 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;
|
return res ? Schemas::CreationStatus::SUCCESS : Schemas::CreationStatus::FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Schemas::DeletionStatus Schemas::DeleteSchema(const LabelId label) {
|
Schemas::DeletionStatus Schemas::DeleteSchema(const LabelId primary_label) {
|
||||||
auto res = schemas_.erase(label);
|
auto res = schemas_.erase(primary_label);
|
||||||
return res != 0 ? Schemas::DeletionStatus::SUCCESS : Schemas::DeletionStatus::FAIL;
|
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)) {
|
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)) {
|
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]) {
|
for (auto &schema_type : schemas_[primary_label]) {
|
||||||
// Property existence check
|
if (!vertex.properties.HasProperty(schema_type.property_id)) {
|
||||||
if (!vertex.properties.HasProperty(property_id)) {
|
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_HAS_NO_PROPERTY, primary_label, schema_type);
|
||||||
return Schemas::ValidationStatus::VERTEX_HAS_NO_PROPERTY;
|
|
||||||
}
|
}
|
||||||
// Property type check
|
// Property type check
|
||||||
if (vertex.properties.GetProperty(property_id).type() != property_type) {
|
// TODO Can this be replaced with just property id check?
|
||||||
return Schemas::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE;
|
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
|
// TODO after the introduction of vertex hashing introduce check for vertex
|
||||||
// primary key uniqueness
|
// primary key uniqueness
|
||||||
|
|
||||||
return Schemas::ValidationStatus::SUCCESS;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Schemas::SchemasList Schemas::ListSchemas() const {
|
Schemas::SchemasList Schemas::ListSchemas() const {
|
||||||
|
@ -11,25 +11,61 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "storage/v2/id_types.hpp"
|
||||||
#include "storage/v2/indices.hpp"
|
#include "storage/v2/indices.hpp"
|
||||||
#include "storage/v2/property_value.hpp"
|
#include "storage/v2/property_value.hpp"
|
||||||
|
#include "storage/v2/temporal.hpp"
|
||||||
#include "storage/v2/transaction.hpp"
|
#include "storage/v2/transaction.hpp"
|
||||||
#include "storage/v2/vertex.hpp"
|
#include "storage/v2/vertex.hpp"
|
||||||
#include "utils/result.hpp"
|
#include "utils/result.hpp"
|
||||||
|
|
||||||
namespace memgraph::storage {
|
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
|
/// Structure that represents a collection of schemas
|
||||||
/// Schema can be mapped under only one label => primary label
|
/// Schema can be mapped under only one label => primary label
|
||||||
class Schemas {
|
class Schemas {
|
||||||
public:
|
public:
|
||||||
using SchemasStructure = std::unordered_map<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<std::pair<PropertyId, PropertyValue::Type>>>>;
|
using SchemasList = std::vector<std::pair<LabelId, std::vector<SchemaType>>>;
|
||||||
|
|
||||||
Schemas() = default;
|
Schemas() = default;
|
||||||
Schemas(const Schemas &) = delete;
|
Schemas(const Schemas &) = delete;
|
||||||
@ -40,21 +76,12 @@ class Schemas {
|
|||||||
|
|
||||||
enum class CreationStatus : uint8_t { SUCCESS, FAIL };
|
enum class CreationStatus : uint8_t { SUCCESS, FAIL };
|
||||||
enum class DeletionStatus : 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,
|
CreationStatus CreateSchema(LabelId label, const std::vector<SchemaType> &schemas_types);
|
||||||
const std::vector<std::pair<PropertyId, PropertyValue::Type>> &property_types);
|
|
||||||
|
|
||||||
DeletionStatus DeleteSchema(LabelId label);
|
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;
|
SchemasList ListSchemas() const;
|
||||||
|
|
||||||
@ -62,4 +89,88 @@ class Schemas {
|
|||||||
SchemasStructure 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
|
} // namespace memgraph::storage
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "storage/v2/indices.hpp"
|
#include "storage/v2/indices.hpp"
|
||||||
#include "storage/v2/mvcc.hpp"
|
#include "storage/v2/mvcc.hpp"
|
||||||
#include "storage/v2/replication/config.hpp"
|
#include "storage/v2/replication/config.hpp"
|
||||||
|
#include "storage/v2/schemas.hpp"
|
||||||
#include "storage/v2/transaction.hpp"
|
#include "storage/v2/transaction.hpp"
|
||||||
#include "storage/v2/vertex_accessor.hpp"
|
#include "storage/v2/vertex_accessor.hpp"
|
||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
@ -456,12 +457,13 @@ VertexAccessor Storage::Accessor::CreateVertex() {
|
|||||||
OOMExceptionEnabler oom_exception;
|
OOMExceptionEnabler oom_exception;
|
||||||
auto gid = storage_->vertex_id_.fetch_add(1, std::memory_order_acq_rel);
|
auto gid = storage_->vertex_id_.fetch_add(1, std::memory_order_acq_rel);
|
||||||
auto acc = storage_->vertices_.access();
|
auto acc = storage_->vertices_.access();
|
||||||
auto delta = CreateDeleteObjectDelta(&transaction_);
|
auto *delta = CreateDeleteObjectDelta(&transaction_);
|
||||||
auto [it, inserted] = acc.insert(Vertex{storage::Gid::FromUint(gid), delta});
|
auto [it, inserted] = acc.insert(Vertex{storage::Gid::FromUint(gid), delta});
|
||||||
MG_ASSERT(inserted, "The vertex must be inserted here!");
|
MG_ASSERT(inserted, "The vertex must be inserted here!");
|
||||||
MG_ASSERT(it != acc.end(), "Invalid Vertex accessor!");
|
MG_ASSERT(it != acc.end(), "Invalid Vertex accessor!");
|
||||||
|
|
||||||
delta->prev.Set(&*it);
|
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) {
|
VertexAccessor Storage::Accessor::CreateVertex(storage::Gid gid) {
|
||||||
|
@ -414,6 +414,12 @@ class Storage final {
|
|||||||
|
|
||||||
ConstraintsInfo ListAllConstraints() const;
|
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;
|
SchemasInfo ListAllSchemas() const;
|
||||||
|
|
||||||
StorageInfo GetInfo() const;
|
StorageInfo GetInfo() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user