Make create/delete accept list instance paths
Change-Id: I5991e1377ebc0edcfc3f8dbc60066a580314a51a
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c9f9919..1289ac4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -173,6 +173,7 @@
cli_test(path_completion)
cli_test(command_completion)
cli_test(enum_completion)
+ cli_test(list_manipulation)
endif()
if(WITH_DOCS)
diff --git a/src/ast_commands.hpp b/src/ast_commands.hpp
index 634a190..5015787 100644
--- a/src/ast_commands.hpp
+++ b/src/ast_commands.hpp
@@ -86,12 +86,13 @@
static constexpr auto name = "create";
static constexpr auto shortHelp = "create - Create a presence container.";
static constexpr auto longHelp = R"(
- create path_to_presence_container
+ create path
- Creates a presence container specified by a path.
+ Creates a presence container or a list instance specified by path.
Usage:
- /> create /module:pContainer)";
+ /> create /module:pContainer
+ /> create /module:list[key=value][anotherKey=value])";
bool operator==(const create_& b) const;
dataPath_ m_path;
};
@@ -100,12 +101,13 @@
static constexpr auto name = "delete";
static constexpr auto shortHelp = "delete - Delete a presence container.";
static constexpr auto longHelp = R"(
- delete path_to_presence_container
+ delete path
- Delete a presence container specified by a path.
+ Deletes a presence container or a list instance specified by path.
Usage:
- /> delete /module:pContainer)";
+ /> delete /module:pContainer
+ /> delete /module:list[key=value][anotherKey=value])";
bool operator==(const delete_& b) const;
dataPath_ m_path;
};
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index c937eee..d365641 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -312,6 +312,18 @@
}
};
+struct listInstancePath_class {
+ template <typename T, typename Iterator, typename Context>
+ void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
+ {
+ auto& parserContext = x3::get<parser_context_tag>(context);
+ if (ast.m_nodes.back().m_suffix.type() != typeid(listElement_)) {
+ parserContext.m_errorMsg = "This is not a list instance.";
+ _pass(context) = false;
+ }
+ }
+};
+
struct create_class {
template <typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
diff --git a/src/datastore_access.hpp b/src/datastore_access.hpp
index 7972523..2f75e51 100644
--- a/src/datastore_access.hpp
+++ b/src/datastore_access.hpp
@@ -24,6 +24,8 @@
virtual void setLeaf(const std::string& path, leaf_data_ value) = 0;
virtual void createPresenceContainer(const std::string& path) = 0;
virtual void deletePresenceContainer(const std::string& path) = 0;
+ virtual void createListInstance(const std::string& path) = 0;
+ virtual void deleteListInstance(const std::string& path) = 0;
virtual void commitChanges() = 0;
virtual void discardChanges() = 0;
diff --git a/src/grammars.hpp b/src/grammars.hpp
index abdd9ce..a2e68fc 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -35,6 +35,7 @@
x3::rule<dataPath_class, dataPath_> const dataPath = "dataPath";
x3::rule<leaf_path_class, dataPath_> const leafPath = "leafPath";
x3::rule<presenceContainerPath_class, dataPath_> const presenceContainerPath = "presenceContainerPath";
+x3::rule<listInstancePath_class, dataPath_> const listInstancePath = "listInstancePath";
x3::rule<leaf_data_class, leaf_data_> const leaf_data = "leaf_data";
x3::rule<leaf_data_enum_class, enum_> const leaf_data_enum = "leaf_data_enum";
@@ -182,6 +183,9 @@
auto const presenceContainerPath_def =
dataPath;
+auto const listInstancePath_def =
+ dataPath;
+
auto const createEnumSuggestions_def =
x3::eps;
@@ -244,10 +248,10 @@
cd_::name >> space_separator > dataPath;
auto const create_def =
- create_::name >> space_separator > presenceContainerPath;
+ create_::name >> space_separator > (presenceContainerPath | listInstancePath);
auto const delete_rule_def =
- delete_::name >> space_separator > presenceContainerPath;
+ delete_::name >> space_separator > (presenceContainerPath | listInstancePath);
auto const get_def =
get_::name >> -(space_separator >> (dataPathListEnd | dataPath));
@@ -298,6 +302,7 @@
BOOST_SPIRIT_DEFINE(leaf)
BOOST_SPIRIT_DEFINE(leafPath)
BOOST_SPIRIT_DEFINE(presenceContainerPath)
+BOOST_SPIRIT_DEFINE(listInstancePath)
BOOST_SPIRIT_DEFINE(schemaPath)
BOOST_SPIRIT_DEFINE(dataPath)
BOOST_SPIRIT_DEFINE(dataNodeList)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index aff5bcc..44177b6 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -65,7 +65,10 @@
void Interpreter::operator()(const delete_& delet) const
{
- m_datastore.deletePresenceContainer(absolutePathFromCommand(delet));
+ if (delet.m_path.m_nodes.back().m_suffix.type() == typeid(container_))
+ m_datastore.deletePresenceContainer(absolutePathFromCommand(delet));
+ else
+ m_datastore.deleteListInstance(absolutePathFromCommand(delet));
}
void Interpreter::operator()(const ls_& ls) const
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index a6388db..d514203 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -117,6 +117,16 @@
m_session->delete_item(path.c_str());
}
+void SysrepoAccess::createListInstance(const std::string& path)
+{
+ m_session->set_item(path.c_str());
+}
+
+void SysrepoAccess::deleteListInstance(const std::string& path)
+{
+ m_session->delete_item(path.c_str());
+}
+
void SysrepoAccess::commitChanges()
{
m_session->commit();
diff --git a/src/sysrepo_access.hpp b/src/sysrepo_access.hpp
index 13b4ace..76e9088 100644
--- a/src/sysrepo_access.hpp
+++ b/src/sysrepo_access.hpp
@@ -32,6 +32,8 @@
void setLeaf(const std::string& path, leaf_data_ value) override;
void createPresenceContainer(const std::string& path) override;
void deletePresenceContainer(const std::string& path) override;
+ void createListInstance(const std::string& path) override;
+ void deleteListInstance(const std::string& path) override;
std::string fetchSchema(const char* module, const char* revision, const char* submodule);
std::vector<std::string> listImplementedSchemas();
diff --git a/tests/list_manipulation.cpp b/tests/list_manipulation.cpp
new file mode 100644
index 0000000..2cc267d
--- /dev/null
+++ b/tests/list_manipulation.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+
+#include "trompeloeil_catch.h"
+#include "parser.hpp"
+#include "static_schema.hpp"
+
+TEST_CASE("list manipulation")
+{
+ auto schema = std::make_shared<StaticSchema>();
+ schema->addModule("mod");
+ schema->addList("", "mod:list", {"number"});
+ schema->addLeaf("mod:list", "mod:leafInList", yang::LeafDataTypes::String);
+ Parser parser(schema);
+ std::string input;
+ std::ostringstream errorStream;
+
+ SECTION("creating/deleting list instances")
+ {
+ dataPath_ expectedPath;
+ SECTION("mod:list[number=3]")
+ {
+ input = "mod:list[number=3]";
+ auto keys = std::map<std::string, std::string>{
+ {"number", "3"}};
+ expectedPath.m_nodes.push_back(dataNode_{module_{"mod"}, listElement_("list", keys)});
+ }
+
+ command_ parsedCreate = parser.parseCommand("create " + input, errorStream);
+ command_ parsedDelete = parser.parseCommand("delete " + input, errorStream);
+ create_ expectedCreate;
+ expectedCreate.m_path = expectedPath;
+ delete_ expectedDelete;
+ expectedDelete.m_path = expectedPath;
+ REQUIRE(parsedCreate.type() == typeid(create_));
+ REQUIRE(parsedDelete.type() == typeid(delete_));
+ REQUIRE(boost::get<create_>(parsedCreate) == expectedCreate);
+ REQUIRE(boost::get<delete_>(parsedDelete) == expectedDelete);
+ }
+}