A modern C++17 PostgreSQL ORM library featuring RAII resource management, compile-time type safety, and zero-cost abstractions.
한국어 | Documentation | 한국어 문서
- RAII-First Design - All resources (connections, results, transactions) are automatically managed
- Type Safety - Compile-time type checking with
std::optionalfor NULL handling - Zero-Cost Abstractions - Minimal overhead compared to raw libpq usage
- JPA-Like API - Declarative entity mapping with macros and Repository pattern
- Connection Pooling - Thread-safe connection pool for high-performance applications
- Modern C++ - Uses C++17 features like
std::optional,std::string_view, structured bindings
| Requirement | Version |
|---|---|
| C++ Standard | C++17 |
| Compiler | GCC 8+, Clang 7+, MSVC 2019+ |
| PostgreSQL libpq | 15.x+ |
| CMake | 3.16+ |
| Google Test | (optional, for tests) |
Using CMake FetchContent:
include(FetchContent)
FetchContent_Declare(
posixlibpq
GIT_REPOSITORY https://github.com/your-repo/posixLibPq.git
GIT_TAG main
)
set(PQ_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(PQ_BUILD_TESTS OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(posixlibpq)
target_link_libraries(your_app PRIVATE pq::pq)Using as subdirectory:
add_subdirectory(external/posixLibPq)
target_link_libraries(your_app PRIVATE pq::pq)#include <pq/pq.hpp>
struct User {
int id{0};
std::string name;
std::optional<std::string> email; // Nullable
PQ_ENTITY(User, "users")
PQ_COLUMN(id, "id", PQ_PRIMARY_KEY | PQ_AUTO_INCREMENT)
PQ_COLUMN(name, "name", PQ_NOT_NULL)
PQ_COLUMN(email, "email")
PQ_ENTITY_END()
};
PQ_REGISTER_ENTITY(User)// Connect
pq::Connection conn("host=localhost dbname=mydb user=postgres");
// Create repository
pq::Repository<User, int> userRepo(conn);
// Create
User user;
user.name = "John";
user.email = "john@example.com";
auto saved = userRepo.save(user);
if (saved) {
std::cout << "Saved with ID: " << saved->id << std::endl;
}
// Read
auto found = userRepo.findById(1);
if (found && *found) {
std::cout << "Found: " << (*found)->name << std::endl;
}
// Update
if (saved) {
saved->name = "Jane";
userRepo.update(*saved);
}
// Delete
userRepo.removeById(1);{
pq::Transaction tx(conn);
if (!tx) {
// Handle error
return;
}
userRepo.save(user1);
userRepo.save(user2);
tx.commit(); // Explicit commit
} // Auto-rollback if commit() not calledpq::PoolConfig config;
config.connectionString = "host=localhost dbname=mydb";
config.minSize = 2;
config.maxSize = 10;
pq::ConnectionPool pool(config);
{
auto conn = pool.acquire();
if (conn) {
conn->execute("SELECT * FROM users");
}
} // Connection returned to pool# Clone
git clone https://github.com/your-repo/posixLibPq.git
cd posixLibPq
# Build
mkdir build && cd build
cmake ..
cmake --build .
# Run tests
ctest --output-on-failure
# Or build with auto-test execution
cmake .. -DPQ_RUN_TESTS=ON
cmake --build .| Option | Default | Description |
|---|---|---|
PQ_BUILD_EXAMPLES |
ON | Build example programs |
PQ_BUILD_TESTS |
ON | Build unit tests |
PQ_RUN_TESTS |
OFF | Run tests after build |
PQ_INSTALL |
ON | Generate install target for cmake --install |
PQ_LIBPQ_INCLUDE_DIR |
(auto) | Manual path to libpq-fe.h directory |
PQ_LIBPQ_LIBRARY |
(auto) | Manual path to libpq library |
If CMake cannot find libpq automatically:
cmake .. \
-DPQ_LIBPQ_INCLUDE_DIR=/path/to/include \
-DPQ_LIBPQ_LIBRARY=/path/to/libpq.socmake .. \
-DPQ_LIBPQ_INCLUDE_DIR=/opt/homebrew/opt/libpq/include \
-DPQ_LIBPQ_LIBRARY=/opt/homebrew/opt/libpq/lib/libpq.dylibposixLibPq/
├── include/pq/
│ ├── core/ # Core components
│ │ ├── PqHandle.hpp # RAII wrappers
│ │ ├── Result.hpp # Result<T,E> error handling
│ │ ├── Types.hpp # Type traits system
│ │ ├── Connection.hpp # Database connection
│ │ ├── QueryResult.hpp # Query results
│ │ ├── Transaction.hpp # Transaction management
│ │ └── ConnectionPool.hpp# Connection pooling
│ ├── orm/ # ORM layer
│ │ ├── Entity.hpp # Entity macros
│ │ ├── Mapper.hpp # Result-Entity mapping
│ │ └── Repository.hpp # Repository pattern
│ └── pq.hpp # Convenience header
├── src/core/ # Implementation files
├── cmake/ # CMake package config
│ └── pqConfig.cmake.in # find_package(pq) support template
├── docs/ # Documentation
│ └── ko/ # Korean documentation
├── examples/ # Example programs
├── tests/ # Unit tests
└── CMakeLists.txt
The cmake/pqConfig.cmake.in file is a template for CMake package configuration. When you run cmake --install, it generates pqConfig.cmake that allows other projects to use this library via:
find_package(pq REQUIRED)
target_link_libraries(your_app PRIVATE pq::pq)- Getting Started
- Entity Mapping
- Repository Pattern
- Transactions
- Connection Pool
- Error Handling
- Custom Queries
- API Reference
- Type System
All libpq resources are managed with RAII:
{
pq::Connection conn("..."); // PQconnectdb
// Use connection...
} // Automatic PQfinish
{
pq::Transaction tx(conn); // BEGIN
// Operations...
} // Automatic ROLLBACK if not committedOperations return DbResult<T> instead of throwing exceptions:
auto result = userRepo.findById(1);
if (result) {
// Success
auto& user = *result;
} else {
// Error
std::cerr << result.error().message << std::endl;
}Use std::optional for nullable columns:
struct User {
int id; // NOT NULL
std::optional<std::string> bio; // NULL allowed
};
// NULL column mapped to non-optional throws MappingExceptionContributions are welcome! Please feel free to submit issues and pull requests.
MIT License - see LICENSE file for details.