From afc0a4a17689c2cc1296bdd989c8d054bfe0b29b Mon Sep 17 00:00:00 2001 From: Marko Budiselic Date: Thu, 17 Nov 2016 15:46:36 +0100 Subject: [PATCH] better architecture for hardcoded test queries (still has to be polished) --- CMakeLists.txt | 1 + include/query/backend/cpp_old/cypher.hpp | 9 +- .../query/backend/cpp_old/handlers/delete.hpp | 17 ++- .../query/hardcode/{queries.hpp => basic.hpp} | 105 +++++---------- include/query/hardcode/dressipi.hpp | 123 ++++++++++++++++++ include/query/hardcode/includes.hpp | 38 ++++++ include/query/language/cypher/ast/ast.hpp | 1 + .../query/language/cypher/ast/ast_visitor.hpp | 4 +- include/query/language/cypher/ast/merge.hpp | 18 +++ include/query/language/cypher/ast/queries.hpp | 14 ++ include/query/language/cypher/common.hpp | 19 ++- include/query/language/cypher/cypher.y | 24 +++- .../language/cypher/debug/tree_print.hpp | 12 ++ .../cypher/tokenizer/cypher_lexer.hpp | 1 + .../language/cypher/visitor/traverser.hpp | 12 ++ include/query/preprocesor.hpp | 5 + include/query/strip/stripper.hpp | 50 +++++-- include/utils/config/config.hpp | 6 +- include/utils/string/file.hpp | 55 +++++++- include/utils/variadic/variadic.hpp | 29 ++++- src/utils/string/file.cpp | 32 ++++- tests/CMakeLists.txt | 4 + tests/data/queries/core/basic.txt | 27 ++++ tests/data/queries/core/dressipi.txt | 15 +++ .../fraudulent_transactions_query2.cypher | 0 .../complex/powerlinx_opportunities.cypher | 0 .../cypher}/read-write/match-delete.cypher | 0 .../read-write/match-set-return.cypher | 0 .../cypher}/read-write/match-set.cypher | 0 .../read-write/match-where-delete.cypher | 0 .../cypher}/read/match/match-custom1.cypher | 0 .../cypher}/read/match/match-custom2.cypher | 0 .../cypher}/read/match/match-n-m.cypher | 0 .../cypher}/read/match/match-optional.cypher | 0 .../cypher}/read/match/match-path.cypher | 0 .../cypher}/read/match/match-property.cypher | 0 .../cypher}/read/match/match-where.cypher | 0 .../cypher}/read/return/return-alias.cypher | 0 .../cypher}/read/return/return-all.cypher | 0 .../cypher}/read/return/return-count.cypher | 0 .../read/return/return-distinct.cypher | 0 .../cypher}/read/return/return-limit.cypher | 0 .../read/return/return-list-001.cypher | 0 .../read/return/return-order-asc.cypher | 0 .../read/return/return-order-desc.cypher | 0 .../read/return/return-skip-limit.cypher | 0 .../cypher}/read/return/return-skip.cypher | 0 .../cypher}/read/union/union-all.cypher | 0 .../cypher}/read/union/union.cypher | 0 .../cypher}/read/where/where.cypher | 0 .../with/match-with-order-skip-limit.cypher | 0 .../cypher}/read/with/match-with-where.cypher | 0 .../cypher}/sprint_0/query_00.cypher | 0 .../cypher}/sprint_0/query_01.cypher | 0 .../cypher}/sprint_0/query_02.cypher | 0 .../cypher}/sprint_0/query_03.cypher | 0 .../cypher}/sprint_0/query_04.cypher | 0 .../cypher}/sprint_0/query_05.cypher | 0 .../cypher}/sprint_0/query_06.cypher | 0 .../cypher}/sprint_0/query_07.cypher | 0 .../cypher}/sprint_0/query_08.cypher | 0 .../cypher}/sprint_0/query_09.cypher | 0 .../cypher}/sprint_0/query_10.cypher | 0 .../cypher}/sprint_1/query_0.cypher | 0 .../cypher}/sprint_1/query_1.cypher | 0 .../cypher}/sprint_1/query_5.cypher | 0 .../cypher}/write/create-return.cypher | 0 .../cypher}/write/create.cypher | 0 tests/data/queries/opencypher/dummy.txt | 0 tests/integration/cleaning.cpp | 18 +-- tests/integration/index.cpp | 19 +-- tests/integration/queries.cpp | 90 ++++++------- tests/integration/snapshot.cpp | 53 ++++---- tests/manual/cypher_ast.cpp | 18 ++- tests/manual/queries.cpp | 20 +-- tests/manual/query_hasher.cpp | 22 ++-- 76 files changed, 599 insertions(+), 262 deletions(-) rename include/query/hardcode/{queries.hpp => basic.hpp} (84%) create mode 100644 include/query/hardcode/dressipi.hpp create mode 100644 include/query/hardcode/includes.hpp create mode 100644 include/query/language/cypher/ast/merge.hpp create mode 100644 tests/data/queries/core/basic.txt create mode 100644 tests/data/queries/core/dressipi.txt rename tests/data/{cypher_queries => queries/cypher}/complex/fraudulent_transactions_query2.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/complex/powerlinx_opportunities.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read-write/match-delete.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read-write/match-set-return.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read-write/match-set.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read-write/match-where-delete.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-custom1.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-custom2.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-n-m.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-optional.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-path.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-property.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/match/match-where.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-alias.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-all.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-count.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-distinct.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-limit.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-list-001.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-order-asc.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-order-desc.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-skip-limit.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/return/return-skip.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/union/union-all.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/union/union.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/where/where.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/with/match-with-order-skip-limit.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/read/with/match-with-where.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_00.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_01.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_02.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_03.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_04.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_05.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_06.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_07.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_08.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_09.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_0/query_10.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_1/query_0.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_1/query_1.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/sprint_1/query_5.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/write/create-return.cypher (100%) rename tests/data/{cypher_queries => queries/cypher}/write/create.cypher (100%) create mode 100644 tests/data/queries/opencypher/dummy.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 63ef6a027..fd67e402b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -593,6 +593,7 @@ if (MEMGRAPH) target_link_libraries(${MEMGRAPH_BUILD_NAME} memgraph) endif () + target_link_libraries(${MEMGRAPH_BUILD_NAME} stdc++fs) target_link_libraries(${MEMGRAPH_BUILD_NAME} Threads::Threads) target_link_libraries(${MEMGRAPH_BUILD_NAME} cypher_lib) if (UNIX) diff --git a/include/query/backend/cpp_old/cypher.hpp b/include/query/backend/cpp_old/cypher.hpp index 7c62632f8..938c08554 100644 --- a/include/query/backend/cpp_old/cypher.hpp +++ b/include/query/backend/cpp_old/cypher.hpp @@ -21,10 +21,11 @@ public: #else std::string template_path = CONFIG(config::TEMPLATE_CPU_CPP_PATH); #endif - template_file = utils::read_file(template_path.c_str()); + template_text = utils::read_text(fs::path(template_path)); } template + // TODO: query and path shoud be distinct types void generate_code(const Tree &tree, const std::string &query, const uint64_t stripped_hash, const std::string &path) { @@ -42,7 +43,7 @@ public: // save the code std::string generated = template_engine::render( - template_file, {{"class_name", "CodeCPU"}, + template_text.str(), {{"class_name", "CodeCPU"}, {"stripped_hash", std::to_string(stripped_hash)}, {"query", query}, #ifdef BARRIER @@ -54,12 +55,12 @@ public: logger.trace("generated code: {}", generated); - utils::write_file(generated, path); + utils::write(utils::Text(generated), fs::path(path)); } protected: Logger logger; private: - std::string template_file; + utils::Text template_text; }; diff --git a/include/query/backend/cpp_old/handlers/delete.hpp b/include/query/backend/cpp_old/handlers/delete.hpp index 31b68ac6c..f8aec6e1f 100644 --- a/include/query/backend/cpp_old/handlers/delete.hpp +++ b/include/query/backend/cpp_old/handlers/delete.hpp @@ -8,15 +8,24 @@ auto delete_query_action = std::string code = ""; - for (auto const &kv : action_data.actions) { + // TODO: don't delete the whole graph + + for (auto const &kv : action_data.actions) + { auto entity = kv.first; - if (kv.second == ClauseAction::DeleteNode && action_data.is_detach) { + + if (kv.second == ClauseAction::DeleteNode && action_data.is_detach) + { code += code_line(delete_whole_graph); } - if (kv.second == ClauseAction::DeleteNode && !action_data.is_detach) { + + if (kv.second == ClauseAction::DeleteNode && !action_data.is_detach) + { code += code_line(delete_all_detached_nodes); } - if (kv.second == ClauseAction::DeleteRelationship) { + + if (kv.second == ClauseAction::DeleteRelationship) + { code += code_line("// DELETE Relationship({})", entity); } } diff --git a/include/query/hardcode/queries.hpp b/include/query/hardcode/basic.hpp similarity index 84% rename from include/query/hardcode/queries.hpp rename to include/query/hardcode/basic.hpp index c2c839316..add5db3ef 100644 --- a/include/query/hardcode/queries.hpp +++ b/include/query/hardcode/basic.hpp @@ -1,50 +1,13 @@ #pragma once -#include -#include +#include "includes.hpp" -using namespace std; - -#ifdef BARRIER - -#include "barrier/barrier.hpp" -namespace barrier +namespace hardcode { -#else - -#include -#include -#include -#include -#include - -#include "communication/bolt/v1/serialization/bolt_serializer.hpp" -#include "communication/bolt/v1/serialization/record_stream.hpp" -#include "database/db.hpp" -#include "database/db.hpp" -#include "database/db_accessor.hpp" -#include "database/db_accessor.hpp" -#include "io/network/socket.hpp" -#include "mvcc/id.hpp" -#include "storage/edge_type/edge_type.hpp" -#include "storage/edge_x_vertex.hpp" -#include "storage/indexes/index_definition.hpp" -#include "storage/label/label.hpp" -#include "storage/model/properties/all.hpp" -#include "storage/model/properties/property.hpp" -#include "utils/border.hpp" -#include "utils/iterator/iterator.hpp" -#include "utils/iterator/iterator.hpp" -#include "utils/option_ptr.hpp" -#include "utils/reference_wrapper.hpp" -#include "query/util.hpp" - -#endif - -auto load_queries(Db &db) +auto load_basic_functions(Db &db) { - std::map> queries; + query_functions_t functions; // CREATE (n {prop: 0}) RETURN n auto create_node = [&db](properties_t &&args) { @@ -54,7 +17,7 @@ auto load_queries(Db &db) vertex_accessor.set(property_key, std::move(args[0])); return t.commit(); }; - queries[11597417457737499503u] = create_node; + functions[11597417457737499503u] = create_node; // CREATE (n:LABEL {name: "TEST"}) RETURN n; auto create_labeled_and_named_node = [&db](properties_t &&args) { @@ -490,45 +453,35 @@ auto load_queries(Db &db) return false; } }; - queries[17721584194272598838u] = match_label_property; + functions[17721584194272598838u] = match_label_property; - // Blueprint: - // auto = [&db](properties_t &&args) { - // DbAccessor t(db); - // - // - // return t.commit(); - // }; - - queries[15284086425088081497u] = match_all_nodes; - queries[4857652843629217005u] = match_by_label; - queries[15648836733456301916u] = create_edge_v2; - queries[10597108978382323595u] = create_account; - queries[5397556489557792025u] = create_labeled_and_named_node; + functions[15284086425088081497u] = match_all_nodes; + functions[4857652843629217005u] = match_by_label; + functions[15648836733456301916u] = create_edge_v2; + functions[10597108978382323595u] = create_account; + functions[5397556489557792025u] = create_labeled_and_named_node; // TODO: query hasher reports two hash values - queries[998725786176032607u] = create_labeled_and_named_node_v2; - queries[16090682663946456821u] = create_labeled_and_named_node_v2; + functions[998725786176032607u] = create_labeled_and_named_node_v2; + functions[16090682663946456821u] = create_labeled_and_named_node_v2; - queries[7939106225150551899u] = create_edge; - queries[6579425155585886196u] = create_edge; - queries[11198568396549106428u] = find_node_by_internal_id; - queries[8320600413058284114u] = find_edge_by_internal_id; - queries[6813335159006269041u] = update_node; - queries[10506105811763742758u] = match_all_delete; - queries[13742779491897528506u] = match_label_delete; - queries[11349462498691305864u] = match_id_delete; - queries[6963549500479100885u] = match_edge_id_delete; - queries[14897166600223619735u] = match_edge_all_delete; - queries[16888549834923624215u] = match_edge_type_delete; - queries[11675960684124428508u] = match_id_type_return; - queries[15698881472054193835u] = match_name_type_return; - queries[12595102442911913761u] = match_name_type_return_cross; - queries[8918221081398321263u] = match_label_type_return; + functions[7939106225150551899u] = create_edge; + functions[6579425155585886196u] = create_edge; + functions[11198568396549106428u] = find_node_by_internal_id; + functions[8320600413058284114u] = find_edge_by_internal_id; + functions[6813335159006269041u] = update_node; + functions[10506105811763742758u] = match_all_delete; + functions[13742779491897528506u] = match_label_delete; + functions[11349462498691305864u] = match_id_delete; + functions[6963549500479100885u] = match_edge_id_delete; + functions[14897166600223619735u] = match_edge_all_delete; + functions[16888549834923624215u] = match_edge_type_delete; + functions[11675960684124428508u] = match_id_type_return; + functions[15698881472054193835u] = match_name_type_return; + functions[12595102442911913761u] = match_name_type_return_cross; + functions[8918221081398321263u] = match_label_type_return; - return queries; + return functions; } -#ifdef BARRIER } -#endif diff --git a/include/query/hardcode/dressipi.hpp b/include/query/hardcode/dressipi.hpp new file mode 100644 index 000000000..3c489de59 --- /dev/null +++ b/include/query/hardcode/dressipi.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include "includes.hpp" + +namespace hardcode +{ + +// TODO: decouple hashes from the code because hashes could and should be +// tested separately + +auto load_dressipi_functions(Db &db) +{ + query_functions_t functions; + + // Query: CREATE (n {garment_id: 1234, garment_category_id: 1}) RETURN n + // Hash: 12139093029838549530 + functions[12139093029838549530u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: CREATE (p:profile {profile_id: 111, partner_id: 55}) RETURN p + // Hash: 17158428452166262783 + functions[17158428452166262783u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (g:garment {garment_id: 1234}) SET g:FF RETURN labels(g) + // Hash: 11123780635391515946 + functions[11123780635391515946u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (p:profile {profile_id: 111, partner_id: 55})-[s:score]-(g:garment{garment_id: 1234}) SET s.score = 1550 RETURN s.score + // Hash: 674581607834128909 + functions[674581607834128909u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (g:garment {garment_id: 3456}) SET g.reveals = 50 RETURN g + // Hash: 2839969099736071844 + functions[2839969099736071844u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MERGE (g1:garment {garment_id: 1234})-[r:default_outfit]-(g2:garment {garment_id: 2345}) RETURN r + // Hash: 3782642357973971504 + functions[3782642357973971504u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MERGE (p:profile {profile_id: 111, partner_id: 55})-[s:score]-(g.garment {garment_id: 1234}) SET s.score=1500 RETURN s + // Hash: 7871009397157280694 + functions[7871009397157280694u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (p:profile {profile_id: 111, partner_id: 55})-[s:score]-(g.garment {garment_id: 1234}) DELETE s + // Hash: 9459600951073026137 + functions[9459600951073026137u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (p:profile {profile_id: 113}) DELETE p + // Hash: 6763665709953344106 + functions[6763665709953344106u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (n) DETACH DELETE n + // Hash: 4798158026600988079 + functions[4798158026600988079u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (p:profile) RETURN p + // Hash: 15599970964909894866 + functions[15599970964909894866u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (g:garment) RETURN COUNT(g) + // Hash: 11458306387621940265 + functions[11458306387621940265u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (g:garment {garment_id: 1234}) RETURN g + // Hash: 7756609649964321221 + functions[7756609649964321221u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (p:profile {partner_id: 55}) RETURN p + // Hash: 17506488413143988006 + functions[17506488413143988006u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + // Query: MATCH (n) RETURN count(n) + // Hash: 10510787599699014973 + functions[10510787599699014973u] = [&db](properties_t &&args) { + DbAccessor t(db); + return t.commit(); + }; + + return functions; +} + +} diff --git a/include/query/hardcode/includes.hpp b/include/query/hardcode/includes.hpp new file mode 100644 index 000000000..c755f8d92 --- /dev/null +++ b/include/query/hardcode/includes.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "communication/bolt/v1/serialization/bolt_serializer.hpp" +#include "communication/bolt/v1/serialization/record_stream.hpp" +#include "database/db.hpp" +#include "database/db.hpp" +#include "database/db_accessor.hpp" +#include "database/db_accessor.hpp" +#include "io/network/socket.hpp" +#include "mvcc/id.hpp" +#include "query/util.hpp" +#include "storage/edge_type/edge_type.hpp" +#include "storage/edge_x_vertex.hpp" +#include "storage/indexes/index_definition.hpp" +#include "storage/label/label.hpp" +#include "storage/model/properties/all.hpp" +#include "storage/model/properties/property.hpp" +#include "utils/border.hpp" +#include "utils/iterator/iterator.hpp" +#include "utils/iterator/iterator.hpp" +#include "utils/option_ptr.hpp" +#include "utils/reference_wrapper.hpp" + +using namespace std; + +namespace hardcode +{ +using query_functions_t = + std::map>; +} diff --git a/include/query/language/cypher/ast/ast.hpp b/include/query/language/cypher/ast/ast.hpp index 04b356ee6..9bc1db7b4 100644 --- a/include/query/language/cypher/ast/ast.hpp +++ b/include/query/language/cypher/ast/ast.hpp @@ -20,3 +20,4 @@ #include "expr.hpp" #include "with.hpp" #include "functions.hpp" +#include "merge.hpp" diff --git a/include/query/language/cypher/ast/ast_visitor.hpp b/include/query/language/cypher/ast/ast_visitor.hpp index aa130d966..823a1f05a 100644 --- a/include/query/language/cypher/ast/ast_visitor.hpp +++ b/include/query/language/cypher/ast/ast_visitor.hpp @@ -55,6 +55,7 @@ struct ReturnList; struct Distinct; struct Create; +struct Merge; struct Match; struct Where; struct Set; @@ -66,6 +67,7 @@ struct ReadQuery; struct UpdateQuery; struct DeleteQuery; struct ReadWriteQuery; +struct MergeQuery; struct SetKey; struct SetValue; @@ -89,7 +91,7 @@ struct AstVisitor Return, Distinct, Delete, DeleteQuery, UpdateQuery, Set, SetKey, ReadWriteQuery, IdentifierList, WithList, WithClause, WithQuery, Long, CountFunction, LabelsFunction, InternalIdExpr, SetValue, SetElement, - LabelSetElement, SetList> + MergeQuery, Merge, LabelSetElement, SetList> { }; } diff --git a/include/query/language/cypher/ast/merge.hpp b/include/query/language/cypher/ast/merge.hpp new file mode 100644 index 000000000..f6d7db518 --- /dev/null +++ b/include/query/language/cypher/ast/merge.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "ast_node.hpp" +#include "pattern.hpp" +#include "return.hpp" + +namespace ast +{ + +struct Merge : public AstNode +{ + Merge(Pattern* pattern) + : pattern(pattern) {} + + Pattern* pattern; +}; + +} diff --git a/include/query/language/cypher/ast/queries.hpp b/include/query/language/cypher/ast/queries.hpp index 6e33430cb..5ed262b23 100644 --- a/include/query/language/cypher/ast/queries.hpp +++ b/include/query/language/cypher/ast/queries.hpp @@ -6,6 +6,7 @@ #include "match.hpp" #include "return.hpp" #include "set.hpp" +#include "merge.hpp" namespace ast { @@ -70,4 +71,17 @@ struct ReadWriteQuery : public AstNode Return *return_clause; }; +struct MergeQuery : public AstNode +{ + MergeQuery(Merge* merge_clause, Set* set_clause, Return* return_clause) : + merge_clause(merge_clause), set_clause(set_clause), + return_clause(return_clause) + { + } + + Merge *merge_clause; + Set *set_clause; + Return *return_clause; +}; + } diff --git a/include/query/language/cypher/common.hpp b/include/query/language/cypher/common.hpp index 7b9e905d4..f2701fed7 100644 --- a/include/query/language/cypher/common.hpp +++ b/include/query/language/cypher/common.hpp @@ -1,15 +1,24 @@ #pragma once +#include + #include "utils/command_line/arguments.hpp" #include "utils/string/file.hpp" -std::string extract_query(const std::vector& arguments) +auto extract_queries(const std::vector& arguments) { + std::vector queries; + + // load single query if (contains_argument(arguments, "-q")) - return get_argument(arguments, "-q", "CREATE (n) RETURN n"); - auto default_file = "query.cypher"; + { + queries.emplace_back(get_argument(arguments, "-q", "CREATE (n) RETURN n")); + return queries; + } + + // load multiple queries from file + auto default_file = "queries.cypher"; auto file = get_argument(arguments, "-f", default_file); - // TODO: error handling - return utils::read_file(file.c_str()); + return utils::read_lines(file.c_str()); } diff --git a/include/query/language/cypher/cypher.y b/include/query/language/cypher/cypher.y index 8dfaee29a..28ed2d8d8 100644 --- a/include/query/language/cypher/cypher.y +++ b/include/query/language/cypher/cypher.y @@ -81,6 +81,22 @@ start ::= read_write_query(Q). { ast->root = Q; } +start ::= merge_query(Q). { + ast->root = Q; +} + +// -- merge query + +%type merge_query {ast::MergeQuery*} + +merge_query(MQ) ::= merge_clause(MC) set_clause(SC) return_clause(RC). { + MQ = ast->create(MC, SC, RC); +} + +merge_query(MQ) ::= merge_clause(MC) return_clause(RC). { + MQ = ast->create(MC, nullptr, RC); +} + // -- with query %type with_query {ast::WithQuery*} @@ -188,7 +204,13 @@ delete_query(DQ) ::= match_clause(M) delete_clause(D). { %type create_clause {ast::Create*} create_clause(C) ::= CREATE pattern(P). { - C = ast->create(P); + C = ast->create(P); +} + +%type merge_clause {ast::Merge*} + +merge_clause(M) ::= MERGE pattern(P). { + M = ast->create(P); } %type match_clause {ast::Match*} diff --git a/include/query/language/cypher/debug/tree_print.hpp b/include/query/language/cypher/debug/tree_print.hpp index 6d555f940..f08c53590 100644 --- a/include/query/language/cypher/debug/tree_print.hpp +++ b/include/query/language/cypher/debug/tree_print.hpp @@ -350,6 +350,12 @@ public: Traverser::visit(write_query); } + void visit(ast::MergeQuery &merge_query) override + { + auto entry = printer.advance("Merge Query"); + Traverser::visit(merge_query); + } + void visit(ast::DeleteQuery &delete_query) override { auto entry = printer.advance("Delete Query"); @@ -371,6 +377,12 @@ public: Traverser::visit(create); } + void visit(ast::Merge &merge) override + { + auto entry = printer.advance("Merge"); + Traverser::visit(merge); + } + void visit(ast::UpdateQuery &update_query) override { auto entry = printer.advance("Update Query"); diff --git a/include/query/language/cypher/tokenizer/cypher_lexer.hpp b/include/query/language/cypher/tokenizer/cypher_lexer.hpp index d4ca665f2..619767992 100644 --- a/include/query/language/cypher/tokenizer/cypher_lexer.hpp +++ b/include/query/language/cypher/tokenizer/cypher_lexer.hpp @@ -43,6 +43,7 @@ public: // keywords rule("(?i:CREATE)", TK_CREATE); + rule("(?i:MERGE)", TK_MERGE); rule("(?i:MATCH)", TK_MATCH); rule("(?i:WHERE)", TK_WHERE); rule("(?i:SET)", TK_SET); diff --git a/include/query/language/cypher/visitor/traverser.hpp b/include/query/language/cypher/visitor/traverser.hpp index d73ffe026..619211572 100644 --- a/include/query/language/cypher/visitor/traverser.hpp +++ b/include/query/language/cypher/visitor/traverser.hpp @@ -34,6 +34,13 @@ public: accept(query.return_clause); } + void visit(ast::MergeQuery& query) override + { + accept(query.merge_clause); + accept(query.set_clause); + accept(query.return_clause); + } + void visit(ast::Match& match) override { accept(match.pattern_list); @@ -261,6 +268,11 @@ public: accept(create.pattern); } + void visit(ast::Merge& merge) override + { + accept(merge.pattern); + } + void visit(ast::Distinct& distinct) override { accept(distinct.identifier); diff --git a/include/query/preprocesor.hpp b/include/query/preprocesor.hpp index a7305b11d..19b025f07 100644 --- a/include/query/preprocesor.hpp +++ b/include/query/preprocesor.hpp @@ -27,5 +27,10 @@ public: auto preprocess(const std::string &query) { return stripper.strip(query); } private: + // In C++17 the ints should be unnecessary? + // as far as I understand in C++17 class template parameters + // can be deduced just like function template parameters + // TODO: once C++ 17 will be well suported by comilers + // refactor this piece of code QueryStripper stripper; }; diff --git a/include/query/strip/stripper.hpp b/include/query/strip/stripper.hpp index decc63325..f1c1975f2 100644 --- a/include/query/strip/stripper.hpp +++ b/include/query/strip/stripper.hpp @@ -26,7 +26,8 @@ template class QueryStripper : public Loggable { public: - QueryStripper(Ts &&... strip_types) : Loggable("QueryStripper"), + QueryStripper(Ts &&... strip_types) + : Loggable("QueryStripper"), strip_types(std::make_tuple(std::forward(strip_types)...)), lexer(std::make_unique()) { @@ -34,19 +35,21 @@ public: QueryStripper(QueryStripper &other) = delete; - QueryStripper(QueryStripper &&other) : Loggable("QueryStripper"), - strip_types(std::move(other.strip_types)), + QueryStripper(QueryStripper &&other) + : Loggable("QueryStripper"), strip_types(std::move(other.strip_types)), lexer(std::move(other.lexer)) { } - auto strip_space(const std::string &query) - { - return strip(query, " "); - } + auto strip_space(const std::string &query) { return strip(query, " "); } auto strip(const std::string &query, const std::string &separator = "") { + // ------------------------------------------------------------------- + // TODO: write speed tests and then optimize, because this + // function is called before every query execution ! + // ------------------------------------------------------------------- + // TODO write this more optimal (resplace string // concatenation with something smarter) // TODO: in place substring replacement @@ -66,7 +69,8 @@ public: if (_or(token.id, strip_types, std::make_index_sequence{})) { auto index = counter++; - switch (token.id) { + switch (token.id) + { case TK_LONG: store_query_param(stripped_arguments, std::stol(token.value)); @@ -78,7 +82,8 @@ public: // TODO: remove store_query_param(stripped_arguments, token.value); break; - case TK_BOOL: { + case TK_BOOL: + { bool value = token.value[0] == 'T' || token.value[0] == 't'; store_query_param(stripped_arguments, value); break; @@ -92,16 +97,33 @@ public: assert(false); } stripped_query += std::to_string(index) + separator; - } else { - // TODO: lowercase only keywords like (MATCH, CREATE, ...) + } + else + { + // if token is keyword then lowercase because query hash + // should be the same + // TODO: probably we shoud do the lowercase before + // or during the tokenization (SPEED TESTS) + if (token.id == TK_OR || token.id == TK_AND || + token.id == TK_NOT || token.id == TK_WITH || + token.id == TK_SET || token.id == TK_CREATE || + token.id == TK_MERGE || token.id == TK_MATCH || + token.id == TK_DELETE || token.id == TK_DETACH || + token.id == TK_WHERE || token.id == TK_RETURN || + token.id == TK_DISTINCT || token.id == TK_COUNT || + token.id == TK_LABELS) + { + std::transform(token.value.begin(), token.value.end(), + token.value.begin(), ::tolower); + } stripped_query += token.value + separator; } } + // TODO: hash function should be a template parameter auto hash = fnv(stripped_query); return QueryStripped(std::move(stripped_query), - std::move(stripped_arguments), - hash); + std::move(stripped_arguments), hash); } private: @@ -111,7 +133,7 @@ private: template bool _or(Value &&value, Tuple &&tuple, std::index_sequence) { - return or_vargs(std::forward(value), + return utils::or_vargs(std::forward(value), std::get(std::forward(tuple))...); } }; diff --git a/include/utils/config/config.hpp b/include/utils/config/config.hpp index d18c7bebb..7fcec7182 100644 --- a/include/utils/config/config.hpp +++ b/include/utils/config/config.hpp @@ -5,7 +5,7 @@ #include #include -// TODO: isolate from caller (caller should know that his dependency is +// TODO: isolate from caller (caller shouldn't know that his dependency is) // yaml-cpp #include "yaml-cpp/yaml.h" @@ -50,6 +50,10 @@ public: return config; } + void register_program_arguments() + { + } + std::string operator[](const char* key) { return _config[key].template as(); diff --git a/include/utils/string/file.hpp b/include/utils/string/file.hpp index c1b580cf6..aca99d1fa 100644 --- a/include/utils/string/file.hpp +++ b/include/utils/string/file.hpp @@ -1,19 +1,66 @@ #pragma once +#include +// TODO: remove experimental from here once that becomes possible +#include #include #include +#include #include #include -#include -#include #include +// TODO: remove experimental from here once it becomes possible +namespace fs = std::experimental::filesystem; + namespace utils { -std::string read_file(const char *filename); +/* + * Type safe text object. + */ +class Text +{ +public: + Text() = default; + explicit Text(const std::string &text) : text_(text) {} -void write_file(const std::string& content, const std::string& path); + // text could be huge and copy operationt would be too expensive + Text(const Text& other) = delete; + Text& operator=(const Text& other) = delete; + + // the object is movable + Text (Text&& other) = default; + Text& operator=(Text&& other) + { + text_ = std::move(other.text_); + return *this; + } + + const std::string &str() const { return text_; } + +private: + std::string text_; +}; + +/* + * Reads the whole text from a file at the path. + */ +Text read_text(const fs::path &path); + +/* + * Reads all the lines from a file at the path. + */ +std::vector read_lines(const fs::path &path); + +// TODO: lazy implementation of read_lines functionality (line by line) + +// TODO: read word by word + lazy implementation + +/* + * Write text in a file at the path. + */ +void write(const Text &text, const fs::path &path); } diff --git a/include/utils/variadic/variadic.hpp b/include/utils/variadic/variadic.hpp index 40f5a54e9..fe01e30b3 100644 --- a/include/utils/variadic/variadic.hpp +++ b/include/utils/variadic/variadic.hpp @@ -2,23 +2,38 @@ #include -// variadic argument printer +namespace utils +{ +/* + * Variadic argument print + */ template -void _print_vargs(std::ostream& s, Head&& head) +void print_vargs(std::ostream& s, Head&& head) { s << std::forward(head); } template -void _print_vargs(std::ostream& s, Head&& head, Tail&& ...tail) +void print_vargs(std::ostream& s, Head&& head, Tail&& ...tail) { s << std::forward(head); - _print_vargs(s, std::forward(tail)...); + print_vargs(s, std::forward(tail)...); } + +/* + * Compile time print line. + * + * USAGE: + * RUN: utils::printer("ONE ", "TWO"); + * OUTPUT: "ONE TWO\n" + * + * TODO: reimplament with C++17 fold expressions + */ template -void print_vargs(Args&&... args) +void println(Args&&... args) { - _print_vargs(std::cout, std::forward(args)...); + print_vargs(std::cout, std::forward(args)...); + std::cout << std::endl; } // value equality with any of variadic argument @@ -39,3 +54,5 @@ bool or_vargs(Value&& value, Array&&... array) { return _or_vargs(std::forward(value), std::forward(array)...); } + +} diff --git a/src/utils/string/file.cpp b/src/utils/string/file.cpp index bb29c4b5c..fa1d32070 100644 --- a/src/utils/string/file.cpp +++ b/src/utils/string/file.cpp @@ -1,25 +1,43 @@ #include "utils/string/file.hpp" +#include + namespace utils { -std::string read_file(const char *filename) +namespace fs = std::experimental::filesystem; + +Text read_text(const fs::path &path) { - std::ifstream in(filename, std::ios::in | std::ios::binary); + std::ifstream in(path, std::ios::in | std::ios::binary); if (in) - return std::string(std::istreambuf_iterator(in), - std::istreambuf_iterator()); + return Text(std::string(std::istreambuf_iterator(in), + std::istreambuf_iterator())); - auto error_message = fmt::format("{0}{1}", "Fail to read: ", filename); + auto error_message = fmt::format("{0}{1}", "Fail to read: ", path.c_str()); throw std::runtime_error(error_message); } -void write_file(const std::string& content, const std::string& path) +std::vector read_lines(const fs::path &path) +{ + std::vector lines; + + std::ifstream stream(path.c_str()); + std::string line; + while (std::getline(stream, line)) + { + lines.emplace_back(line); + } + + return lines; +} + +void write(const Text &text, const fs::path &path) { std::ofstream stream; stream.open(path.c_str()); - stream << content; + stream << text.str(); stream.close(); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f5532198c..d0b46b38f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -64,6 +64,7 @@ endforeach() # test hard coded queries add_executable(integration_queries integration/queries.cpp) +target_link_libraries(integration_queries stdc++fs) target_link_libraries(integration_queries memgraph) target_link_libraries(integration_queries Threads::Threads) target_link_libraries(integration_queries ${fmt_static_lib}) @@ -102,6 +103,7 @@ set_property(TARGET index PROPERTY CXX_STANDARD 14) # cypher_ast add_executable(manual_cypher_ast manual/cypher_ast.cpp) +target_link_libraries(manual_cypher_ast stdc++fs) target_link_libraries(manual_cypher_ast memgraph) target_link_libraries(manual_cypher_ast Threads::Threads) target_link_libraries(manual_cypher_ast ${fmt_static_lib}) @@ -120,6 +122,7 @@ set_property(TARGET manual_queries PROPERTY CXX_STANDARD 14) # query_engine add_executable(manual_query_engine manual/query_engine.cpp) +target_link_libraries(manual_query_engine stdc++fs) target_link_libraries(manual_query_engine memgraph) target_link_libraries(manual_query_engine ${fmt_static_lib}) target_link_libraries(manual_query_engine ${yaml_static_lib}) @@ -130,6 +133,7 @@ set_property(TARGET manual_query_engine PROPERTY CXX_STANDARD 14) # query_hasher add_executable(manual_query_hasher manual/query_hasher.cpp) +target_link_libraries(manual_query_hasher stdc++fs) target_link_libraries(manual_query_hasher memgraph) target_link_libraries(manual_query_hasher ${fmt_static_lib}) target_link_libraries(manual_query_hasher ${yaml_static_lib}) diff --git a/tests/data/queries/core/basic.txt b/tests/data/queries/core/basic.txt new file mode 100644 index 000000000..74add328a --- /dev/null +++ b/tests/data/queries/core/basic.txt @@ -0,0 +1,27 @@ +CREATE (n:LABEL {name: "TEST01"}) RETURN n +CREATE (n:LABEL {name: "TEST02"}) RETURN n +CREATE (n:LABEL {name: "TEST2"}) RETURN n +CREATE (n:LABEL {name: "TEST3"}) RETURN n +CREATE (n:OTHER {name: "TEST4"}) RETURN n +CREATE (n:ACCOUNT {id: 2322, name: "TEST", country: "Croatia", "created_at": 2352352}) RETURN n +MATCH (n {id: 0}) RETURN n", "MATCH (n {id: 1}) RETURN n +MATCH (n {id: 2}) RETURN n", "MATCH (n {id: 3}) RETURN n +MATCH (a {id:0}), (p {id: 1}) CREATE (a)-[r:IS]->(p) RETURN r +MATCH (a {id:1}), (p {id: 2}) CREATE (a)-[r:IS]->(p) RETURN r +MATCH ()-[r]-() WHERE ID(r)=0 RETURN r +MATCH ()-[r]-() WHERE ID(r)=1 RETURN r +MATCH (n: {id: 0}) SET n.name = "TEST100" RETURN n +MATCH (n: {id: 1}) SET n.name = "TEST101" RETURN n +MATCH (n: {id: 0}) SET n.name = "TEST102" RETURN n +MATCH (n:LABEL) RETURN n" +MATCH (n1), (n2) WHERE ID(n1)=0 AND ID(n2)=1 CREATE (n1)<-[r:IS {age: 25,weight: 70}]-(n2) RETURN r +MATCH (n) RETURN n", "MATCH (n:LABEL) RETURN n", "MATCH (n) DELETE n +MATCH (n:LABEL) DELETE n", "MATCH (n) WHERE ID(n) = 0 DELETE n +MATCH ()-[r]-() WHERE ID(r) = 0 DELETE r", "MATCH ()-[r]-() DELETE r +MATCH ()-[r:TYPE]-() DELETE r +MATCH (n)-[:TYPE]->(m) WHERE ID(n) = 0 RETURN m +MATCH (n)-[:TYPE]->(m) WHERE n.name = "kruno" RETURN m +MATCH (n)-[:TYPE]->(m) WHERE n.name = "kruno" RETURN n,m +MATCH (n:LABEL)-[:TYPE]->(m) RETURN n" +CREATE (n:LABEL1:LABEL2 {name: "TEST01", age: 20}) RETURN n +MATCH (n:LABEL1:LABEL2 {name: "TEST01", age: 20}) RETURN n diff --git a/tests/data/queries/core/dressipi.txt b/tests/data/queries/core/dressipi.txt new file mode 100644 index 000000000..892e783a7 --- /dev/null +++ b/tests/data/queries/core/dressipi.txt @@ -0,0 +1,15 @@ +CREATE (n {garment_id: 1234, garment_category_id: 1}) RETURN n +CREATE (p:profile {profile_id: 111, partner_id: 55}) RETURN p +MATCH (g:garment {garment_id: 1234}) SET g:FF RETURN labels(g) +MATCH (p:profile {profile_id: 111, partner_id: 55})-[s:score]-(g:garment{garment_id: 1234}) SET s.score = 1550 RETURN s.score +MATCH (g:garment {garment_id: 3456}) SET g.reveals = 50 RETURN g +MERGE (g1:garment {garment_id: 1234})-[r:default_outfit]-(g2:garment {garment_id: 2345}) RETURN r +MERGE (p:profile {profile_id: 111, partner_id: 55})-[s:score]-(g.garment {garment_id: 1234}) SET s.score=1500 RETURN s +MATCH (p:profile {profile_id: 111, partner_id: 55})-[s:score]-(g.garment {garment_id: 1234}) DELETE s +MATCH (p:profile {profile_id: 113}) DELETE p +MATCH (n) DETACH DELETE n +MATCH (p:profile) RETURN p +MATCH (g:garment) RETURN COUNT(g) +MATCH (g:garment {garment_id: 1234}) RETURN g +MATCH (p:profile {partner_id: 55}) RETURN p +MATCH (n) RETURN count(n) diff --git a/tests/data/cypher_queries/complex/fraudulent_transactions_query2.cypher b/tests/data/queries/cypher/complex/fraudulent_transactions_query2.cypher similarity index 100% rename from tests/data/cypher_queries/complex/fraudulent_transactions_query2.cypher rename to tests/data/queries/cypher/complex/fraudulent_transactions_query2.cypher diff --git a/tests/data/cypher_queries/complex/powerlinx_opportunities.cypher b/tests/data/queries/cypher/complex/powerlinx_opportunities.cypher similarity index 100% rename from tests/data/cypher_queries/complex/powerlinx_opportunities.cypher rename to tests/data/queries/cypher/complex/powerlinx_opportunities.cypher diff --git a/tests/data/cypher_queries/read-write/match-delete.cypher b/tests/data/queries/cypher/read-write/match-delete.cypher similarity index 100% rename from tests/data/cypher_queries/read-write/match-delete.cypher rename to tests/data/queries/cypher/read-write/match-delete.cypher diff --git a/tests/data/cypher_queries/read-write/match-set-return.cypher b/tests/data/queries/cypher/read-write/match-set-return.cypher similarity index 100% rename from tests/data/cypher_queries/read-write/match-set-return.cypher rename to tests/data/queries/cypher/read-write/match-set-return.cypher diff --git a/tests/data/cypher_queries/read-write/match-set.cypher b/tests/data/queries/cypher/read-write/match-set.cypher similarity index 100% rename from tests/data/cypher_queries/read-write/match-set.cypher rename to tests/data/queries/cypher/read-write/match-set.cypher diff --git a/tests/data/cypher_queries/read-write/match-where-delete.cypher b/tests/data/queries/cypher/read-write/match-where-delete.cypher similarity index 100% rename from tests/data/cypher_queries/read-write/match-where-delete.cypher rename to tests/data/queries/cypher/read-write/match-where-delete.cypher diff --git a/tests/data/cypher_queries/read/match/match-custom1.cypher b/tests/data/queries/cypher/read/match/match-custom1.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-custom1.cypher rename to tests/data/queries/cypher/read/match/match-custom1.cypher diff --git a/tests/data/cypher_queries/read/match/match-custom2.cypher b/tests/data/queries/cypher/read/match/match-custom2.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-custom2.cypher rename to tests/data/queries/cypher/read/match/match-custom2.cypher diff --git a/tests/data/cypher_queries/read/match/match-n-m.cypher b/tests/data/queries/cypher/read/match/match-n-m.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-n-m.cypher rename to tests/data/queries/cypher/read/match/match-n-m.cypher diff --git a/tests/data/cypher_queries/read/match/match-optional.cypher b/tests/data/queries/cypher/read/match/match-optional.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-optional.cypher rename to tests/data/queries/cypher/read/match/match-optional.cypher diff --git a/tests/data/cypher_queries/read/match/match-path.cypher b/tests/data/queries/cypher/read/match/match-path.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-path.cypher rename to tests/data/queries/cypher/read/match/match-path.cypher diff --git a/tests/data/cypher_queries/read/match/match-property.cypher b/tests/data/queries/cypher/read/match/match-property.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-property.cypher rename to tests/data/queries/cypher/read/match/match-property.cypher diff --git a/tests/data/cypher_queries/read/match/match-where.cypher b/tests/data/queries/cypher/read/match/match-where.cypher similarity index 100% rename from tests/data/cypher_queries/read/match/match-where.cypher rename to tests/data/queries/cypher/read/match/match-where.cypher diff --git a/tests/data/cypher_queries/read/return/return-alias.cypher b/tests/data/queries/cypher/read/return/return-alias.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-alias.cypher rename to tests/data/queries/cypher/read/return/return-alias.cypher diff --git a/tests/data/cypher_queries/read/return/return-all.cypher b/tests/data/queries/cypher/read/return/return-all.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-all.cypher rename to tests/data/queries/cypher/read/return/return-all.cypher diff --git a/tests/data/cypher_queries/read/return/return-count.cypher b/tests/data/queries/cypher/read/return/return-count.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-count.cypher rename to tests/data/queries/cypher/read/return/return-count.cypher diff --git a/tests/data/cypher_queries/read/return/return-distinct.cypher b/tests/data/queries/cypher/read/return/return-distinct.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-distinct.cypher rename to tests/data/queries/cypher/read/return/return-distinct.cypher diff --git a/tests/data/cypher_queries/read/return/return-limit.cypher b/tests/data/queries/cypher/read/return/return-limit.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-limit.cypher rename to tests/data/queries/cypher/read/return/return-limit.cypher diff --git a/tests/data/cypher_queries/read/return/return-list-001.cypher b/tests/data/queries/cypher/read/return/return-list-001.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-list-001.cypher rename to tests/data/queries/cypher/read/return/return-list-001.cypher diff --git a/tests/data/cypher_queries/read/return/return-order-asc.cypher b/tests/data/queries/cypher/read/return/return-order-asc.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-order-asc.cypher rename to tests/data/queries/cypher/read/return/return-order-asc.cypher diff --git a/tests/data/cypher_queries/read/return/return-order-desc.cypher b/tests/data/queries/cypher/read/return/return-order-desc.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-order-desc.cypher rename to tests/data/queries/cypher/read/return/return-order-desc.cypher diff --git a/tests/data/cypher_queries/read/return/return-skip-limit.cypher b/tests/data/queries/cypher/read/return/return-skip-limit.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-skip-limit.cypher rename to tests/data/queries/cypher/read/return/return-skip-limit.cypher diff --git a/tests/data/cypher_queries/read/return/return-skip.cypher b/tests/data/queries/cypher/read/return/return-skip.cypher similarity index 100% rename from tests/data/cypher_queries/read/return/return-skip.cypher rename to tests/data/queries/cypher/read/return/return-skip.cypher diff --git a/tests/data/cypher_queries/read/union/union-all.cypher b/tests/data/queries/cypher/read/union/union-all.cypher similarity index 100% rename from tests/data/cypher_queries/read/union/union-all.cypher rename to tests/data/queries/cypher/read/union/union-all.cypher diff --git a/tests/data/cypher_queries/read/union/union.cypher b/tests/data/queries/cypher/read/union/union.cypher similarity index 100% rename from tests/data/cypher_queries/read/union/union.cypher rename to tests/data/queries/cypher/read/union/union.cypher diff --git a/tests/data/cypher_queries/read/where/where.cypher b/tests/data/queries/cypher/read/where/where.cypher similarity index 100% rename from tests/data/cypher_queries/read/where/where.cypher rename to tests/data/queries/cypher/read/where/where.cypher diff --git a/tests/data/cypher_queries/read/with/match-with-order-skip-limit.cypher b/tests/data/queries/cypher/read/with/match-with-order-skip-limit.cypher similarity index 100% rename from tests/data/cypher_queries/read/with/match-with-order-skip-limit.cypher rename to tests/data/queries/cypher/read/with/match-with-order-skip-limit.cypher diff --git a/tests/data/cypher_queries/read/with/match-with-where.cypher b/tests/data/queries/cypher/read/with/match-with-where.cypher similarity index 100% rename from tests/data/cypher_queries/read/with/match-with-where.cypher rename to tests/data/queries/cypher/read/with/match-with-where.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_00.cypher b/tests/data/queries/cypher/sprint_0/query_00.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_00.cypher rename to tests/data/queries/cypher/sprint_0/query_00.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_01.cypher b/tests/data/queries/cypher/sprint_0/query_01.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_01.cypher rename to tests/data/queries/cypher/sprint_0/query_01.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_02.cypher b/tests/data/queries/cypher/sprint_0/query_02.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_02.cypher rename to tests/data/queries/cypher/sprint_0/query_02.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_03.cypher b/tests/data/queries/cypher/sprint_0/query_03.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_03.cypher rename to tests/data/queries/cypher/sprint_0/query_03.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_04.cypher b/tests/data/queries/cypher/sprint_0/query_04.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_04.cypher rename to tests/data/queries/cypher/sprint_0/query_04.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_05.cypher b/tests/data/queries/cypher/sprint_0/query_05.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_05.cypher rename to tests/data/queries/cypher/sprint_0/query_05.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_06.cypher b/tests/data/queries/cypher/sprint_0/query_06.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_06.cypher rename to tests/data/queries/cypher/sprint_0/query_06.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_07.cypher b/tests/data/queries/cypher/sprint_0/query_07.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_07.cypher rename to tests/data/queries/cypher/sprint_0/query_07.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_08.cypher b/tests/data/queries/cypher/sprint_0/query_08.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_08.cypher rename to tests/data/queries/cypher/sprint_0/query_08.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_09.cypher b/tests/data/queries/cypher/sprint_0/query_09.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_09.cypher rename to tests/data/queries/cypher/sprint_0/query_09.cypher diff --git a/tests/data/cypher_queries/sprint_0/query_10.cypher b/tests/data/queries/cypher/sprint_0/query_10.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_0/query_10.cypher rename to tests/data/queries/cypher/sprint_0/query_10.cypher diff --git a/tests/data/cypher_queries/sprint_1/query_0.cypher b/tests/data/queries/cypher/sprint_1/query_0.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_1/query_0.cypher rename to tests/data/queries/cypher/sprint_1/query_0.cypher diff --git a/tests/data/cypher_queries/sprint_1/query_1.cypher b/tests/data/queries/cypher/sprint_1/query_1.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_1/query_1.cypher rename to tests/data/queries/cypher/sprint_1/query_1.cypher diff --git a/tests/data/cypher_queries/sprint_1/query_5.cypher b/tests/data/queries/cypher/sprint_1/query_5.cypher similarity index 100% rename from tests/data/cypher_queries/sprint_1/query_5.cypher rename to tests/data/queries/cypher/sprint_1/query_5.cypher diff --git a/tests/data/cypher_queries/write/create-return.cypher b/tests/data/queries/cypher/write/create-return.cypher similarity index 100% rename from tests/data/cypher_queries/write/create-return.cypher rename to tests/data/queries/cypher/write/create-return.cypher diff --git a/tests/data/cypher_queries/write/create.cypher b/tests/data/queries/cypher/write/create.cypher similarity index 100% rename from tests/data/cypher_queries/write/create.cypher rename to tests/data/queries/cypher/write/create.cypher diff --git a/tests/data/queries/opencypher/dummy.txt b/tests/data/queries/opencypher/dummy.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/integration/cleaning.cpp b/tests/integration/cleaning.cpp index 1bca27a75..60adb81f5 100644 --- a/tests/integration/cleaning.cpp +++ b/tests/integration/cleaning.cpp @@ -1,11 +1,6 @@ -#include "query/hardcode/queries.hpp" - -#ifdef BARRIER -#include "barrier/barrier.cpp" -#endif - #include "logging/default.hpp" #include "logging/streams/stdout.hpp" +#include "query/hardcode/basic.hpp" #include "query/strip/stripper.hpp" #include "utils/sysinfo/memory.hpp" @@ -15,7 +10,8 @@ void run(size_t n, std::string &query, S &stripper, Q &qf) auto stripped = stripper.strip(query); std::cout << "Running query [" << stripped.hash << "] for " << n << " time." << std::endl; - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) + { properties_t vec = stripped.arguments; assert(qf[stripped.hash](std::move(vec))); } @@ -37,11 +33,7 @@ int main(void) Db db("cleaning"); -#ifdef BARRIER - auto query_functions = load_queries(barrier::trans(db)); -#else - auto query_functions = load_queries(db); -#endif + auto query_functions = hardcode::load_basic_functions(db); auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); @@ -50,7 +42,7 @@ int main(void) std::string create_vertex_other = "CREATE (n:OTHER {name: \"cleaner_test\"}) RETURN n"; std::string delete_label_vertices = "MATCH (n:LABEL) DELETE n"; - std::string delete_all_vertices = "MATCH (n) DELETE n"; + std::string delete_all_vertices = "MATCH (n) DELETE n"; // ******************************* TEST 1 ********************************// // add vertices a diff --git a/tests/integration/index.cpp b/tests/integration/index.cpp index 56db281b0..42bc96aad 100644 --- a/tests/integration/index.cpp +++ b/tests/integration/index.cpp @@ -1,11 +1,6 @@ -#include "query/hardcode/queries.hpp" - #include -#ifdef BARRIER -#include "barrier/barrier.cpp" -#endif - +#include "query/hardcode/basic.hpp" #include "logging/default.hpp" #include "logging/streams/stdout.hpp" #include "query/strip/stripper.hpp" @@ -24,11 +19,7 @@ void run(size_t n, std::string &query, Db &db) { auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); -#ifdef BARRIER - auto qf = load_queries(barrier::trans(db)); -#else - auto qf = load_queries(db); -#endif + auto qf = hardcode::load_basic_functions(db); auto stripped = stripper.strip(query); std::cout << "Running query [" << stripped.hash << "] for " << n << " time." @@ -43,11 +34,7 @@ void add_edge(size_t n, Db &db) { auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); -#ifdef BARRIER - auto qf = load_queries(barrier::trans(db)); -#else - auto qf = load_queries(db); -#endif + auto qf = hardcode::load_basic_functions(db); std::string query = "MATCH (n1), (n2) WHERE ID(n1)=0 AND " "ID(n2)=1 CREATE (n1)<-[r:IS {age: " diff --git a/tests/integration/queries.cpp b/tests/integration/queries.cpp index 5326f1208..46a25bcc5 100644 --- a/tests/integration/queries.cpp +++ b/tests/integration/queries.cpp @@ -1,76 +1,60 @@ -#include "query/hardcode/queries.hpp" - -#ifdef BARRIER -#include "barrier/barrier.cpp" -#endif - #include "communication/bolt/v1/serialization/bolt_serializer.hpp" #include "database/db.hpp" #include "logging/default.hpp" #include "logging/streams/stdout.hpp" +#include "query/hardcode/basic.hpp" +#include "query/hardcode/dressipi.hpp" #include "query/strip/stripper.hpp" +#include "utils/string/file.hpp" +#include "utils/variadic/variadic.hpp" +#include "utils/command_line/arguments.hpp" -int main(void) +int main(int argc, char *argv[]) { + auto arguments = all_arguments(argc, argv); + + // POSSIBILITIES: basic, dressipi + auto suite_name = get_argument(arguments, "-s", "basic"); + // POSSIBILITIES: query_execution, hash_generation + auto work_mode = get_argument(arguments, "-w", "query_execution"); + + // init logging logging::init_async(); logging::log->pipe(std::make_unique()); + // init db, functions and stripper Db db; - -#ifdef BARRIER - auto query_functions = load_queries(barrier::trans(db)); -#else - auto query_functions = load_queries(db); -#endif - + hardcode::query_functions_t query_functions; + if (suite_name == "dressipi") + { + query_functions = std::move(hardcode::load_dressipi_functions(db)); + } + else + { + query_functions = std::move(hardcode::load_basic_functions(db)); + } auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); - // TODO: put all queries into a file - std::vector queries = { + // load quries + std::string file_path = "data/queries/core/" + suite_name + ".txt"; + auto queries = utils::read_lines(file_path.c_str()); - // CREATE and MATCH by label and property - "CREATE (n:LABEL {name: \"TEST01\"}) RETURN n", - "CREATE (n:LABEL {name: \"TEST02\"}) RETURN n", - // "MATCH (n:LABEL {name: \"TEST01\"}) RETURN n", + // execute all queries + for (auto &query : queries) + { + utils::println("Query: ", query); - "CREATE (n:LABEL {name: \"TEST2\"}) RETURN n", - "CREATE (n:LABEL {name: \"TEST3\"}) RETURN n", - "CREATE (n:OTHER {name: \"TEST4\"}) RETURN n" - "CREATE (n:ACCOUNT {id: 2322, name: \"TEST\", country: \"Croatia\", " - "created_at: 2352352}) RETURN n", - "MATCH (n {id: 0}) RETURN n", "MATCH (n {id: 1}) RETURN n", - "MATCH (n {id: 2}) RETURN n", "MATCH (n {id: 3}) RETURN n", - "MATCH (a {id:0}), (p {id: 1}) CREATE (a)-[r:IS]->(p) RETURN r", - "MATCH (a {id:1}), (p {id: 2}) CREATE (a)-[r:IS]->(p) RETURN r", - "MATCH ()-[r]-() WHERE ID(r)=0 RETURN r", - "MATCH ()-[r]-() WHERE ID(r)=1 RETURN r", - "MATCH (n: {id: 0}) SET n.name = \"TEST100\" RETURN n", - "MATCH (n: {id: 1}) SET n.name = \"TEST101\" RETURN n", - "MATCH (n: {id: 0}) SET n.name = \"TEST102\" RETURN n", - "MATCH (n:LABEL) RETURN n", "MATCH (n1), (n2) WHERE ID(n1)=0 AND " - "ID(n2)=1 CREATE (n1)<-[r:IS {age: " - "25,weight: 70}]-(n2) RETURN r", - "MATCH (n) RETURN n", "MATCH (n:LABEL) RETURN n", "MATCH (n) DELETE n ", - "MATCH (n:LABEL) DELETE n", "MATCH (n) WHERE ID(n) = 0 DELETE n", - "MATCH ()-[r]-() WHERE ID(r) = 0 DELETE r", "MATCH ()-[r]-() DELETE r", - "MATCH ()-[r:TYPE]-() DELETE r", - "MATCH (n)-[:TYPE]->(m) WHERE ID(n) = 0 RETURN m", - "MATCH (n)-[:TYPE]->(m) WHERE n.name = \"kruno\" RETURN m", - "MATCH (n)-[:TYPE]->(m) WHERE n.name = \"kruno\" RETURN n,m", - "MATCH (n:LABEL)-[:TYPE]->(m) RETURN n" - - // CREATE and MATCH multiple labels and properties - // "CREATE (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n", - // "MATCH (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n" - }; - - for (auto &query : queries) { auto stripped = stripper.strip(query); - std::cout << "Query hash: " << stripped.hash << std::endl; + utils::println("Hash: ", stripped.hash); + + // TODO: more robust solution (enum like) + if (work_mode == "hash_generation") continue; + auto result = query_functions[stripped.hash](std::move(stripped.arguments)); permanent_assert(result == true, "Result retured from query function is not true"); + utils::println("------------------------ PASS"); } return 0; diff --git a/tests/integration/snapshot.cpp b/tests/integration/snapshot.cpp index 3a233bff9..682618950 100644 --- a/tests/integration/snapshot.cpp +++ b/tests/integration/snapshot.cpp @@ -1,13 +1,8 @@ -#include "query/hardcode/queries.hpp" - #include -#ifdef BARRIER -#include "barrier/barrier.cpp" -#endif - #include "logging/default.hpp" #include "logging/streams/stdout.hpp" +#include "query/hardcode/basic.hpp" #include "query/strip/stripper.hpp" #include "storage/indexes/indexes.hpp" #include "utils/sysinfo/memory.hpp" @@ -24,16 +19,13 @@ void run(size_t n, std::string &query, Db &db) { auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); -#ifdef BARRIER - auto qf = load_queries(barrier::trans(db)); -#else - auto qf = load_queries(db); -#endif + auto qf = hardcode::load_basic_functions(db); auto stripped = stripper.strip(query); std::cout << "Running query [" << stripped.hash << "] for " << n << " time." << std::endl; - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) + { properties_t vec = stripped.arguments; assert(qf[stripped.hash](std::move(vec))); } @@ -42,11 +34,7 @@ void run(size_t n, std::string &query, Db &db) void add_edge(size_t n, Db &db) { auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); -#ifdef BARRIER - auto qf = load_queries(barrier::trans(db)); -#else - auto qf = load_queries(db); -#endif + auto qf = hardcode::load_basic_functions(db); std::string query = "MATCH (n1), (n2) WHERE ID(n1)=0 AND " "ID(n2)=1 CREATE (n1)<-[r:IS {age: " @@ -57,15 +45,17 @@ void add_edge(size_t n, Db &db) << " time to add edge." << std::endl; std::vector vertices; - for (auto &v : db.graph.vertices.access()) { + for (auto &v : db.graph.vertices.access()) + { vertices.push_back(v.second.id); } auto rand = rand_gen(vertices.size()); - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) + { properties_t vec = stripped.arguments; - vec[0] = Property(Int64(vertices[rand()]), Flags::Int64); - vec[1] = Property(Int64(vertices[rand()]), Flags::Int64); + vec[0] = Property(Int64(vertices[rand()]), Flags::Int64); + vec[1] = Property(Int64(vertices[rand()]), Flags::Int64); assert(qf[stripped.hash](std::move(vec))); } } @@ -99,8 +89,9 @@ size_t size(Db &db, IndexHolder &h) DbAccessor t(db); size_t count = 0; - auto oin = h.get_read(); - if (oin.is_present()) { + auto oin = h.get_read(); + if (oin.is_present()) + { oin.get()->for_range(t).for_all([&](auto va) mutable { count++; }); } @@ -132,7 +123,7 @@ void clean_edge(Db &db) void clear_database(Db &db) { std::string delete_all_vertices = "MATCH (n) DELETE n"; - std::string delete_all_edges = "MATCH ()-[r]-() DELETE r"; + std::string delete_all_edges = "MATCH ()-[r]-() DELETE r"; run(1, delete_all_edges, db); run(1, delete_all_vertices, db); @@ -147,14 +138,16 @@ bool equal(Db &a, Db &b) auto acc_a = a.graph.vertices.access(); auto acc_b = b.graph.vertices.access(); - if (acc_a.size() != acc_b.size()) { + if (acc_a.size() != acc_b.size()) + { return false; } auto it_a = acc_a.begin(); auto it_b = acc_b.begin(); - for (auto i = acc_a.size(); i > 0; i--) { + for (auto i = acc_a.size(); i > 0; i--) + { // TODO: compare } } @@ -163,14 +156,16 @@ bool equal(Db &a, Db &b) auto acc_a = a.graph.edges.access(); auto acc_b = b.graph.edges.access(); - if (acc_a.size() != acc_b.size()) { + if (acc_a.size() != acc_b.size()) + { return false; } auto it_a = acc_a.begin(); auto it_b = acc_b.begin(); - for (auto i = acc_a.size(); i > 0; i--) { + for (auto i = acc_a.size(); i > 0; i--) + { // TODO: compare } } @@ -190,7 +185,7 @@ int main(void) std::string create_vertex_other = "CREATE (n:OTHER {name: \"cleaner_test\"}) RETURN n"; std::string delete_label_vertices = "MATCH (n:LABEL) DELETE n"; - std::string delete_all_vertices = "MATCH (n) DELETE n"; + std::string delete_all_vertices = "MATCH (n) DELETE n"; // ******************************* TEST 1 ********************************// { diff --git a/tests/manual/cypher_ast.cpp b/tests/manual/cypher_ast.cpp index 588072018..ab5242033 100644 --- a/tests/manual/cypher_ast.cpp +++ b/tests/manual/cypher_ast.cpp @@ -19,14 +19,18 @@ int main(int argc, char *argv[]) auto arguments = all_arguments(argc, argv); // // query extraction - auto cypher_query = extract_query(arguments); - cout << "QUERY: " << cypher_query << endl; + auto queries = extract_queries(arguments); - auto print_visitor = new PrintVisitor(cout); - cypher::Compiler compiler; - auto tree = compiler.syntax_tree(cypher_query); - tree.root->accept(*print_visitor); - cout << endl; + + for (auto &query : queries) + { + cout << "QUERY: " << query << endl; + auto print_visitor = new PrintVisitor(cout); + cypher::Compiler compiler; + auto tree = compiler.syntax_tree(query); + tree.root->accept(*print_visitor); + cout << endl; + } return 0; } diff --git a/tests/manual/queries.cpp b/tests/manual/queries.cpp index df189f7ae..01da7ef8a 100644 --- a/tests/manual/queries.cpp +++ b/tests/manual/queries.cpp @@ -1,15 +1,11 @@ #include -#include "query/hardcode/queries.hpp" - -#ifdef BARRIER -#include "barrier/barrier.cpp" -#endif - #include "communication/bolt/v1/serialization/bolt_serializer.hpp" #include "database/db.hpp" #include "logging/default.hpp" #include "logging/streams/stdout.hpp" +#include "query/hardcode/basic.hpp" +#include "query/hardcode/dressipi.hpp" #include "query/strip/stripper.hpp" #include "storage/edges.cpp" #include "storage/edges.hpp" @@ -24,25 +20,23 @@ int main(int argc, char **argv) logging::log->pipe(std::make_unique()); Db db; -#ifdef BARRIER - auto queries = load_queries(barrier::trans(db)); -#else - auto queries = load_queries(db); -#endif + auto queries = hardcode::load_basic_functions(db); auto stripper = make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL); vector history; string command; cout << "-- Memgraph query engine --" << endl; - do { + do + { cout << "> "; getline(cin, command); history.push_back(command); auto stripped = stripper.strip(command); - if (queries.find(stripped.hash) == queries.end()) { + if (queries.find(stripped.hash) == queries.end()) + { cout << "unsupported query" << endl; continue; } diff --git a/tests/manual/query_hasher.cpp b/tests/manual/query_hasher.cpp index bc0e9cba6..99e7dbf47 100644 --- a/tests/manual/query_hasher.cpp +++ b/tests/manual/query_hasher.cpp @@ -15,18 +15,24 @@ int main(int argc, char **argv) auto arguments = all_arguments(argc, argv); // query extraction - auto input_query = extract_query(arguments); + auto queries = extract_queries(arguments); QueryPreprocessor preprocessor; - auto preprocessed = preprocessor.preprocess(input_query); - cout << "QUERY: " << input_query << endl; - cout << "STRIPPED QUERY: " << preprocessed.query << endl; - cout << "QUERY HASH: " << preprocessed.hash << endl; - cout << "PROPERTIES:" << endl; - for (auto property : preprocessed.arguments) { - cout << " " << property << endl; + for (auto &query : queries) + { + auto preprocessed = preprocessor.preprocess(query); + cout << "QUERY: " << query << endl; + cout << "STRIPPED QUERY: " << preprocessed.query << endl; + cout << "QUERY HASH: " << preprocessed.hash << endl; + cout << "PROPERTIES:" << endl; + for (auto property : preprocessed.arguments) { + cout << " " << property << endl; + } + cout << "-----------------------------" << endl; } + + return 0; }