Compare commits

...

3 Commits

Author SHA1 Message Date
jbajic
cd9faabf2c Gix visitor 2023-02-10 08:34:54 +01:00
jbajic
45c7689396 Propate config 2023-02-09 23:06:49 +01:00
jbajic
24225eee32 Add query & schema support 2023-02-09 22:30:07 +01:00
16 changed files with 194 additions and 76 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -16,4 +16,6 @@
namespace memgraph::common {
enum class SchemaType : uint8_t { BOOL, INT, STRING, DATE, LOCALTIME, LOCALDATETIME, DURATION };
enum class SchemaConfigParams : uint8_t { REPLICATION_FACTOR, SPLIT_THRESHOLD };
} // namespace memgraph::common

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -33,6 +33,7 @@
#include <boost/preprocessor/cat.hpp>
#include "common/types.hpp"
#include "expr/ast.hpp"
#include "expr/ast/ast_visitor.hpp"
#include "expr/exceptions.hpp"
@@ -2941,6 +2942,40 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
return schema_property_map;
}
inline memgraph::common::SchemaConfigParams SchemaConfigKeyToEnum(std::string_view val) {
if (val == "replication_factor") {
return memgraph::common::SchemaConfigParams::REPLICATION_FACTOR;
} else if (val == "split_threshold") {
return memgraph::common::SchemaConfigParams::SPLIT_THRESHOLD;
}
throw memgraph::expr::SemanticException("Schema configuration parameter not recognized!");
}
/**
* @return Schema*
*/
antlrcpp::Any visitSchemaConfigKeyValuePair(MemgraphCypher::SchemaConfigKeyValuePairContext *ctx) override {
MG_ASSERT(ctx->literal().size() == 2);
const auto key_value =
SchemaConfigKeyToEnum(utils::ToLowerCase(std::any_cast<std::string>(ctx->literal(0)->accept(this))));
// TODO(jbajic) Introduce variable values here
const auto value = std::any_cast<int64_t>(ctx->literal(1)->accept(this));
return std::pair<common::SchemaConfigParams, int64_t>{key_value, value};
}
/**
* @return Schema*
*/
antlrcpp::Any visitSchemaConfiguration(MemgraphCypher::SchemaConfigurationContext *ctx) override {
std::unordered_map<common::SchemaConfigParams, int64_t> map;
for (auto *key_value_pair : ctx->schemaConfigKeyValuePair()) {
// If the queries are cached, then only the stripped query is parsed, so the actual keys cannot be determined
// here. That means duplicates cannot be checked.
map.insert(std::any_cast<std::pair<common::SchemaConfigParams, int64_t>>(key_value_pair->accept(this)));
}
return map;
}
/**
* @return Schema*
*/
@@ -2981,7 +3016,11 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
schema_query->label_ = AddLabel(std::any_cast<std::string>(ctx->labelName()->accept(this)));
schema_query->schema_type_map_ =
std::any_cast<std::vector<std::pair<PropertyIx, common::SchemaType>>>(ctx->schemaPropertyMap()->accept(this));
query_ = schema_query;
if (ctx->schemaConfiguration()) {
schema_query->schema_config_map_ = std::any_cast<std::unordered_map<common::SchemaConfigParams, int64_t>>(
ctx->schemaConfiguration()->accept(this));
query_ = schema_query;
}
return schema_query;
}

View File

@@ -394,6 +394,10 @@ propertyKeyTypePair : propertyKeyName propertyType ;
schemaPropertyMap : '(' propertyKeyTypePair ( ',' propertyKeyTypePair )* ')' ;
createSchema : CREATE SCHEMA ON ':' labelName schemaPropertyMap ;
schemaConfigKeyValuePair : literal '=' literal ;
schemaConfiguration : ( schemaConfigKeyValuePair ( ',' schemaConfigKeyValuePair )* )? ;
createSchema : CREATE SCHEMA ON ':' labelName schemaPropertyMap ( CONFIG schemaConfiguration ) ? ;
dropSchema : DROP SCHEMA ON ':' labelName ;

View File

@@ -147,6 +147,14 @@ cpp<#
}
cpp<#)
(defun clone-map (source dest)
#>cpp
${dest}.reserve(${source}.size());
for (const auto &[config_key, config_val]: ${source}) {
${dest}.emplace(config_key, config_val);
}
cpp<#)
;; The following index structs serve as a decoupling point of AST from
;; concrete database types. All the names are collected in AstStorage, and can
;; be indexed through these instances. This means that we can create a vector
@@ -2698,10 +2706,15 @@ cpp<#
#>cpp
${dest} = storage->GetLabelIx(${source}.name);
cpp<#))
(schema_type_map "std::vector<std::pair<PropertyIx, common::SchemaType>>"
:slk-save #'slk-save-property-map
:slk-load #'slk-load-property-map
:clone #'clone-schema-property-vector
:scope :public)
(schema_config_map "std::unordered_map<common::SchemaConfigParams, int64_t>"
:clone #'clone-map
:scope :public))
(:public

View File

@@ -22,6 +22,7 @@
#include <memory>
#include <optional>
#include "common/types.hpp"
#include "coordinator/coordinator_client.hpp"
#include "expr/ast/ast_visitor.hpp"
#include "io/local_transport/local_system.hpp"
@@ -542,7 +543,7 @@ Callback HandleSchemaQuery(SchemaQuery *schema_query, InterpreterContext *interp
std::vector<std::vector<TypedValue>> results;
results.reserve(schemas_info.schemas.size());
for (const auto &[label_id, schema_types] : schemas_info.schemas) {
for ([[maybe_unused]] const auto &[label_id, schema_types, config] : schemas_info.schemas) {
std::vector<TypedValue> schema_info_row;
schema_info_row.reserve(3);
@@ -570,7 +571,7 @@ Callback HandleSchemaQuery(SchemaQuery *schema_query, InterpreterContext *interp
const auto *schema = db->GetSchema(label);
std::vector<std::vector<TypedValue>> results;
if (schema) {
for (const auto &schema_property : schema->second) {
for (const auto &schema_property : schema->properties) {
std::vector<TypedValue> schema_info_row;
schema_info_row.reserve(2);
schema_info_row.emplace_back(db->PropertyToName(schema_property.property_id));
@@ -589,7 +590,8 @@ Callback HandleSchemaQuery(SchemaQuery *schema_query, InterpreterContext *interp
throw SyntaxException("One or more types have to be defined in schema definition.");
}
callback.fn = [interpreter_context, primary_label = schema_query->label_,
schema_type_map = std::move(schema_type_map)]() {
schema_type_map = std::move(schema_type_map),
config_map = std::move(schema_query->schema_config_map_)]() {
auto *db = interpreter_context->db;
const auto label = interpreter_context->NameToLabelId(primary_label.name);
std::vector<storage::v3::SchemaProperty> schemas_types;
@@ -598,8 +600,30 @@ Callback HandleSchemaQuery(SchemaQuery *schema_query, InterpreterContext *interp
auto property_id = interpreter_context->NameToPropertyId(schema_type.first.name);
schemas_types.push_back({property_id, schema_type.second});
}
if (!db->CreateSchema(label, schemas_types)) {
throw QueryException(fmt::format("Schema on label :{} already exists!", primary_label.name));
auto schema_config = std::invoke([&config_map]() -> std::optional<storage::v3::Schema::SchemaConfiguration> {
if (!config_map.empty()) {
return std::nullopt;
}
storage::v3::Schema::SchemaConfiguration config;
if (const auto replication_factor_it = config_map.find(common::SchemaConfigParams::REPLICATION_FACTOR);
replication_factor_it != config_map.end()) {
config.replication_factor = replication_factor_it->second;
}
if (const auto split_threshold_it = config_map.find(common::SchemaConfigParams::SPLIT_THRESHOLD);
split_threshold_it != config_map.end()) {
config.split_threshold = split_threshold_it->second;
}
return config;
});
// TODO FIx this late
if (schema_config) {
if (!db->CreateSchema(label, schemas_types, *schema_config)) {
throw QueryException(fmt::format("Schema on label :{} already exists!", primary_label.name));
}
} else {
if (!db->CreateSchema(label, schemas_types)) {
throw QueryException(fmt::format("Schema on label :{} already exists!", primary_label.name));
}
}
return std::vector<std::vector<TypedValue>>{};
};

View File

@@ -146,6 +146,14 @@ cpp<#
}
cpp<#)
(defun clone-map (source dest)
#>cpp
${dest}.reserve(${source}.size());
for (const auto &[config_key, config_val]: ${source}) {
${dest}.emplace(config_key, config_val);
}
cpp<#)
;; The following index structs serve as a decoupling point of AST from
;; concrete database types. All the names are collected in AstStorage, and can
;; be indexed through these instances. This means that we can create a vector
@@ -2705,10 +2713,15 @@ cpp<#
#>cpp
${dest} = storage->GetLabelIx(${source}.name);
cpp<#))
(schema_type_map "std::vector<std::pair<PropertyIx, common::SchemaType>>"
:slk-save #'slk-save-property-map
:slk-load #'slk-load-property-map
:clone #'clone-schema-property-vector
:scope :public)
(schema_config_map "std::unordered_map<common::SchemaConfigParams, int64_t>"
:clone #'clone-map
:scope :public))
(:public

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -44,7 +44,7 @@ struct VertexIdCmpr {
};
std::optional<std::map<PropertyId, Value>> PrimaryKeysFromAccessor(const VertexAccessor &acc, View view,
const Schemas::Schema &schema) {
const Schema &schema) {
std::map<PropertyId, Value> ret;
auto props = acc.Properties(view);
auto maybe_pk = acc.PrimaryKey(view);
@@ -53,9 +53,9 @@ std::optional<std::map<PropertyId, Value>> PrimaryKeysFromAccessor(const VertexA
return std::nullopt;
}
auto &pk = maybe_pk.GetValue();
MG_ASSERT(schema.second.size() == pk.size(), "PrimaryKey size does not match schema!");
for (size_t i{0}; i < schema.second.size(); ++i) {
ret.emplace(schema.second[i].property_id, FromPropertyValueToValue(std::move(pk[i])));
MG_ASSERT(schema.properties.size() == pk.size(), "PrimaryKey size does not match schema!");
for (size_t i{0}; i < schema.properties.size(); ++i) {
ret.emplace(schema.properties[i].property_id, FromPropertyValueToValue(std::move(pk[i])));
}
return ret;
@@ -82,8 +82,7 @@ ShardResult<std::vector<msgs::Label>> FillUpSourceVertexSecondaryLabels(const st
ShardResult<std::map<PropertyId, Value>> FillUpSourceVertexProperties(const std::optional<VertexAccessor> &v_acc,
const msgs::ExpandOneRequest &req,
storage::v3::View view,
const Schemas::Schema &schema) {
storage::v3::View view, const Schema &schema) {
std::map<PropertyId, Value> src_vertex_properties;
if (!req.src_vertex_properties) {
@@ -236,7 +235,7 @@ std::vector<TypedValue> EvaluateEdgeExpressions(DbAccessor &dba, const VertexAcc
}
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
const Schemas::Schema &schema) {
const Schema &schema) {
auto ret = impl::CollectAllPropertiesImpl<VertexAccessor>(acc, view);
if (ret.HasError()) {
return ret.GetError();
@@ -380,7 +379,7 @@ bool FilterOnEdge(DbAccessor &dba, const storage::v3::VertexAccessor &v_acc, con
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
Shard::Accessor &acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
const Schemas::Schema &schema) {
const Schema &schema) {
/// Fill up source vertex
const auto primary_key = ConvertPropertyVector(src_vertex.second);
auto v_acc = acc.FindVertex(primary_key, View::NEW);
@@ -423,7 +422,7 @@ ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
VertexAccessor v_acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
std::vector<EdgeAccessor> in_edge_accessors, std::vector<EdgeAccessor> out_edge_accessors,
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
const Schemas::Schema &schema) {
const Schema &schema) {
/// Fill up source vertex
msgs::Vertex source_vertex = {.id = src_vertex};
auto maybe_secondary_labels = FillUpSourceVertexSecondaryLabels(v_acc, req);

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -217,7 +217,7 @@ ShardResult<std::map<PropertyId, Value>> CollectSpecificPropertiesFromAccessor(c
}
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesFromAccessor(const VertexAccessor &acc, View view,
const Schemas::Schema &schema);
const Schema &schema);
namespace impl {
template <PropertiesAccessor TAccessor>
ShardResult<std::map<PropertyId, Value>> CollectAllPropertiesImpl(const TAccessor &acc, View view) {
@@ -249,11 +249,11 @@ EdgeFiller InitializeEdgeFillerFunction(const msgs::ExpandOneRequest &req);
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
Shard::Accessor &acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
const Schemas::Schema &schema);
const Schema &schema);
ShardResult<msgs::ExpandOneResultRow> GetExpandOneResult(
VertexAccessor v_acc, msgs::VertexId src_vertex, const msgs::ExpandOneRequest &req,
std::vector<EdgeAccessor> in_edge_accessors, std::vector<EdgeAccessor> out_edge_accessors,
const EdgeUniquenessFunction &maybe_filter_based_on_edge_uniqueness, const EdgeFiller &edge_filler,
const Schemas::Schema &schema);
const Schema &schema);
} // namespace memgraph::storage::v3

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -44,20 +44,20 @@ ShardResult<void> SchemaValidator::ValidateVertexCreate(LabelId primary_label, c
}
// Quick size check
if (schema->second.size() != primary_properties.size()) {
if (schema->properties.size() != primary_properties.size()) {
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED,
"Not all primary properties have been specified for :{} vertex",
name_id_mapper_->IdToName(primary_label.AsInt()));
}
// Check only properties defined by schema
for (size_t i{0}; i < schema->second.size(); ++i) {
for (size_t i{0}; i < schema->properties.size(); ++i) {
// Check schema property type
if (auto property_schema_type = PropertyTypeToSchemaType(primary_properties[i]);
property_schema_type && *property_schema_type != schema->second[i].type) {
property_schema_type && *property_schema_type != schema->properties[i].type) {
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE,
"Property {} is of wrong type, expected {}, actual {}",
name_id_mapper_->IdToName(schema->second[i].property_id.AsInt()),
SchemaTypeToString(schema->second[i].type), SchemaTypeToString(*property_schema_type));
name_id_mapper_->IdToName(schema->properties[i].property_id.AsInt()),
SchemaTypeToString(schema->properties[i].type), SchemaTypeToString(*property_schema_type));
}
}
@@ -72,9 +72,9 @@ ShardResult<void> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_
// Verify that updating property is not part of schema
if (const auto schema_property = std::ranges::find_if(
schema->second,
schema->properties,
[property_id](const auto &schema_property) { return property_id == schema_property.property_id; });
schema_property != schema->second.end()) {
schema_property != schema->properties.end()) {
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY,
"Cannot update primary property {} of schema on label :{}",
name_id_mapper_->IdToName(schema_property->property_id.AsInt()),
@@ -92,7 +92,7 @@ ShardResult<void> SchemaValidator::ValidateLabelUpdate(const LabelId label) cons
return {};
}
const Schemas::Schema *SchemaValidator::GetSchema(LabelId label) const { return schemas_->GetSchema(label); }
const Schema *SchemaValidator::GetSchema(LabelId label) const { return schemas_->GetSchema(label); }
VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const LabelId primary_label)
: schema_validator{&schema_validator}, primary_label_{primary_label} {}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -33,7 +33,7 @@ class SchemaValidator {
[[nodiscard]] ShardResult<void> ValidateLabelUpdate(LabelId label) const;
const Schemas::Schema *GetSchema(LabelId label) const;
const Schema *GetSchema(LabelId label) const;
private:
Schemas *schemas_;

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -25,25 +25,26 @@ bool operator==(const SchemaProperty &lhs, const SchemaProperty &rhs) {
}
Schemas::SchemasList Schemas::ListSchemas() const {
Schemas::SchemasList ret;
SchemasList ret;
ret.reserve(schemas_.size());
std::transform(schemas_.begin(), schemas_.end(), std::back_inserter(ret),
[](const auto &schema_property_type) { return schema_property_type; });
[](const auto &schema_property_type) { return schema_property_type.second; });
return ret;
}
const Schemas::Schema *Schemas::GetSchema(const LabelId primary_label) const {
const Schema *Schemas::GetSchema(const LabelId primary_label) const {
if (auto schema_map = schemas_.find(primary_label); schema_map != schemas_.end()) {
return &*schema_map;
return &schema_map->second;
}
return nullptr;
}
bool Schemas::CreateSchema(const LabelId primary_label, const std::vector<SchemaProperty> &schemas_types) {
bool Schemas::CreateSchema(const LabelId primary_label, const std::vector<SchemaProperty> &schemas_types,
Schema::SchemaConfiguration config) {
if (schemas_.contains(primary_label)) {
return false;
}
schemas_.emplace(primary_label, schemas_types);
schemas_.insert({primary_label, Schema{.label = primary_label, .properties = schemas_types, .config = config}});
return true;
}
@@ -51,9 +52,9 @@ bool Schemas::DropSchema(const LabelId primary_label) { return schemas_.erase(pr
bool Schemas::IsPropertyKey(const LabelId primary_label, const PropertyId property_id) const {
if (const auto schema = schemas_.find(primary_label); schema != schemas_.end()) {
return std::ranges::find_if(schema->second, [property_id](const auto &elem) {
return std::ranges::find_if(schema->second.properties, [property_id](const auto &elem) {
return elem.property_id == property_id;
}) != schema->second.end();
}) != schema->second.properties.end();
}
throw utils::BasicException("Schema not found!");
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -11,6 +11,7 @@
#pragma once
#include <cstdint>
#include <memory>
#include <optional>
#include <unordered_map>
@@ -43,12 +44,24 @@ struct SchemaProperty {
}
};
struct Schema {
LabelId label;
std::vector<SchemaProperty> properties;
struct SchemaConfiguration {
uint64_t replication_factor;
uint64_t split_threshold;
} config;
friend bool operator==(const Schema &lhs, const Schema &rhs) noexcept {
return lhs.label == rhs.label && lhs.properties == rhs.properties;
}
};
/// Structure that represents a collection of schemas
/// Schema can be mapped under only one label => primary label
class Schemas {
public:
using SchemasMap = std::unordered_map<LabelId, std::vector<SchemaProperty>>;
using Schema = SchemasMap::value_type;
using SchemasMap = std::unordered_map<LabelId, Schema>;
using SchemasList = std::vector<Schema>;
Schemas() = default;
@@ -64,7 +77,8 @@ class Schemas {
// Returns true if it was successfully created or false if the schema
// already exists
[[nodiscard]] bool CreateSchema(LabelId primary_label, const std::vector<SchemaProperty> &schemas_types);
[[nodiscard]] bool CreateSchema(LabelId primary_label, const std::vector<SchemaProperty> &schemas_types,
Schema::SchemaConfiguration config = {});
// Returns true if it was successfully dropped or false if the schema
// does not exist

View File

@@ -35,6 +35,7 @@
#include "storage/v3/property_value.hpp"
#include "storage/v3/result.hpp"
#include "storage/v3/schema_validator.hpp"
#include "storage/v3/schemas.hpp"
#include "storage/v3/transaction.hpp"
#include "storage/v3/vertex.hpp"
#include "storage/v3/vertex_accessor.hpp"
@@ -403,8 +404,6 @@ ShardResult<VertexAccessor> Shard::Accessor::CreateVertexAndValidate(
const std::vector<LabelId> &labels, const PrimaryKey &primary_properties,
const std::vector<std::pair<PropertyId, PropertyValue>> &properties) {
OOMExceptionEnabler oom_exception;
const auto schema = shard_->GetSchema(shard_->primary_label_)->second;
auto maybe_schema_violation =
GetSchemaValidator().ValidateVertexCreate(shard_->primary_label_, labels, primary_properties);
if (maybe_schema_violation.HasError()) {
@@ -907,8 +906,8 @@ bool Shard::CreateIndex(LabelId label, const std::optional<uint64_t> /*desired_c
bool Shard::CreateIndex(LabelId label, PropertyId property,
const std::optional<uint64_t> /*desired_commit_timestamp*/) {
// TODO(jbajic) response should be different when index conflicts with schema
if (label == primary_label_ && schemas_.GetSchema(primary_label_)->second.size() == 1 &&
schemas_.GetSchema(primary_label_)->second[0].property_id == property) {
if (label == primary_label_ && schemas_.GetSchema(primary_label_)->properties.size() == 1 &&
schemas_.GetSchema(primary_label_)->properties[0].property_id == property) {
// Index already exists on primary key
return false;
}
@@ -934,10 +933,11 @@ const SchemaValidator &Shard::Accessor::GetSchemaValidator() const { return shar
SchemasInfo Shard::ListAllSchemas() const { return {schemas_.ListSchemas()}; }
const Schemas::Schema *Shard::GetSchema(const LabelId primary_label) const { return schemas_.GetSchema(primary_label); }
const Schema *Shard::GetSchema(const LabelId primary_label) const { return schemas_.GetSchema(primary_label); }
bool Shard::CreateSchema(const LabelId primary_label, const std::vector<SchemaProperty> &schemas_types) {
return schemas_.CreateSchema(primary_label, schemas_types);
bool Shard::CreateSchema(const LabelId primary_label, const std::vector<SchemaProperty> &schemas_types,
Schema::SchemaConfiguration config) {
return schemas_.CreateSchema(primary_label, schemas_types, config);
}
bool Shard::DropSchema(const LabelId primary_label) { return schemas_.DropSchema(primary_label); }

View File

@@ -364,9 +364,10 @@ class Shard final {
SchemasInfo ListAllSchemas() const;
const Schemas::Schema *GetSchema(LabelId primary_label) const;
const Schema *GetSchema(LabelId primary_label) const;
bool CreateSchema(LabelId primary_label, const std::vector<SchemaProperty> &schemas_types);
bool CreateSchema(LabelId primary_label, const std::vector<SchemaProperty> &schemas_types,
Schema::SchemaConfiguration = {});
bool DropSchema(LabelId primary_label);

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -396,8 +396,8 @@ PropertyValue VertexAccessor::GetPropertyValue(PropertyId property, View view) c
return value;
}
// Find PropertyId index in keystore
for (size_t property_index{0}; property_index < schema->second.size(); ++property_index) {
if (schema->second[property_index].property_id == property) {
for (size_t property_index{0}; property_index < schema->properties.size(); ++property_index) {
if (schema->properties[property_index].property_id == property) {
return vertex_->first[property_index];
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Memgraph Ltd.
// Copyright 2023 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
@@ -60,18 +60,22 @@ TEST_F(SchemaTest, TestSchemaCreate) {
EXPECT_TRUE(schemas.CreateSchema(label2, {schema_prop_string, schema_prop_int}));
const auto current_schemas = schemas.ListSchemas();
EXPECT_EQ(current_schemas.size(), 2);
EXPECT_THAT(current_schemas,
UnorderedElementsAre(Pair(label1, std::vector<SchemaProperty>{schema_prop_string}),
Pair(label2, std::vector<SchemaProperty>{schema_prop_string, schema_prop_int})));
EXPECT_THAT(
current_schemas,
UnorderedElementsAre(
Schema{.label = label1, .properties = std::vector<SchemaProperty>{schema_prop_string}},
Schema{.label = label2, .properties = std::vector<SchemaProperty>{schema_prop_string, schema_prop_int}}));
}
{
// Assert after unsuccessful creation, number oif schemas remains the same
EXPECT_FALSE(schemas.CreateSchema(label2, {schema_prop_int}));
const auto current_schemas = schemas.ListSchemas();
EXPECT_EQ(current_schemas.size(), 2);
EXPECT_THAT(current_schemas,
UnorderedElementsAre(Pair(label1, std::vector<SchemaProperty>{schema_prop_string}),
Pair(label2, std::vector<SchemaProperty>{schema_prop_string, schema_prop_int})));
EXPECT_THAT(
current_schemas,
UnorderedElementsAre(
Schema{.label = label1, .properties = std::vector<SchemaProperty>{schema_prop_string}},
Schema{.label = label2, .properties = std::vector<SchemaProperty>{schema_prop_string, schema_prop_int}}));
}
}
@@ -89,27 +93,29 @@ TEST_F(SchemaTest, TestSchemaList) {
{
const auto current_schemas = schemas.ListSchemas();
EXPECT_EQ(current_schemas.size(), 2);
EXPECT_THAT(current_schemas,
UnorderedElementsAre(
Pair(label1, std::vector<SchemaProperty>{schema_prop_string}),
Pair(label2, std::vector<SchemaProperty>{{NameToProperty("prop1"), SchemaType::STRING},
EXPECT_THAT(
current_schemas,
UnorderedElementsAre(
Schema{.label = label1, .properties = std::vector<SchemaProperty>{schema_prop_string}},
Schema{.label = label2,
.properties = std::vector<SchemaProperty>{{NameToProperty("prop}"), SchemaType::STRING},
{NameToProperty("prop2"), SchemaType::INT},
{NameToProperty("prop3"), SchemaType::BOOL},
{NameToProperty("prop4"), SchemaType::DATE},
{NameToProperty("prop5"), SchemaType::LOCALDATETIME},
{NameToProperty("prop6"), SchemaType::DURATION},
{NameToProperty("prop7"), SchemaType::LOCALTIME}})));
{NameToProperty("prop7"), SchemaType::LOCALTIME}}}));
}
{
const auto *const schema1 = schemas.GetSchema(label1);
ASSERT_NE(schema1, nullptr);
EXPECT_EQ(*schema1, (Schemas::Schema{label1, std::vector<SchemaProperty>{schema_prop_string}}));
EXPECT_EQ(*schema1, (Schema{.label = label1, .properties = std::vector<SchemaProperty>{schema_prop_string}}));
}
{
const auto *const schema2 = schemas.GetSchema(label2);
ASSERT_NE(schema2, nullptr);
EXPECT_EQ(schema2->first, label2);
EXPECT_EQ(schema2->second.size(), 7);
EXPECT_EQ(schema2->label, label2);
EXPECT_EQ(schema2->properties.size(), 7);
}
}
@@ -132,7 +138,8 @@ TEST_F(SchemaTest, TestSchemaDrop) {
const auto current_schemas = schemas.ListSchemas();
EXPECT_EQ(current_schemas.size(), 1);
EXPECT_THAT(current_schemas,
UnorderedElementsAre(Pair(label2, std::vector<SchemaProperty>{schema_prop_string, schema_prop_int})));
UnorderedElementsAre(Schema{
.label = label2, .properties = std::vector<SchemaProperty>{schema_prop_string, schema_prop_int}}));
}
{
@@ -141,7 +148,8 @@ TEST_F(SchemaTest, TestSchemaDrop) {
const auto current_schemas = schemas.ListSchemas();
EXPECT_EQ(current_schemas.size(), 1);
EXPECT_THAT(current_schemas,
UnorderedElementsAre(Pair(label2, std::vector<SchemaProperty>{schema_prop_string, schema_prop_int})));
UnorderedElementsAre(Schema{
.label = label2, .properties = std::vector<SchemaProperty>{schema_prop_string, schema_prop_int}}));
}
EXPECT_TRUE(schemas.DropSchema(label2));