From 9e1b9e73145e00ea591bd1e0e9777625bad66dc9 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Thu, 3 Jan 2013 07:41:14 +0000 Subject: Add support for HTTP patch and application of patch scripts to server and data store components. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1428192 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/components/sqldb/sqldb.cpp | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'sca-cpp/trunk/components/sqldb/sqldb.cpp') diff --git a/sca-cpp/trunk/components/sqldb/sqldb.cpp b/sca-cpp/trunk/components/sqldb/sqldb.cpp index 1288dd553b..75be2c0624 100644 --- a/sca-cpp/trunk/components/sqldb/sqldb.cpp +++ b/sca-cpp/trunk/components/sqldb/sqldb.cpp @@ -63,6 +63,65 @@ const failable put(const list& params, const pgsql::PGSql& pg) { return value(content(val)); } +/** + * Patch an item in the database. + */ +const failable patch(const list& params, const pgsql::PGSql& pg) { + // Read patch + value p = assoc("patch", assoc("content", car(cadr(params)))); + if (isNil(p)) + return mkfailure("Couldn't read patch script"); + const string script = cadr(p); + debug(script, "pgsql::patch::script"); + + const lambda(const value&, const pgsql::PGSql&, const string&, const int)> tryPatch = [&tryPatch](const value& key, const pgsql::PGSql& pg, const string& script, const int count) -> const failable { + + // Begin database transaction + const failable brc = pgsql::begin(pg); + if (!hasContent(brc)) + return mkfailure(brc); + + // Get existing value from database + const failable ival = pgsql::get(key, pg); + if (!hasContent(ival) && rcode(ival) != 404) { + pgsql::rollback(pg); + return mkfailure(ival); + } + + // Apply patch + istringstream is(script); + scheme::Env env = scheme::setupEnvironment(); + const value pval = scheme::evalScript(cons("patch", scheme::quotedParameters(mklist(key, hasContent(ival)? content(ival) : (value)list()))), is, env); + if (isNil(pval)) { + ostringstream os; + os << "Couldn't patch postgresql entry: " << key; + return mkfailure(str(os), 404, false); + } + + // Push patched value to database + const failable val = pgsql::patch(key, pval, pg); + if (!hasContent(val)) { + pgsql::rollback(pg); + + // Retry on a transaction serialization error + if (rcode(val) == 409 && count > 0) + return tryPatch(key, pg, script, count - 1); + return mkfailure(val); + } + + // Commit database transaction + const failable crc = pgsql::commit(pg); + if (!hasContent(crc)) + return mkfailure(crc); + + return value(content(val)); + }; + + // Try patching the entry and automatically retry a few times on transaction + // serialization errors + return tryPatch(car(params), pg, script, 5); +} + /** * Delete an item from the database. */ @@ -98,6 +157,8 @@ const failable start(const list& params) { return post(cdr(params), *pg); if (func == "put") return put(cdr(params), *pg); + if (func == "patch") + return patch(cdr(params), *pg); if (func == "delete") return del(cdr(params), *pg); return mkfailure(); -- cgit v1.2.3