Rework datastores

DatastoreAccess now has "targets". The target determines what datastores
are used for writing and reading data. There are three targets:
  Operational:
  - reads from operational, writes to running
  Startup:
  - reads from startup, writes to startup
  Running:
  - reads from running, writes to running

(the datastores types above correspond to the NMDA datastore types)

The need to define targets instead of just calling them "datastores" is
that the operational target doesn't actually use the operational
datastore for both writing and reading.

Change-Id: Iffb7034c27aba42d10d715e23a2c970031b9bd1b
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index 6bcb6f0..30a3e25 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -77,28 +77,56 @@
     __builtin_unreachable();
 }
 
-SysrepoAccess::SysrepoAccess(const Datastore datastore)
+SysrepoAccess::SysrepoAccess()
     : m_connection(std::make_shared<sysrepo::Connection>())
     , m_session(std::make_shared<sysrepo::Session>(m_connection))
     , m_schema(std::make_shared<YangSchema>(m_session->get_context()))
 {
     try {
-        m_session = std::make_shared<sysrepo::Session>(m_connection, toSrDatastore(datastore));
+        m_session = std::make_shared<sysrepo::Session>(m_connection);
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
     }
 }
 
+namespace {
+auto targetToDs_get(const DatastoreTarget target)
+{
+    switch (target) {
+    case DatastoreTarget::Operational:
+        return SR_DS_OPERATIONAL;
+    case DatastoreTarget::Running:
+        return SR_DS_RUNNING;
+    case DatastoreTarget::Startup:
+        return SR_DS_STARTUP;
+    }
+
+    __builtin_unreachable();
+}
+
+auto targetToDs_set(const DatastoreTarget target)
+{
+    switch (target) {
+    case DatastoreTarget::Operational:
+    case DatastoreTarget::Running:
+        // TODO: Doing candidate here doesn't work, why?
+        return SR_DS_RUNNING;
+    case DatastoreTarget::Startup:
+        return SR_DS_STARTUP;
+    }
+
+    __builtin_unreachable();
+}
+}
+
 DatastoreAccess::Tree SysrepoAccess::getItems(const std::string& path) const
 {
     using namespace std::string_literals;
     Tree res;
 
     try {
-        auto oldDs = m_session->session_get_ds();
-        m_session->session_switch_ds(SR_DS_OPERATIONAL);
+        m_session->session_switch_ds(targetToDs_get(m_target));
         auto config = m_session->get_data(((path == "/") ? "/*" : path).c_str());
-        m_session->session_switch_ds(oldDs);
         if (config) {
             lyNodesToTree(res, config->tree_for());
         }
@@ -111,6 +139,7 @@
 void SysrepoAccess::setLeaf(const std::string& path, leaf_data_ value)
 {
     try {
+        m_session->session_switch_ds(targetToDs_set(m_target));
         m_session->set_item(path.c_str(), boost::apply_visitor(valFromValue(), value));
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
@@ -120,6 +149,7 @@
 void SysrepoAccess::createItem(const std::string& path)
 {
     try {
+        m_session->session_switch_ds(targetToDs_set(m_target));
         m_session->set_item(path.c_str());
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
@@ -131,6 +161,7 @@
     try {
         // Have to use SR_EDIT_ISOLATE, because deleting something that's been set without committing is not supported
         // https://github.com/sysrepo/sysrepo/issues/1967#issuecomment-625085090
+        m_session->session_switch_ds(targetToDs_set(m_target));
         m_session->delete_item(path.c_str(), SR_EDIT_ISOLATE);
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
@@ -164,12 +195,14 @@
             destination = instanceToString(relative.m_path);
         }
     }
+    m_session->session_switch_ds(targetToDs_set(m_target));
     m_session->move_item(source.c_str(), toSrMoveOp(move), destination.c_str(), destination.c_str());
 }
 
 void SysrepoAccess::commitChanges()
 {
     try {
+        m_session->session_switch_ds(targetToDs_set(m_target));
         m_session->apply_changes(OPERATION_TIMEOUT_MS, 1);
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
@@ -179,6 +212,7 @@
 void SysrepoAccess::discardChanges()
 {
     try {
+        m_session->session_switch_ds(targetToDs_set(m_target));
         m_session->discard_changes();
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
@@ -188,16 +222,15 @@
 DatastoreAccess::Tree SysrepoAccess::execute(const std::string& path, const Tree& input)
 {
     auto inputNode = treeToRpcInput(m_session->get_context(), path, input);
+    m_session->session_switch_ds(targetToDs_set(m_target));
     auto output = m_session->rpc_send(inputNode);
     return rpcOutputToTree(path, output);
 }
 
 void SysrepoAccess::copyConfig(const Datastore source, const Datastore destination)
 {
-    auto oldDs = m_session->session_get_ds();
     m_session->session_switch_ds(toSrDatastore(destination));
     m_session->copy_config(toSrDatastore(source), nullptr, OPERATION_TIMEOUT_MS, 1);
-    m_session->session_switch_ds(oldDs);
 }
 
 std::shared_ptr<Schema> SysrepoAccess::schema()