module util.sqlite; import slf4d; import handy_httpd.components.optional; import d2sqlite3; /** * Tries to find a single row from a database. * Params: * db = The database to use. * query = The query to execute. * resultMapper = A function to map rows to the desired result type. * args = Arguments for the query. * Returns: An optional result. */ Optional!T findOne(T, Args...)(Database db, string query, T function(Row) resultMapper, Args args) { Statement stmt = db.prepare(query); stmt.bindAll(args); ResultRange result = stmt.execute(); if (result.empty) return Optional!T.empty; return Optional!T.of(resultMapper(result.front)); } /** * Finds a list of records from a database. * Params: * db = The database to use. * query = The query to execute. * resultMapper = A function to map rows to the desired result type. * args = Arguments for the query. * Returns: A list of results. */ T[] findAll(T, Args...)(Database db, string query, T function(Row) resultMapper, Args args) { Statement stmt = db.prepare(query); stmt.bindAll(args); import std.algorithm : map; import std.array : array; return stmt.execute().map!(r => resultMapper(r)).array; } /** * Determines if at least one record exists. * Params: * db = The database to use. * query = The query to execute. * args = The arguments for the query. * Returns: True if at least one record is returned, or false if not. */ bool exists(Args...)(Database db, string query, Args args) { Statement stmt = db.prepare(query); stmt.bindAll(args); return !stmt.execute().empty(); } /** * Performs an update (UPDATE/INSERT/DELETE). * Params: * db = The database to use. * query = The query to execute. * args = The arguments for the query. * Returns: The number of rows that were affected. */ int update(Args...)(Database db, string query, Args args) { Statement stmt = db.prepare(query); stmt.bindAll(args); stmt.execute(); return db.changes(); } /** * Wraps a given delegate block of code in an SQL transaction, so that all * operations will be committed at once when done. If an exception is thrown, * then the changes will be rolled back. * Params: * db = The database to use. * dg = The delegate block of code to run in the transaction. * Returns: The return value of the delegate, if the delegate does indeed * return something. */ T doTransaction(T)(Database db, T delegate() dg) { try { db.begin(); static if (is(T : void)) { dg(); } else { T result = dg(); } db.commit(); static if (!is(T : void)) return result; } catch (Exception e) { error("Rolling back transaction due to exception.", e); db.rollback(); throw e; } }