diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fd4155..75c121f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -129,7 +129,7 @@ add_subdirectory(src/common)
add_subdirectory(src/machinery)
add_subdirectory(lib/pbl)
add_subdirectory(lib/glob2regex)
-add_subdirectory(src/backends/postgresql)
+add_subdirectory(src/backends)
#Actions
add_subdirectory(src/main)
diff --git a/include/backends/backend_loader.hpp b/include/backends/backend_loader.hpp
new file mode 100644
index 0000000..70bb592
--- /dev/null
+++ b/include/backends/backend_loader.hpp
@@ -0,0 +1,59 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#ifndef id756A258A98B24B0DB2529BCEEC5137E2
+#define id756A258A98B24B0DB2529BCEEC5137E2
+
+#include
+#include
+#include
+
+namespace YAML {
+ class Node;
+} //namespace YAML
+
+namespace dindb {
+ class Backend;
+
+ using BackendPtr = std::unique_ptr;
+
+ class BackendPlugin {
+ public:
+ BackendPlugin ( void );
+ BackendPlugin ( BackendPlugin&& ) = default;
+ BackendPlugin ( const std::string& parSOPath, const YAML::Node* parConfig );
+ ~BackendPlugin ( void ) noexcept;
+
+ const boost::string_ref& name ( void ) const;
+ Backend& backend ( void );
+ const Backend& backend ( void ) const;
+ bool is_loaded ( void ) const;
+
+ BackendPlugin& operator= ( BackendPlugin&& ) = default;
+
+ private:
+ using SoHandle = std::unique_ptr;
+
+ SoHandle m_lib;
+ BackendPtr m_backend;
+ boost::string_ref m_name;
+ };
+
+ std::string backend_name ( const std::string& parSOPath );
+} //namespace dindb
+
+#endif
diff --git a/include/backends/db_backend.hpp b/include/backends/db_backend.hpp
new file mode 100644
index 0000000..cc79b43
--- /dev/null
+++ b/include/backends/db_backend.hpp
@@ -0,0 +1,49 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#ifndef id7506CA9825454B80856154ACFE8A9DE2
+#define id7506CA9825454B80856154ACFE8A9DE2
+
+#include "backends/backend_loader.hpp"
+#include
+#include
+#include
+#include
+
+namespace dindb {
+ using GroupIDType = uint32_t;
+ using FileIDType = uint64_t;
+
+ constexpr const GroupIDType InvalidGroupID = 0;
+ constexpr const FileIDType InvalidFileID = 0;
+
+ class Backend {
+ public:
+ Backend ( void ) = default;
+ virtual ~Backend ( void ) noexcept = default;
+
+ virtual void tag_files ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const = 0;
+ virtual void tag_files ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const = 0;
+ virtual void delete_tags ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const = 0;
+ virtual void delete_tags ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const = 0;
+ virtual void delete_all_tags ( const std::vector& parFiles, GroupIDType parSet ) const = 0;
+ virtual void delete_all_tags ( const std::vector& parRegexes, GroupIDType parSet ) const = 0;
+
+ };
+} //namespace dindb
+
+#endif
diff --git a/include/backends/exposed_functions.hpp b/include/backends/exposed_functions.hpp
new file mode 100644
index 0000000..a1b21e9
--- /dev/null
+++ b/include/backends/exposed_functions.hpp
@@ -0,0 +1,33 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#ifndef idA9E47E37E2FA49EE84C2E93FB701C368
+#define idA9E47E37E2FA49EE84C2E93FB701C368
+
+namespace YAML {
+ class Node;
+} //namespace YAML
+
+namespace dindb {
+ class Backend;
+} //namespace dindb
+
+extern "C" dindb::Backend* dindexer_create_backend ( const YAML::Node* parConfig );
+extern "C" void dindexer_destroy_backend ( dindb::Backend* parDele );
+extern "C" const char* dindexer_backend_name ( void );
+
+#endif
diff --git a/src/backends/CMakeLists.txt b/src/backends/CMakeLists.txt
new file mode 100644
index 0000000..eae379f
--- /dev/null
+++ b/src/backends/CMakeLists.txt
@@ -0,0 +1,28 @@
+project(${bare_name}-backend CXX)
+
+add_library(${PROJECT_NAME} STATIC
+ backend_loader.cpp
+)
+
+target_include_directories(${PROJECT_NAME}
+ PUBLIC ${DINDEXER_PUB_INCLUDE_DIR}
+)
+target_include_directories(${PROJECT_NAME} SYSTEM
+ PUBLIC ${YAMLCPP_INCLUDE_DIR}
+)
+
+target_link_libraries(${PROJECT_NAME}
+ PRIVATE ${bare_name}-if
+ PUBLIC ${YAMLCPP_LIBRARY}
+ PUBLIC dl
+)
+
+#install(TARGETS ${PROJECT_NAME}
+# LIBRARY DESTINATION lib
+# RUNTIME DESTINATION bin
+# ARCHIVE DESTINATION lib/static
+#)
+
+add_subdirectory(postgresql)
+
+add_dependencies(${PROJECT_NAME} ${bare_name}-backend-postgresql)
diff --git a/src/backends/backend_loader.cpp b/src/backends/backend_loader.cpp
new file mode 100644
index 0000000..a6eba27
--- /dev/null
+++ b/src/backends/backend_loader.cpp
@@ -0,0 +1,107 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+//See:
+// http://stackoverflow.com/questions/496664/c-dynamic-shared-library-on-linux
+
+#include "backends/backend_loader.hpp"
+#include "backends/exposed_functions.hpp"
+#include
+#include
+#include
+
+namespace dindb {
+ namespace {
+ BackendPtr load_backend (void* parSOHandle, const YAML::Node* parConfig) {
+ typedef decltype(&dindexer_create_backend) CreateBackendFun;
+ typedef decltype(&dindexer_destroy_backend) DeleteBackendFun;
+
+ assert(parSOHandle);
+ assert(parConfig);
+
+ auto create = reinterpret_cast(dlsym(parSOHandle, "dindexer_create_backend"));
+ auto destroy = reinterpret_cast(dlsym(parSOHandle, "dindexer_destroy_backend"));
+
+ return BackendPtr(create(parConfig), destroy);
+ }
+
+ const char* backend_name (void* parSOHandle) {
+ typedef decltype(&dindexer_backend_name) GetNameFun;
+
+ assert(parSOHandle);
+
+ auto get_name = reinterpret_cast(dlsym(parSOHandle, "dindexer_backend_name"));
+ return get_name();
+ }
+
+ void nop_destroy (Backend*) {
+ }
+ } //unnamed namespace
+
+ std::string backend_name (const std::string& parSOPath) {
+ assert(not parSOPath.empty());
+ using SoHandle = std::unique_ptr;
+
+ auto handle = SoHandle(dlopen(parSOPath.c_str(), RTLD_LAZY), &dlclose);
+ return backend_name(handle.get());
+ }
+
+ BackendPlugin::BackendPlugin() :
+ m_lib(nullptr, &dlclose),
+ m_backend(nullptr, &nop_destroy),
+ m_name()
+ {
+ }
+
+ BackendPlugin::BackendPlugin (const std::string& parSOPath, const YAML::Node* parConfig) :
+ m_lib(dlopen(parSOPath.c_str(), RTLD_LAZY), &dlclose),
+ m_backend(load_backend(m_lib.get(), parConfig)),
+ m_name(backend_name(m_lib.get()))
+ {
+ }
+
+ BackendPlugin::~BackendPlugin() noexcept {
+ }
+
+ const boost::string_ref& BackendPlugin::name() const {
+ return m_name;
+ }
+
+ Backend& BackendPlugin::backend() {
+ assert(m_lib);
+ assert(m_backend);
+ if (not m_backend) {
+ throw std::bad_function_call();
+ }
+
+ return *m_backend;
+ }
+
+ const Backend& BackendPlugin::backend() const {
+ assert(m_lib);
+ assert(m_backend);
+ if (not m_backend) {
+ throw std::bad_function_call();
+ }
+
+ return *m_backend;
+ }
+
+ bool BackendPlugin::is_loaded() const {
+ return static_cast(m_backend);
+ }
+} //namespace dindb
diff --git a/src/backends/postgresql/CMakeLists.txt b/src/backends/postgresql/CMakeLists.txt
index 8238350..40eb8e3 100644
--- a/src/backends/postgresql/CMakeLists.txt
+++ b/src/backends/postgresql/CMakeLists.txt
@@ -6,6 +6,7 @@ add_library(${PROJECT_NAME} STATIC
locate.cpp
scan.cpp
dbsource.cpp
+ backend_postgresql.cpp
)
target_include_directories(${PROJECT_NAME}
diff --git a/src/backends/postgresql/backend_postgresql.cpp b/src/backends/postgresql/backend_postgresql.cpp
new file mode 100644
index 0000000..7ccf8cc
--- /dev/null
+++ b/src/backends/postgresql/backend_postgresql.cpp
@@ -0,0 +1,102 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#include "backend_postgresql.hpp"
+#include "backends/exposed_functions.hpp"
+#include "pq/connection.hpp"
+#include
+#include
+#include
+#include
+
+namespace YAML {
+ template<>
+ struct convert {
+ static Node encode (const dindb::Settings& parSettings) {
+ Node node;
+ node["address"] = parSettings.address;
+ node["username"] = parSettings.username;
+ node["password"] = parSettings.password;
+ node["port"] = parSettings.port;
+ node["dbname"] = parSettings.dbname;
+ return node;
+ }
+
+ static bool decode (const Node& parNode, dindb::Settings& parSettings) {
+ if (not parNode.IsMap() or parNode.size() != 5) {
+ return false;
+ }
+
+ parSettings.address = parNode["address"].as();
+ parSettings.username = parNode["username"].as();
+ parSettings.password = parNode["password"].as();
+ parSettings.dbname = parNode["dbname"].as();
+ parSettings.port = parNode["port"].as();
+ return true;
+ }
+ };
+} //namespace YAML
+
+namespace dindb {
+ BackendPostgreSql::BackendPostgreSql (std::string&& parUser, std::string&& parPass, std::string&& parDB, std::string&& parAddr, uint16_t parPort) :
+ m_conn(new pq::Connection(std::move(parUser), std::move(parPass), std::move(parDB), std::move(parAddr), parPort))
+ {
+ assert(m_conn);
+ m_conn->connect();
+ }
+
+ BackendPostgreSql::~BackendPostgreSql() noexcept {
+ m_conn->disconnect();
+ }
+
+ void BackendPostgreSql::tag_files (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) const {
+ if (InvalidGroupID != parSet) {
+ const std::string query =
+ "UPDATE \"files\" SET \"tags\" = ARRAY(SELECT DISTINCT UNNEST(\"tags\" || $1) ORDER BY 1) WHERE \"id\"=ANY($2) AND \"group_id\"=$3;";
+ m_conn->query(query, parTags, parFiles, parSet);
+ }
+ else {
+ const std::string query =
+ "UPDATE \"files\" SET \"tags\" = ARRAY(SELECT DISTINCT UNNEST(\"tags\" || $1) ORDER BY 1) WHERE \"id\"=ANY($2);";
+ m_conn->query(query, parTags, parFiles);
+ }
+ }
+
+ void BackendPostgreSql::tag_files (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) const {
+ }
+
+ void BackendPostgreSql::delete_tags (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) const {
+ }
+
+ void BackendPostgreSql::delete_tags (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) const {
+ }
+
+ void BackendPostgreSql::delete_all_tags (const std::vector& parFiles, GroupIDType parSet) const {
+ }
+
+ void BackendPostgreSql::delete_all_tags (const std::vector& parRegexes, GroupIDType parSet) const {
+ }
+} //namespace dindb
+
+extern "C" dindb::Backend* create_backend (const YAML::Node*) {
+ return new dindb::BackendPostgreSql("A", "B", "C", "D", 1);
+}
+
+extern "C" void destroy_backend (dindb::Backend* parDele) {
+ if (parDele)
+ delete parDele;
+}
diff --git a/src/backends/postgresql/backend_postgresql.hpp b/src/backends/postgresql/backend_postgresql.hpp
new file mode 100644
index 0000000..bce0e7c
--- /dev/null
+++ b/src/backends/postgresql/backend_postgresql.hpp
@@ -0,0 +1,49 @@
+/* Copyright 2015, 2016, Michele Santullo
+ * This file is part of "dindexer".
+ *
+ * "dindexer" is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * "dindexer" is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with "dindexer". If not, see .
+ */
+
+#ifndef idBE5BBAFEC7334F39AC9338F193703341
+#define idBE5BBAFEC7334F39AC9338F193703341
+
+#include "backends/db_backend.hpp"
+#include
+#include
+#include
+
+namespace pq {
+ class Connection;
+} //namespace pq
+
+namespace dindb {
+ class BackendPostgreSql : public Backend {
+ public:
+ BackendPostgreSql ( BackendPostgreSql&& ) = default;
+ BackendPostgreSql ( std::string&& parUser, std::string&& parPass, std::string&& parDB, std::string&& parAddr, uint16_t parPort );
+ virtual ~BackendPostgreSql ( void ) noexcept;
+
+ virtual void tag_files ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const override;
+ virtual void tag_files ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const override;
+ virtual void delete_tags ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const override;
+ virtual void delete_tags ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const override;
+ virtual void delete_all_tags ( const std::vector& parFiles, GroupIDType parSet ) const override;
+ virtual void delete_all_tags ( const std::vector& parRegexes, GroupIDType parSet ) const override;
+
+ private:
+ std::unique_ptr m_conn;
+ };
+} //namespace dindb
+
+#endif
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e41e3b5..724d45f 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -19,8 +19,6 @@ target_include_directories(${PROJECT_NAME} SYSTEM
PRIVATE ${Readline_INCLUDE_DIR}
)
-string(TOLOWER "${DINDEXER_DB_BACKEND}" DINDEXER_DB_BACKEND_LOWERCASE)
-
target_link_libraries(${PROJECT_NAME}
PRIVATE ${bare_name}-if
PRIVATE ${YAMLCPP_LIBRARY}
diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt
index 1b16abb..8f0f1d8 100644
--- a/src/main/CMakeLists.txt
+++ b/src/main/CMakeLists.txt
@@ -12,7 +12,6 @@ add_executable(${PROJECT_NAME}
make_timestamp(${bare_name} timestamp.h.in)
target_include_directories(${PROJECT_NAME}
- PRIVATE ${CMAKE_SOURCE_DIR}/include
PRIVATE ${CMAKE_SOURCE_DIR}/lib/pbl/pbl/src/src
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)