From 244cd1840964f7f9f90c93c14513069e08801306 Mon Sep 17 00:00:00 2001 From: Terence Rokop Date: Mon, 29 Jun 2020 09:33:42 -0700 Subject: [PATCH] Maps between vectors and SQL records Introduce three generic functions for operating on database records in bulk: - selectMap() takes a function which maps a SQL record to an element of a client-defined (templated) type, and produces a function which takes a SQL SELECT statement and produces a vector of the client-defined type comprising the list of selected records mapped through the client-defined function. - updateMap() takes a function which maps an element of a client-defined (templated) type to a SQL UPDATE statement, and produces a function which generates a series of SQL UPDATE statements from a vector of the client-defined type. - selectUpdateMap() produces the composition of updateMap() following selectMap(), namely, a function which takes a SQL SELECT statement and produces for each selected record an UPDATE statement derived from a transformation applied to the record via client-defined functions which interpret the record as an element of a client-defined type and then use that interpretation to choose some update to perform on it. --- src/database/Database.h | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/database/Database.h b/src/database/Database.h index 4634545ca1..0d7f2cef47 100644 --- a/src/database/Database.h +++ b/src/database/Database.h @@ -248,6 +248,72 @@ class DBTimeExcluder : NonCopyable ~DBTimeExcluder(); }; +// Select a set of records using a client-defined query string, then map +// each record into an element of a client-defined datatype by applying a +// client-defined function (the records are accumulated in the "out" +// vector). +template +void +selectMap(Database& db, std::string const& selectStr, + std::function makeT, std::vector& out) +{ + soci::rowset rs = (db.getSession().prepare << selectStr); + + std::transform(rs.begin(), rs.end(), std::back_inserter(out), makeT); +} + +// Map each element in the given vector of a client-defined datatype into a +// SQL update command by applying a client-defined function, then send those +// update strings to the database. +// +// The "postUpdate" function receives the number of records affected +// by the given update, as well as the element of the client-defined +// datatype which generated that update. +template +void updateMap(Database& db, std::vector const& in, + std::string const& updateStr, + std::function prepUpdate, + std::function postUpdate); +template +void +updateMap(Database& db, std::vector const& in, std::string const& updateStr, + std::function prepUpdate, + std::function postUpdate) +{ + auto st_update = db.getPreparedStatement(updateStr).statement(); + + for (auto& recT : in) + { + prepUpdate(st_update, recT); + st_update.define_and_bind(); + st_update.execute(true); + auto affected_rows = st_update.get_affected_rows(); + st_update.clean_up(false); + postUpdate(affected_rows, recT); + } +} + +// The composition of updateMap() following selectMap(). +// +// Returns the number of records selected by selectMap() (all of which were +// then passed through updateMap() before the selectUpdateMap() call +// returned). +template +size_t +selectUpdateMap(Database& db, std::string const& selectStr, + std::function makeT, + std::string const& updateStr, + std::function prepUpdate, + std::function postUpdate) +{ + std::vector vecT; + + selectMap(db, selectStr, makeT, vecT); + updateMap(db, vecT, updateStr, prepUpdate, postUpdate); + + return vecT.size(); +} + template void decodeOpaqueXDR(std::string const& in, T& out)