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/constdb/client-test.cpp | 26 ++++++++++++++ sca-cpp/trunk/components/constdb/constdb.cpp | 35 ++++++++++++++++++ sca-cpp/trunk/components/constdb/tinycdb-test.cpp | 2 ++ sca-cpp/trunk/components/constdb/tinycdb.hpp | 43 +++++++++++++++++++++-- 4 files changed, 104 insertions(+), 2 deletions(-) (limited to 'sca-cpp/trunk/components/constdb') diff --git a/sca-cpp/trunk/components/constdb/client-test.cpp b/sca-cpp/trunk/components/constdb/client-test.cpp index b796ef01dd..165e3d8836 100644 --- a/sca-cpp/trunk/components/constdb/client-test.cpp +++ b/sca-cpp/trunk/components/constdb/client-test.cpp @@ -77,6 +77,32 @@ const bool testConstDb() { assert(hasContent(val)); assert(content(val) == b); } + + const list k = nilListValue + "content" + (nilListValue + "item" + + (nilListValue + "name" + string("Apple")) + + (nilListValue + "price" + string("$3.99"))); + const list c = nilListValue + (nilListValue + "entry" + + (nilListValue + "title" + string("item")) + + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + k); + + { + const list s = nilListValue + "content" + + (nilListValue + "patch" + string("(define (patch id e) (tree-subst-assoc '(price) '(price \"$3.99\") e))")); + const list ps = nilListValue + (nilListValue + "entry" + + (nilListValue + "title" + string("item")) + + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")) + + s); + + const failable r = http::patch(ps, uri + p, cs); + assert(hasContent(r)); + assert(content(r) == trueValue); + } + { + const failable val = http::get(uri + p, cs); + assert(hasContent(val)); + assert(content(val) == c); + } { const failable r = http::del(uri + p, cs); assert(hasContent(r)); diff --git a/sca-cpp/trunk/components/constdb/constdb.cpp b/sca-cpp/trunk/components/constdb/constdb.cpp index a9a5bc5817..2d34ed2b73 100644 --- a/sca-cpp/trunk/components/constdb/constdb.cpp +++ b/sca-cpp/trunk/components/constdb/constdb.cpp @@ -62,6 +62,39 @@ const failable put(const list& params, const tinycdb::TinyCDB& cdb return value(content(val)); } +/** + * Patch an item in the database. + */ +const failable patch(const list& params, const tinycdb::TinyCDB& cdb) { + // 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, "tinycdb::patch::script"); + istringstream is(script); + + // Get existing value from database + const failable ival = tinycdb::get(car(params), cdb); + if (!hasContent(ival) && rcode(ival) != 404) + return mkfailure(ival); + + // Apply patch + scheme::Env env = scheme::setupEnvironment(); + const value pval = scheme::evalScript(cons("patch", scheme::quotedParameters(mklist(car(params), hasContent(ival)? content(ival) : (value)list()))), is, env); + if (isNil(pval)) { + ostringstream os; + os << "Couldn't patch tinycdb entry: " << car(params); + return mkfailure(str(os), 404, false); + } + + // Push patched value to database + const failable val = tinycdb::patch(car(params), pval, cdb); + if (!hasContent(val)) + return mkfailure(val); + return value(content(val)); +} + /** * Delete an item from the database. */ @@ -89,6 +122,8 @@ const failable start(unused const list& params) { return post(cdr(params), cdb); if (func == "put") return put(cdr(params), cdb); + if (func == "patch") + return patch(cdr(params), cdb); if (func == "delete") return del(cdr(params), cdb); return mkfailure(); diff --git a/sca-cpp/trunk/components/constdb/tinycdb-test.cpp b/sca-cpp/trunk/components/constdb/tinycdb-test.cpp index 6cc9e9eabb..41bfe12772 100644 --- a/sca-cpp/trunk/components/constdb/tinycdb-test.cpp +++ b/sca-cpp/trunk/components/constdb/tinycdb-test.cpp @@ -40,6 +40,8 @@ const bool testTinyCDB() { assert((get(k, cdb)) == value(string("AAA"))); assert(hasContent(put(k, string("aaa"), cdb))); assert((get(k, cdb)) == value(string("aaa"))); + assert(hasContent(patch(k, string("bbb"), cdb))); + assert((get(k, cdb)) == value(string("bbb"))); assert(hasContent(del(k, cdb))); assert(!hasContent(get(k, cdb))); diff --git a/sca-cpp/trunk/components/constdb/tinycdb.hpp b/sca-cpp/trunk/components/constdb/tinycdb.hpp index ce1dcbb011..3da5f3c216 100644 --- a/sca-cpp/trunk/components/constdb/tinycdb.hpp +++ b/sca-cpp/trunk/components/constdb/tinycdb.hpp @@ -388,6 +388,37 @@ const failable put(const value& key, const value& val, const TinyCDB& cdb) return r; } +/** + * Patch an item in the database. If the item doesn't exist it is added. + */ +const failable patch(const value& key, const value& val, const TinyCDB& cdb) { + debug(key, "tinycdb::patch::key"); + debug(val, "tinycdb::patch::value"); + debug(dbname(cdb), "tinycdb::patch::dbname"); + + const string ks(write(content(scheme::writeValue(key)))); + const string vs(write(content(scheme::writeValue(val)))); + + // Process each entry and skip existing key + const lambda(buffer&, const unsigned int, const unsigned int)> update = [ks](buffer& buf, const unsigned int klen, unused const unsigned int vlen) -> const failable { + if (ks == string((char*)buf, klen)) + return false; + return true; + }; + + // Add the new entry to the db + const lambda(struct cdb_make&)> finish = [ks, vs](struct cdb_make& cdbm) -> const failable { + if (cdb_make_add(&cdbm, c_str(ks), (unsigned int)length(ks), c_str(vs), (unsigned int)length(vs)) == -1) + return mkfailure(string("Couldn't add tinycdb entry: ") + ks); + return true; + }; + + // Rewrite the db + const failable r = rewrite(update, finish, cdb); + debug(r, "tinycdb::patch::result"); + return r; +} + /** * Get an item from the database. */ @@ -425,11 +456,14 @@ const failable del(const value& key, const TinyCDB& cdb) { debug(dbname(cdb), "tinycdb::delete::dbname"); const string ks(write(content(scheme::writeValue(key)))); + bool found = false; // Process each entry and skip existing key - const lambda(buffer&, const unsigned int, const unsigned int)> update = [ks](buffer& buf, const unsigned int klen, unused const unsigned int vlen) -> const failable { - if (ks == string((char*)buf, klen)) + const lambda(buffer&, const unsigned int, const unsigned int)> update = [ks, &found](buffer& buf, const unsigned int klen, unused const unsigned int vlen) -> const failable { + if (ks == string((char*)buf, klen)) { + found = true; return false; + } return true; }; @@ -440,6 +474,11 @@ const failable del(const value& key, const TinyCDB& cdb) { // Rewrite the db const failable r = rewrite(update, finish, cdb); + if (!hasContent(r) || !found) { + ostringstream os; + os << "Couldn't delete tinycdb entry: " << key; + return hasContent(r)? mkfailure(str(os), 404, false) : r; + } debug(r, "tinycdb::delete::result"); return r; } -- cgit v1.2.3