Skip to content

Commit

Permalink
Maps between vectors and SQL records
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rokopt committed Jun 29, 2020
1 parent 0af8465 commit 244cd18
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/database/Database.h
Expand Up @@ -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 <typename T>
void
selectMap(Database& db, std::string const& selectStr,
std::function<T(soci::row const&)> makeT, std::vector<T>& out)
{
soci::rowset<soci::row> 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 <typename T>
void updateMap(Database& db, std::vector<T> const& in,
std::string const& updateStr,
std::function<void(soci::statement&, T const&)> prepUpdate,
std::function<void(long long const, T const&)> postUpdate);
template <typename T>
void
updateMap(Database& db, std::vector<T> const& in, std::string const& updateStr,
std::function<void(soci::statement&, T const&)> prepUpdate,
std::function<void(long long const, T const&)> 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 <typename T>
size_t
selectUpdateMap(Database& db, std::string const& selectStr,
std::function<T(soci::row const&)> makeT,
std::string const& updateStr,
std::function<void(soci::statement&, T const&)> prepUpdate,
std::function<void(long long const, T const&)> postUpdate)
{
std::vector<T> vecT;

selectMap<T>(db, selectStr, makeT, vecT);
updateMap<T>(db, vecT, updateStr, prepUpdate, postUpdate);

return vecT.size();
}

template <typename T>
void
decodeOpaqueXDR(std::string const& in, T& out)
Expand Down

0 comments on commit 244cd18

Please sign in to comment.