Skip to content
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ FetchContent_MakeAvailable(logger)
FetchContent_Declare(
argparse
GIT_REPOSITORY https://github.com/p-ranav/argparse.git
GIT_TAG 997da9255618311d1fcb0135ce86022729d1f1cb # release-2.9
GIT_TAG 68fd0277eea5412aff9b91c0b70efc698359dae0 # release-3.1
)
FetchContent_MakeAvailable(argparse)
FetchContent_Declare(
Expand Down
40 changes: 33 additions & 7 deletions include/SCC/config/scc_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,22 @@

namespace scc::config {

constexpr std::string_view SCC_SCHEMA_SUBCOMMAND = "schema";
constexpr std::string_view SCC_DATA_SUBCOMMAND = "data";

class no_argument_error : private std::runtime_error {
public:
explicit no_argument_error(const std::string& message);
};

class SCCArgs : public argparse::ArgumentParser {
class SCCArgumentParser : public argparse::ArgumentParser {
public:
explicit SCCArgs();
explicit SCCArgumentParser(std::string_view program_name);

void ParseArgs(int argc, const char* const argv[]);
SCCArgumentParser& subparser(std::string_view name);

template<typename T = std::string>
auto Get(const std::string& arg_name) const
-> std::conditional_t<argparse::details::IsContainer<T>, T, const T&> {
T Get(const std::string& arg_name) const {
try {
return get<T>(arg_name);
} catch (const std::logic_error& e) {
Expand All @@ -60,10 +62,34 @@ class SCCArgs : public argparse::ArgumentParser {
return present<T>(arg_name);
}

bool IsUsed(const std::string& arg_name) const;
[[nodiscard]] bool IsUsed(const std::string& arg_name) const;

private:
void PrintHelpAndExit(int exit_code) const;
};

class SCCArgs : public SCCArgumentParser {
public:
explicit SCCArgs();

void ParseArgs(int argc, const char* const argv[]);
};

class SCCSubcommand : public SCCArgumentParser {
public:
explicit SCCSubcommand(std::string_view subcommand, const std::string& description);
virtual ~SCCSubcommand() = default;
};

class SCCSubcommandSchema : public SCCSubcommand {
public:
explicit SCCSubcommandSchema();
~SCCSubcommandSchema() override = default;
};

class SCCSubcommandData : public SCCSubcommand {
public:
explicit SCCSubcommandData();
~SCCSubcommandData() override = default;
};

} // scc::config
4 changes: 2 additions & 2 deletions include/SCC/config/scc_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class SCCConfig : public common::Singleton<SCCConfig> {
bool translate_schema;
bool translate_data;

explicit SCCConfig(const SCCArgs& args);
explicit SCCConfig(SCCArgs& args);

static SCCConfig* Get();

Expand All @@ -42,6 +42,6 @@ class SCCConfig : public common::Singleton<SCCConfig> {
std::filesystem::path ast_dump_file_;
};

void InitConfig(const SCCArgs& args);
void InitConfig(SCCArgs& args);

} // scc::config
42 changes: 21 additions & 21 deletions include/SCC/parser/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,19 @@ class Parser {
std::shared_ptr<ast::INode> ParseMathPower();
std::shared_ptr<ast::INode> ParseMathValue();

ast::StmtType DetermineConstraintType(const std::string& keyword) const;
ast::StmtType DetermineAlterTableActionType(const std::string& keyword) const;
ast::StmtType DetermineDropElementType(const std::string& keyword) const;
ast::StmtType DetermineLogicalOperatorType(const std::string& keyword) const;

bool DetermineIsFullConstraintDefinition(const std::string& keyword) const;
bool DetermineIsPrimaryKey(const std::string& keyword) const;
bool DetermineIsForeignKey(const std::string& keyword) const;
bool DetermineIsReferences(const std::string& keyword) const;
bool DetermineIsOROperator(const std::string& keyword) const;
bool DetermineIsANDOperator(const std::string& keyword) const;
bool DetermineIsNOTOperator(const std::string& keyword) const;
bool DetermineIsPrefix(const std::string_view& string, const std::string& prefix) const;
static ast::StmtType DetermineConstraintType(const std::string& keyword);
static ast::StmtType DetermineAlterTableActionType(const std::string& keyword);
static ast::StmtType DetermineDropElementType(const std::string& keyword);
static ast::StmtType DetermineLogicalOperatorType(const std::string& keyword);

static bool DetermineIsFullConstraintDefinition(const std::string& keyword);
static bool DetermineIsPrimaryKey(const std::string& keyword);
static bool DetermineIsForeignKey(const std::string& keyword);
static bool DetermineIsReferences(const std::string& keyword);
static bool DetermineIsOROperator(const std::string& keyword);
static bool DetermineIsANDOperator(const std::string& keyword);
static bool DetermineIsNOTOperator(const std::string& keyword);
static bool DetermineIsPrefix(const std::string_view& string, const std::string& prefix);

std::shared_ptr<ast::INode> ParsePrimaryKey();
std::shared_ptr<ast::INode> ParseForeignKey();
Expand All @@ -127,14 +127,14 @@ class Parser {
void ValidateHasTokens(unsigned min_count = 1) const;
void ValidateHasNotTokens() const;

void ValidateIsWord(const std::shared_ptr<ast::INode>& node) const;
void ValidateIsOpeningRoundBracket(const std::shared_ptr<ast::INode>& node) const;
void ValidateIsClosingRoundBracket(const std::shared_ptr<ast::INode>& node) const;
void ValidateIsSingleQuote(const std::shared_ptr<ast::INode>& node) const;
void ValidateIsDoubleQuote(const std::shared_ptr<ast::INode>& node) const;
void ValidateIsBinaryOperator(const std::shared_ptr<ast::INode>& node) const;

void ValidateIsAssignmentOperator(const std::shared_ptr<ast::INode>& node) const;
static void ValidateIsWord(const std::shared_ptr<ast::INode>& node);
static void ValidateIsOpeningRoundBracket(const std::shared_ptr<ast::INode>& node);
static void ValidateIsClosingRoundBracket(const std::shared_ptr<ast::INode>& node);
static void ValidateIsSingleQuote(const std::shared_ptr<ast::INode>& node);
static void ValidateIsDoubleQuote(const std::shared_ptr<ast::INode>& node);
static void ValidateIsBinaryOperator(const std::shared_ptr<ast::INode>& node);
static void ValidateIsAssignmentOperator(const std::shared_ptr<ast::INode>& node);
};

} // scc::parser
39 changes: 20 additions & 19 deletions include/SCC/translator/translator.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ class Translator {
void TranslateAlterTableActionDrop(const std::shared_ptr<ast::INode>& action_node,
std::string& table_name);

std::vector<schema::Property> TranslateColumnDefinitions(
static std::vector<schema::Property> TranslateColumnDefinitions(
const std::shared_ptr<ast::INode>& column_definition);
schema::Property TranslateColumnDefinition(const std::shared_ptr<ast::INode>& node);
static schema::Property TranslateColumnDefinition(const std::shared_ptr<ast::INode>& node);
void TranslateTableConstraint(const std::shared_ptr<ast::INode>& constraint_definition,
const std::string& table_name);

Expand All @@ -96,17 +96,17 @@ class Translator {
void TranslateForeignKey(const std::shared_ptr<ast::INode>& foreign_key,
const std::string& constraint_name, const std::string& table_name);

std::string GetName(const std::shared_ptr<ast::INode>& name_node) const;
std::string GetIdentifier(const std::shared_ptr<ast::INode>& node) const;
static std::string GetName(const std::shared_ptr<ast::INode>& name_node);
static std::string GetIdentifier(const std::shared_ptr<ast::INode>& node);

std::pair<cypher::PropertyType, std::string>
TranslateExpression(const std::shared_ptr<ast::INode>& expr) const;
static TranslateExpression(const std::shared_ptr<ast::INode>& expr);

std::string TranslateMathExpression(const std::shared_ptr<ast::INode>& expr) const;
std::string TranslateMathSum(const std::shared_ptr<ast::INode>& sum) const;
std::string TranslateMathProduct(const std::shared_ptr<ast::INode>& product) const;
std::string TranslateMathPower(const std::shared_ptr<ast::INode>& power) const;
std::string TranslateMathValue(const std::shared_ptr<ast::INode>& value) const;
static std::string TranslateMathExpression(const std::shared_ptr<ast::INode>& expr);
static std::string TranslateMathSum(const std::shared_ptr<ast::INode>& sum);
static std::string TranslateMathProduct(const std::shared_ptr<ast::INode>& product);
static std::string TranslateMathPower(const std::shared_ptr<ast::INode>& power);
static std::string TranslateMathValue(const std::shared_ptr<ast::INode>& value);

void AddPropertyConstraints(const std::string& constraint_name_prefix, const std::string& label,
const std::string& property_name,
Expand All @@ -120,21 +120,22 @@ class Translator {
const std::string& end_label, const std::vector<std::string>& end_node_props
);
std::string CreateRelationshipType(const std::string& type_prefix);
std::string CreatePKConstraintPrefix(const std::string& table_name) const;
std::string CreateFKConstraintPrefix(const std::string& table_name,
const std::string& ref_table_name) const;
static std::string CreatePKConstraintPrefix(const std::string& table_name);
static std::string CreateFKConstraintPrefix(const std::string& table_name,
const std::string& ref_table_name);

const schema::Node& GetNodeFromSchema(const std::string& label) const;

// Validation

bool HasChildren(const std::shared_ptr<ast::INode>& node, unsigned min_children_count = 1) const;
bool IsCorrectStmtType(const std::shared_ptr<ast::INode>& node, ast::StmtType stmt_type) const;
static bool HasChildren(const std::shared_ptr<ast::INode>& node, unsigned min_children_count = 1);
static bool IsCorrectStmtType(const std::shared_ptr<ast::INode>& node, ast::StmtType stmt_type);

void ValidateHasChildren(const std::shared_ptr<ast::INode>& node, unsigned min_children_count = 1,
const std::string& details = "") const;
void ValidateIsCorrectStmtType(const std::shared_ptr<ast::INode>& node,
ast::StmtType stmt_type) const;
static void ValidateHasChildren(const std::shared_ptr<ast::INode>& node,
unsigned min_children_count = 1,
const std::string& details = "");
static void ValidateIsCorrectStmtType(const std::shared_ptr<ast::INode>& node,
ast::StmtType stmt_type);
};

} // scc::translator
120 changes: 83 additions & 37 deletions src/config/scc_args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,31 @@

namespace scc::config {

using namespace argparse;

no_argument_error::no_argument_error(const std::string& message)
: std::runtime_error(message) {}

SCCArgs::SCCArgs() : ArgumentParser(PROGRAM_NAME, VERSION, argparse::default_arguments::none) {
SCCArgumentParser::SCCArgumentParser(std::string_view program_name)
: ArgumentParser(std::string(program_name), VERSION, default_arguments::none) {
set_assign_chars("= ");
}

SCCArgumentParser& SCCArgumentParser::subparser(std::string_view name) {
auto& subparser = at<ArgumentParser>(name);
return static_cast<SCCArgumentParser&>(subparser);
}

bool SCCArgumentParser::IsUsed(const std::string& arg_name) const {
return is_used(arg_name);
}

void SCCArgumentParser::PrintHelpAndExit(int exit_code) const {
std::cout << help().str();
exit(exit_code);
}

SCCArgs::SCCArgs() : SCCArgumentParser(PROGRAM_NAME) {
add_description("Translates SQL queries for MS SQL Server into queries for Neo4j DBMS.");
add_epilog("Contribute to SCC: " CONTRIBUTE_LINK);

Expand All @@ -30,37 +49,6 @@ SCCArgs::SCCArgs() : ArgumentParser(PROGRAM_NAME, VERSION, argparse::default_arg
.implicit_value(true)
.nargs(0);

add_argument("--translate-schema")
.help("Use this option to translate SQL schema migration queries into Cypher")
.default_value(false)
.implicit_value(true);

add_argument("--sql-schema")
.help("Specify path to the file with SQL schema migration queries to be converted")
.metavar("FILENAME");

std::string default_graph_schema_file =
(std::filesystem::current_path() / "schema.json").string();
add_argument("--graph-schema")
.help("Specify path to the file with Neo4j graph schema")
.metavar("FILENAME")
.default_value(default_graph_schema_file);

add_argument("--translate-data")
.help("Use this option to translate SQL data migration queries into Cypher")
.default_value(false)
.implicit_value(true);

add_argument("--sql")
.help("Specify path to the file with SQL data migration queries to be converted")
.metavar("FILENAME");

std::string default_cypher_file = (std::filesystem::current_path() / "out.cql").string();
add_argument("--cypher")
.help("Specify path to the file with the result CypherQL queries")
.metavar("FILENAME")
.default_value(default_cypher_file);

add_argument("--dump")
.help("Specify path to the PNG image with the dump of SQL AST")
.metavar("FILENAME");
Expand Down Expand Up @@ -92,19 +80,77 @@ void SCCArgs::ParseArgs(int argc, const char* const argv[]) {

try {
parse_args(argc, argv);

if (argc == 2) {
if (is_subcommand_used(SCC_SCHEMA_SUBCOMMAND)) {
auto& schema_subparser = subparser(SCC_SCHEMA_SUBCOMMAND);
schema_subparser.PrintHelpAndExit(EXIT_SUCCESS);
}
if (is_subcommand_used(SCC_DATA_SUBCOMMAND)) {
auto& data_subparser = subparser(SCC_DATA_SUBCOMMAND);
data_subparser.PrintHelpAndExit(EXIT_SUCCESS);
}
}
} catch (const std::runtime_error& e) {
std::cerr << e.what() << std::endl;
PrintHelpAndExit(EXIT_FAILURE);
}
}

bool SCCArgs::IsUsed(const std::string& arg_name) const {
return is_used(arg_name);
SCCSubcommand::SCCSubcommand(std::string_view name, const std::string& description)
: SCCArgumentParser(name) {
add_description(description);

add_argument("-h", "--help")
.action([this](const std::string& /*unused*/) {
std::cout << help().str();
exit(EXIT_SUCCESS);
})
.help("Show this info")
.default_value(false)
.implicit_value(true)
.nargs(0);

add_argument("-v", "--version")
.action([](const std::string& /*unused*/) {
std::cout << "scc version " VERSION << std::endl;
exit(EXIT_SUCCESS);
})
.help("Show version info")
.default_value(false)
.implicit_value(true)
.nargs(0);
}

void SCCArgs::PrintHelpAndExit(int exit_code) const {
std::cout << help().str();
exit(exit_code);
SCCSubcommandSchema::SCCSubcommandSchema()
: SCCSubcommand(SCC_SCHEMA_SUBCOMMAND, "Translate SQL schema migration queries into Cypher.") {
add_argument("--sql")
.help("Specify path to the file with SQL schema migration queries to be converted")
.metavar("FILENAME");

std::string default_graph_schema_file =
(std::filesystem::current_path() / "schema.json").string();
add_argument("--graph-schema")
.help("Specify path to the file with Neo4j graph schema")
.metavar("FILENAME")
.default_value(default_graph_schema_file);
}

SCCSubcommandData::SCCSubcommandData()
: SCCSubcommand(SCC_DATA_SUBCOMMAND, "Translate SQL data migration queries into Cypher.") {
add_argument("--graph-schema")
.help("Specify path to the file with Neo4j graph schema")
.metavar("FILENAME");

add_argument("--sql")
.help("Specify path to the file with SQL data migration queries to be converted")
.metavar("FILENAME");

std::string default_cypher_file = (std::filesystem::current_path() / "out.cql").string();
add_argument("--cypher")
.help("Specify path to the file with the result CypherQL queries")
.metavar("FILENAME")
.default_value(default_cypher_file);
}

} // scc::config
Loading