Dressipi Test Cases No 1 - DONE
This commit is contained in:
parent
d45121a1a2
commit
dba261036b
@ -18,5 +18,9 @@ enum class ClauseAction : uint32_t
|
||||
ReturnPack,
|
||||
ReturnProjection,
|
||||
ReturnCount,
|
||||
ReturnLabels
|
||||
ReturnLabels,
|
||||
|
||||
UpdateEntityLabels,
|
||||
UpdateEntityLabels_Identifier,
|
||||
UpdateEntityLabels_Labels
|
||||
};
|
||||
|
@ -86,15 +86,75 @@ const std::string find_and_write_vertices_by_label =
|
||||
" stream.write_meta(\"rw\");\n";
|
||||
|
||||
const std::string find_and_write_vertices_by_label_and_properties =
|
||||
"{0}\n"
|
||||
" auto properties = query_properties(indices, args);\n"
|
||||
" auto &label = t.label_find_or_create(\"{1}\");\n"
|
||||
" stream.write_field(\"{2}\");\n"
|
||||
" label.index().for_range(t).properties_filter(t, properties).for_all(\n"
|
||||
"{{\n"
|
||||
" DbAccessor _t(db);\n"
|
||||
" {0}\n"
|
||||
" auto properties = query_properties(indices, args);\n"
|
||||
" auto &label = _t.label_find_or_create(\"{1}\");\n"
|
||||
" stream.write_field(\"{2}\");\n"
|
||||
" label.index().for_range(_t).properties_filter(_t, properties).for_all(\n"
|
||||
" [&](auto vertex_accessor) -> void {{\n"
|
||||
" "+ write_vertex_accessor +
|
||||
" }});\n"
|
||||
" stream.write_meta(\"rw\");\n"
|
||||
" _t.commit();"
|
||||
"}}\n";
|
||||
|
||||
// -- LABELS
|
||||
const std::string set_vertex_element =
|
||||
"{{\n"
|
||||
" DbAccessor _t(db);" // TODO: HACK (set labels should somehow persist the state)
|
||||
" {0}\n"
|
||||
" auto properties = query_properties(indices, args);\n"
|
||||
" auto &label = _t.label_find_or_create(\"{1}\");\n"
|
||||
" label.index().for_range(_t).properties_filter(_t, properties).for_all(\n"
|
||||
" [&](auto vertex_accessor) -> void {{\n"
|
||||
" "+ write_vertex_accessor +
|
||||
" }});\n"
|
||||
" stream.write_meta(\"rw\");\n";
|
||||
" auto {2} = _t.vertex_property_key(\"{2}\", args[{3}].key.flags());\n"
|
||||
" vertex_accessor.set({2}, std::move(args[{3}]));\n"
|
||||
" }}\n"
|
||||
" );\n"
|
||||
" _t.commit();\n"
|
||||
"}}";
|
||||
|
||||
const std::string set_labels_start =
|
||||
" {{\n"
|
||||
" DbAccessor _t(db);" // TODO: HACK (set labels should somehow persist the state)
|
||||
" {0}\n"
|
||||
" auto properties = query_properties(indices, args);\n"
|
||||
" auto &label = _t.label_find_or_create(\"{1}\");\n"
|
||||
" label.index().for_range(_t).properties_filter(_t, properties).for_all(\n"
|
||||
" [&](auto vertex_accessor) -> void {{\n";
|
||||
const std::string set_label =
|
||||
" auto &{0} = _t.label_find_or_create(\"{0}\");\n"
|
||||
" vertex_accessor.add_label({0});\n";
|
||||
const std::string set_labels_end =
|
||||
" }}\n"
|
||||
" );\n"
|
||||
" _t.commit();"
|
||||
" }}";
|
||||
|
||||
const std::string return_labels =
|
||||
"{{\n"
|
||||
" DbAccessor _t(db);" // TODO: HACK (set labels should somehow persist the state)
|
||||
" {0}\n"
|
||||
" auto properties = query_properties(indices, args);\n"
|
||||
" auto &label = _t.label_find_or_create(\"{1}\");\n"
|
||||
" stream.write_field(\"labels({2})\");\n"
|
||||
" label.index().for_range(_t).properties_filter(_t, properties).for_all(\n"
|
||||
" [&](auto vertex_accessor) -> void {{\n"
|
||||
" auto &labels = vertex_accessor.labels();\n"
|
||||
" stream.write_record();\n"
|
||||
" stream.write_list_header(1);\n" // TODO: figure out why
|
||||
" stream.write_list_header(labels.size());\n"
|
||||
" for (auto &label : labels) {{\n"
|
||||
" stream.write(label.get().str());\n"
|
||||
" }}\n"
|
||||
" stream.chunk();\n"
|
||||
" }}\n"
|
||||
" );\n"
|
||||
" stream.write_meta(\"rw\");\n"
|
||||
" _t.commit();\n"
|
||||
"}}";
|
||||
|
||||
const std::string write_all_edges =
|
||||
"stream.write_field(\"{0}\");\n"
|
||||
|
@ -66,8 +66,6 @@ auto return_query_action =
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (cypher_data.source(entity) == EntitySource::TypeIndex)
|
||||
{
|
||||
if (cypher_data.type(entity) == EntityType::Relationship)
|
||||
@ -116,7 +114,17 @@ auto return_query_action =
|
||||
}
|
||||
if (kv.second == ClauseAction::ReturnLabels)
|
||||
{
|
||||
// TODO: similar to above
|
||||
if (cypher_data.source(name) == EntitySource::LabelIndex)
|
||||
{
|
||||
auto tags = cypher_data.tags(name);
|
||||
if (tags.size() == 1)
|
||||
{
|
||||
auto label = tags.at(0);
|
||||
code += code_line(code::return_labels,
|
||||
cypher_data.print_indices(name), label,
|
||||
name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,21 +7,66 @@ auto set_query_action = [](CypherStateData &cypher_data,
|
||||
|
||||
std::string code = "";
|
||||
|
||||
for (auto const &kv : action_data.actions) {
|
||||
for (auto const &kv : action_data.actions)
|
||||
{
|
||||
auto name = kv.first;
|
||||
|
||||
if (kv.second == ClauseAction::UpdateNode &&
|
||||
cypher_data.status(name) == EntityStatus::Matched &&
|
||||
cypher_data.type(name) == EntityType::Node) {
|
||||
cypher_data.source(name) == EntitySource::InternalId &&
|
||||
cypher_data.type(name) == EntityType::Node)
|
||||
{
|
||||
code += update_properties(cypher_data, action_data, name);
|
||||
}
|
||||
|
||||
if (kv.second == ClauseAction::UpdateNode &&
|
||||
cypher_data.status(name) == EntityStatus::Matched &&
|
||||
cypher_data.source(name) == EntitySource::LabelIndex &&
|
||||
cypher_data.type(name) == EntityType::Node)
|
||||
{
|
||||
auto entity_data = action_data.get_entity_property(name);
|
||||
for (auto &property : entity_data.properties)
|
||||
{
|
||||
auto index = action_data.parameter_index.at(
|
||||
ParameterIndexKey(name, property));
|
||||
auto tmp_name = name::unique();
|
||||
auto label = cypher_data.tags(name).at(0);
|
||||
// TODO: move this code inside the loop (in generated code)
|
||||
code += code_line(code::set_vertex_element,
|
||||
cypher_data.print_indices(name), label,
|
||||
property, index);
|
||||
}
|
||||
}
|
||||
|
||||
if (kv.second == ClauseAction::UpdateRelationship &&
|
||||
cypher_data.status(name) == EntityStatus::Matched &&
|
||||
cypher_data.type(name) == EntityType::Relationship) {
|
||||
cypher_data.type(name) == EntityType::Relationship)
|
||||
{
|
||||
code += update_properties(cypher_data, action_data, name);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const &set_entity_labels : action_data.label_set_elements)
|
||||
{
|
||||
auto &entity = set_entity_labels.entity;
|
||||
|
||||
if (cypher_data.status(entity) == EntityStatus::Matched &&
|
||||
cypher_data.source(entity) == EntitySource::LabelIndex)
|
||||
{
|
||||
auto label = cypher_data.tags(entity).at(0);
|
||||
if (cypher_data.has_properties(entity))
|
||||
{
|
||||
code += code_line(code::set_labels_start,
|
||||
cypher_data.print_indices(entity), label);
|
||||
auto labels = set_entity_labels.labels;
|
||||
for (auto const &set_label : labels)
|
||||
{
|
||||
code += code_line(code::set_label, set_label);
|
||||
}
|
||||
code += code_line(code::set_labels_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
};
|
||||
|
@ -111,6 +111,22 @@ struct ReturnElement
|
||||
bool is_projection() const { return has_entity() && has_property(); }
|
||||
};
|
||||
|
||||
struct LabelSetElement
|
||||
{
|
||||
std::string entity;
|
||||
std::vector<std::string> labels;
|
||||
|
||||
LabelSetElement() = default;
|
||||
LabelSetElement(const LabelSetElement&) = default;
|
||||
LabelSetElement(LabelSetElement&&) = default;
|
||||
|
||||
void clear()
|
||||
{
|
||||
entity.clear();
|
||||
labels.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct QueryActionData
|
||||
{
|
||||
std::map<ParameterIndexKey, uint64_t> parameter_index;
|
||||
@ -118,6 +134,7 @@ struct QueryActionData
|
||||
std::map<std::string, EntityData> entity_data;
|
||||
std::map<std::string, RelationshipData> relationship_data;
|
||||
std::vector<ReturnElement> return_elements;
|
||||
std::vector<LabelSetElement> label_set_elements;
|
||||
bool is_detach;
|
||||
CypherStateMachine csm;
|
||||
|
||||
|
@ -30,8 +30,8 @@ struct SetElementState
|
||||
void clear()
|
||||
{
|
||||
set_entity = "";
|
||||
set_prop = "";
|
||||
set_index = -1;
|
||||
set_prop = "";
|
||||
set_index = -1;
|
||||
}
|
||||
};
|
||||
|
||||
@ -52,7 +52,7 @@ struct PropertyState
|
||||
|
||||
void clear()
|
||||
{
|
||||
property_name = "";
|
||||
property_name = "";
|
||||
property_index = -1;
|
||||
}
|
||||
};
|
||||
@ -79,6 +79,7 @@ private:
|
||||
RelationshipData::Direction direction;
|
||||
|
||||
SetElementState set_element_state;
|
||||
LabelSetElement labels_set_element;
|
||||
PropertyState property_state;
|
||||
|
||||
void clear_state()
|
||||
@ -95,7 +96,9 @@ private:
|
||||
void finish_query_execution()
|
||||
{
|
||||
generator.add_action(QueryAction::TransactionCommit);
|
||||
|
||||
code += generator.generate();
|
||||
|
||||
generator.clear();
|
||||
}
|
||||
|
||||
@ -182,7 +185,7 @@ public:
|
||||
code += generator.generate();
|
||||
generator.add_action(QueryAction::Create);
|
||||
|
||||
state = CypherState::Create;
|
||||
state = CypherState::Create;
|
||||
query_action = QueryAction::Create;
|
||||
|
||||
Traverser::visit(ast_create);
|
||||
@ -194,10 +197,12 @@ public:
|
||||
|
||||
generator.add_action(QueryAction::Set);
|
||||
|
||||
state = CypherState::Set;
|
||||
state = CypherState::Set;
|
||||
query_action = QueryAction::Set;
|
||||
|
||||
Traverser::visit(ast_set);
|
||||
|
||||
code += generator.generate();
|
||||
}
|
||||
|
||||
void visit(ast::Return &ast_return) override
|
||||
@ -206,7 +211,7 @@ public:
|
||||
|
||||
generator.add_action(QueryAction::Return);
|
||||
|
||||
state = CypherState::Return;
|
||||
state = CypherState::Return;
|
||||
query_action = QueryAction::Return;
|
||||
|
||||
Traverser::visit(ast_return);
|
||||
@ -225,11 +230,14 @@ public:
|
||||
void visit(ast::Pattern &ast_pattern) override
|
||||
{
|
||||
// TODO: Is that traversal order OK for all cases? Probably NOT.
|
||||
if (ast_pattern.has_next()) {
|
||||
if (ast_pattern.has_next())
|
||||
{
|
||||
visit(*ast_pattern.next);
|
||||
visit(*ast_pattern.node);
|
||||
visit(*ast_pattern.relationship);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Traverser::visit(ast_pattern);
|
||||
}
|
||||
}
|
||||
@ -242,17 +250,22 @@ public:
|
||||
if (!ast_node.has_identifier()) return;
|
||||
|
||||
auto name = ast_node.idn->name;
|
||||
entity = name;
|
||||
entity = name;
|
||||
visited_nodes.push_back(name);
|
||||
|
||||
if (state == CypherState::Match) {
|
||||
if (state == CypherState::Match)
|
||||
{
|
||||
action_data.actions[name] = ClauseAction::MatchNode;
|
||||
}
|
||||
|
||||
if (state == CypherState::Create) {
|
||||
if (cypher_data.status(name) == EntityStatus::Matched) {
|
||||
if (state == CypherState::Create)
|
||||
{
|
||||
if (cypher_data.status(name) == EntityStatus::Matched)
|
||||
{
|
||||
action_data.actions[name] = ClauseAction::MatchNode;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
action_data.actions[name] = ClauseAction::CreateNode;
|
||||
}
|
||||
}
|
||||
@ -260,7 +273,8 @@ public:
|
||||
Traverser::visit(ast_node);
|
||||
|
||||
if (cypher_data.status(name) != EntityStatus::Matched &&
|
||||
state == CypherState::Create) {
|
||||
state == CypherState::Create)
|
||||
{
|
||||
cypher_data.node_created(name);
|
||||
}
|
||||
}
|
||||
@ -286,9 +300,9 @@ public:
|
||||
// -- RELATIONSHIP --
|
||||
void create_relationship(const std::string &name)
|
||||
{
|
||||
auto &data = generator.action_data();
|
||||
auto &data = generator.action_data();
|
||||
data.actions[name] = ClauseAction::CreateRelationship;
|
||||
auto nodes = visited_nodes.last_two();
|
||||
auto nodes = visited_nodes.last_two();
|
||||
data.relationship_data.emplace(name,
|
||||
RelationshipData(nodes, direction));
|
||||
}
|
||||
@ -301,7 +315,7 @@ public:
|
||||
if (!ast_relationship.has_name()) return;
|
||||
entity = ast_relationship.name();
|
||||
|
||||
using ast_direction = ast::Relationship::Direction;
|
||||
using ast_direction = ast::Relationship::Direction;
|
||||
using generator_direction = RelationshipData::Direction;
|
||||
|
||||
if (ast_relationship.direction == ast_direction::Left)
|
||||
@ -313,15 +327,19 @@ public:
|
||||
// TODO: add suport for Direction::Both
|
||||
|
||||
// TODO: simplify somehow
|
||||
if (state == CypherState::Create) {
|
||||
if (!cypher_data.exist(entity)) {
|
||||
if (state == CypherState::Create)
|
||||
{
|
||||
if (!cypher_data.exist(entity))
|
||||
{
|
||||
clause_action = ClauseAction::CreateRelationship;
|
||||
create_relationship(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (state == CypherState::Match) {
|
||||
if (!cypher_data.exist(entity)) {
|
||||
if (state == CypherState::Match)
|
||||
{
|
||||
if (!cypher_data.exist(entity))
|
||||
{
|
||||
action_data.actions[entity] = ClauseAction::MatchRelationship;
|
||||
}
|
||||
}
|
||||
@ -331,20 +349,25 @@ public:
|
||||
|
||||
void visit(ast::RelationshipSpecs &ast_relationship_specs) override
|
||||
{
|
||||
if (state == CypherState::Match) {
|
||||
if (ast_relationship_specs.has_identifier()) {
|
||||
auto name = ast_relationship_specs.name();
|
||||
if (state == CypherState::Match)
|
||||
{
|
||||
if (ast_relationship_specs.has_identifier())
|
||||
{
|
||||
auto name = ast_relationship_specs.name();
|
||||
auto &cypher_data = generator.cypher_data();
|
||||
if (!cypher_data.exist(name)) {
|
||||
clause_action = ClauseAction::MatchRelationship;
|
||||
auto &data = generator.action_data();
|
||||
if (!cypher_data.exist(name))
|
||||
{
|
||||
clause_action = ClauseAction::MatchRelationship;
|
||||
auto &data = generator.action_data();
|
||||
data.actions[name] = ClauseAction::MatchRelationship;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state == CypherState::Create) {
|
||||
if (ast_relationship_specs.has_identifier()) {
|
||||
if (state == CypherState::Create)
|
||||
{
|
||||
if (ast_relationship_specs.has_identifier())
|
||||
{
|
||||
entity = ast_relationship_specs.name();
|
||||
}
|
||||
}
|
||||
@ -356,7 +379,8 @@ public:
|
||||
{
|
||||
auto &action_data = generator.action_data();
|
||||
|
||||
if (ast_relationship_type_list.has_value()) {
|
||||
if (ast_relationship_type_list.has_value())
|
||||
{
|
||||
auto type = ast_relationship_type_list.value->name;
|
||||
action_data.add_entity_tag(entity, type);
|
||||
action_data.csm.search_cost(entity,
|
||||
@ -369,6 +393,13 @@ public:
|
||||
|
||||
void visit(ast::LabelList &ast_label_list) override
|
||||
{
|
||||
if (state == CypherState::Set)
|
||||
{
|
||||
clause_action = ClauseAction::UpdateEntityLabels_Labels;
|
||||
Traverser::visit(ast_label_list);
|
||||
return;
|
||||
}
|
||||
|
||||
auto &action_data = generator.action_data();
|
||||
auto &cypher_data = generator.cypher_data();
|
||||
|
||||
@ -398,12 +429,13 @@ public:
|
||||
Traverser::visit(ast_property);
|
||||
|
||||
// TODO: too ugly refactor somehow (clear_state part is awful)
|
||||
if (entity.empty() || !property_state.is_defined()) {
|
||||
if (entity.empty() || !property_state.is_defined())
|
||||
{
|
||||
clear_state();
|
||||
return;
|
||||
}
|
||||
|
||||
auto prop = property_state.property_name;
|
||||
auto prop = property_state.property_name;
|
||||
auto index = property_state.property_index;
|
||||
|
||||
// update action data
|
||||
@ -423,20 +455,33 @@ public:
|
||||
{
|
||||
property_state.property_name = ast_identifier.name;
|
||||
|
||||
if (state == CypherState::Delete) {
|
||||
if (state == CypherState::Delete)
|
||||
{
|
||||
auto &action_data = generator.action_data();
|
||||
auto name = ast_identifier.name;
|
||||
auto name = ast_identifier.name;
|
||||
auto &cypher_data = generator.cypher_data();
|
||||
if (cypher_data.type(name) == EntityType::Node)
|
||||
action_data.actions[name] = ClauseAction::DeleteNode;
|
||||
if (cypher_data.type(name) == EntityType::Relationship)
|
||||
action_data.actions[name] = ClauseAction::DeleteRelationship;
|
||||
}
|
||||
|
||||
if (state == CypherState::Set &&
|
||||
clause_action == ClauseAction::UpdateEntityLabels_Identifier)
|
||||
{
|
||||
labels_set_element.entity = ast_identifier.name;
|
||||
}
|
||||
|
||||
if (state == CypherState::Set &&
|
||||
clause_action == ClauseAction::UpdateEntityLabels_Labels)
|
||||
{
|
||||
labels_set_element.labels.emplace_back(ast_identifier.name);
|
||||
}
|
||||
}
|
||||
|
||||
void visit(ast::Long &ast_long) override
|
||||
{
|
||||
set_element_state.set_index = ast_long.value;
|
||||
set_element_state.set_index = ast_long.value;
|
||||
property_state.property_index = ast_long.value;
|
||||
}
|
||||
|
||||
@ -454,17 +499,18 @@ public:
|
||||
{
|
||||
Traverser::visit(ast_set_element);
|
||||
|
||||
if (!set_element_state.is_defined()) {
|
||||
if (!set_element_state.is_defined())
|
||||
{
|
||||
clear_state();
|
||||
return;
|
||||
}
|
||||
|
||||
auto entity = set_element_state.set_entity;
|
||||
auto prop = set_element_state.set_prop;
|
||||
auto index = set_element_state.set_index;
|
||||
auto prop = set_element_state.set_prop;
|
||||
auto index = set_element_state.set_index;
|
||||
|
||||
auto &cypher_data = generator.cypher_data();
|
||||
auto entity_type = cypher_data.type(entity);
|
||||
auto entity_type = cypher_data.type(entity);
|
||||
|
||||
if (entity_type == EntityType::None)
|
||||
throw CypherSemanticError("Entity (" + entity + ") doesn't exist");
|
||||
@ -489,12 +535,16 @@ public:
|
||||
|
||||
auto &action_data = generator.action_data();
|
||||
|
||||
if (state == CypherState::Return) {
|
||||
if (state == CypherState::Return)
|
||||
{
|
||||
auto &return_elements = action_data.return_elements;
|
||||
auto &entity = ast_accessor.entity_name();
|
||||
if (!ast_accessor.has_prop()) {
|
||||
auto &entity = ast_accessor.entity_name();
|
||||
if (!ast_accessor.has_prop())
|
||||
{
|
||||
return_elements.emplace_back(ReturnElement(entity));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
auto &property = ast_accessor.entity_prop();
|
||||
return_elements.emplace_back(ReturnElement(entity, property));
|
||||
}
|
||||
@ -502,9 +552,10 @@ public:
|
||||
|
||||
if (!ast_accessor.has_prop()) return;
|
||||
|
||||
if (state == CypherState::Set) {
|
||||
if (state == CypherState::Set)
|
||||
{
|
||||
set_element_state.set_entity = ast_accessor.entity_name();
|
||||
set_element_state.set_prop = ast_accessor.entity_prop();
|
||||
set_element_state.set_prop = ast_accessor.entity_prop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,6 +564,21 @@ public:
|
||||
Traverser::visit(ast_set_value);
|
||||
}
|
||||
|
||||
void visit(ast::LabelSetElement &ast_label_set_element) override
|
||||
{
|
||||
clause_action = ClauseAction::UpdateEntityLabels_Identifier;
|
||||
|
||||
labels_set_element.clear();
|
||||
|
||||
Traverser::visit(ast_label_set_element);
|
||||
|
||||
auto &action_data = generator.action_data();
|
||||
|
||||
action_data.label_set_elements.emplace_back(std::move(labels_set_element));
|
||||
|
||||
clause_action = ClauseAction::Undefined;
|
||||
}
|
||||
|
||||
void visit(ast::Delete &ast_delete) override
|
||||
{
|
||||
code += generator.generate();
|
||||
@ -536,4 +602,10 @@ public:
|
||||
action_data.actions[ast_count.argument] = ClauseAction::ReturnCount;
|
||||
// }
|
||||
}
|
||||
|
||||
void visit(ast::LabelsFunction &ast_label) override
|
||||
{
|
||||
auto &action_data = generator.action_data();
|
||||
action_data.actions[ast_label.argument] = ClauseAction::ReturnLabels;
|
||||
}
|
||||
};
|
||||
|
@ -70,6 +70,7 @@ struct ReadWriteQuery;
|
||||
struct SetKey;
|
||||
struct SetValue;
|
||||
struct SetElement;
|
||||
struct LabelSetElement;
|
||||
struct SetList;
|
||||
|
||||
struct WithList;
|
||||
@ -87,8 +88,8 @@ struct AstVisitor
|
||||
PatternList, Match, ReadQuery, Start, Where, WriteQuery, Create,
|
||||
Return, Distinct, Delete, DeleteQuery, UpdateQuery, Set, SetKey,
|
||||
ReadWriteQuery, IdentifierList, WithList, WithClause, WithQuery, Long,
|
||||
CountFunction, LabelsFunction,
|
||||
InternalIdExpr, SetValue, SetElement, SetList>
|
||||
CountFunction, LabelsFunction, InternalIdExpr, SetValue, SetElement,
|
||||
LabelSetElement, SetList>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
@ -35,7 +35,19 @@ struct SetValue : public AstNode<SetValue>
|
||||
bool has_value() const { return value != nullptr; }
|
||||
};
|
||||
|
||||
struct SetElement : public AstNode<SetElement>
|
||||
struct SetElementBase : public AstVisitable
|
||||
{
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
struct SetElementDerivedBase : public Crtp<Derived>, public SetElementBase
|
||||
{
|
||||
using uptr = std::unique_ptr<Derived>;
|
||||
|
||||
virtual void accept(AstVisitor &visitor) { visitor.visit(this->derived()); }
|
||||
};
|
||||
|
||||
struct SetElement : public SetElementDerivedBase<SetElement>
|
||||
{
|
||||
SetElement(Accessor* accessor, SetValue* set_value)
|
||||
: accessor(accessor), set_value(set_value) {}
|
||||
@ -47,7 +59,19 @@ struct SetElement : public AstNode<SetElement>
|
||||
bool has_value() const { return set_value != nullptr; }
|
||||
};
|
||||
|
||||
struct SetList : public List<SetElement, SetList>
|
||||
struct LabelSetElement : public SetElementDerivedBase<LabelSetElement>
|
||||
{
|
||||
LabelSetElement(Identifier* identifier, LabelList* label_list)
|
||||
: identifier(identifier), label_list(label_list) {}
|
||||
|
||||
Identifier* identifier;
|
||||
LabelList* label_list;
|
||||
|
||||
bool has_identifier() const { return identifier != nullptr; }
|
||||
bool has_label_list() const { return label_list != nullptr; }
|
||||
};
|
||||
|
||||
struct SetList : public List<SetElementBase, SetList>
|
||||
{
|
||||
using List::List;
|
||||
};
|
||||
|
@ -544,12 +544,16 @@ set_list(L) ::= set_element(E). {
|
||||
L = ast->create<ast::SetList>(E, nullptr);
|
||||
}
|
||||
|
||||
%type set_element {ast::SetElement*}
|
||||
%type set_element {ast::SetElementBase*}
|
||||
|
||||
set_element(E) ::= accessor(A) EQ set_value(V). {
|
||||
E = ast->create<ast::SetElement>(A, V);
|
||||
}
|
||||
|
||||
set_element(E) ::= idn(I) label_idn(L). {
|
||||
E = ast->create<ast::LabelSetElement>(I, L);
|
||||
}
|
||||
|
||||
%type accessor {ast::Accessor*}
|
||||
|
||||
accessor(A) ::= idn(E) DOT idn(P). {
|
||||
|
@ -395,6 +395,12 @@ public:
|
||||
Traverser::visit(set_element);
|
||||
}
|
||||
|
||||
void visit(ast::LabelSetElement &label_set_element) override
|
||||
{
|
||||
auto entry = printer.advance("Label Set Element");
|
||||
Traverser::visit(label_set_element);
|
||||
}
|
||||
|
||||
void visit(ast::SetList &set_list) override
|
||||
{
|
||||
auto entry = printer.advance("Set List");
|
||||
|
@ -244,6 +244,12 @@ public:
|
||||
accept(set_element.set_value);
|
||||
}
|
||||
|
||||
void visit(ast::LabelSetElement& label_set_element) override
|
||||
{
|
||||
accept(label_set_element.identifier);
|
||||
accept(label_set_element.label_list);
|
||||
}
|
||||
|
||||
void visit(ast::SetList& set_list) override
|
||||
{
|
||||
accept(set_list.value);
|
||||
|
@ -4,18 +4,21 @@
|
||||
import logging
|
||||
|
||||
# TODO: auto import
|
||||
from scenario import no_000001
|
||||
# TODO: better logging (scenario visibility)
|
||||
# TODO: result storage
|
||||
from scenario import no_000001, no_000002
|
||||
from neo4j.v1 import GraphDatabase, basic_auth, types, Node
|
||||
|
||||
scenarios = [no_000001.scenario_1]
|
||||
# scenarios = [no_000001.scenario_1, no_000002.scenario_2]
|
||||
scenarios = [no_000002.scenario_2]
|
||||
|
||||
# logging init
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# initialize driver and create session
|
||||
session = GraphDatabase.driver("bolt://localhost",
|
||||
auth=basic_auth("neo4j", "1234"),
|
||||
encrypted=0).session()
|
||||
auth=basic_auth("neo4j", "1234"),
|
||||
encrypted=0).session()
|
||||
|
||||
|
||||
def check(condition, scenario_no, message):
|
||||
@ -55,6 +58,7 @@ if __name__ == "__main__":
|
||||
|
||||
# in case that the result is single
|
||||
if count == 1:
|
||||
|
||||
# extract properties from record
|
||||
record = records[0]
|
||||
record_name, = record
|
||||
|
@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__author__ = "Marko Budiselic"
|
||||
__date__ = "2016_11_02"
|
||||
|
||||
class Scenario1:
|
||||
'''
|
||||
|
28
tests/integration/scenario/no_000002.py
Normal file
28
tests/integration/scenario/no_000002.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
__author__ = "Marko Budiselic"
|
||||
__date__ = "2016_11_03"
|
||||
|
||||
class Scenario2:
|
||||
'''
|
||||
Create node, edit labels and return all labels for the node.
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
'''
|
||||
Constructor
|
||||
'''
|
||||
self.no = 2
|
||||
self.desctiption = "Create node, edit labels and return all labels for the node."
|
||||
self.init_graph = []
|
||||
self.queries = [
|
||||
("MATCH (n) DETACH DELETE n", (0, None)),
|
||||
("CREATE (n:Garment {garment_id: 1234, garment_category_id: 1}) RETURN n", (1, [{"garment_id": 1234, "garment_category_id": 1}])),
|
||||
("MATCH (g:Garment {garment_id: 1234}) SET g:FF RETURN labels(g)", (1, [["Garment", "FF"]])),
|
||||
("MATCH(g:Garment {garment_id: 1234}) SET g.reveals = 50 RETURN g", (1, [{"garment_id": 1234, "garment_category_id": 1, "reveals": 50}])),
|
||||
("MATCH (n) RETURN n", (1, [{"garment_id": 1234, "garment_category_id": 1, "reveals": 50}])),
|
||||
]
|
||||
self.side_effects = None
|
||||
|
||||
scenario_2 = Scenario2()
|
Loading…
Reference in New Issue
Block a user