summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/components/filedb
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/components/filedb')
-rw-r--r--sca-cpp/trunk/components/filedb/client-test.cpp26
-rw-r--r--sca-cpp/trunk/components/filedb/file-test.cpp3
-rw-r--r--sca-cpp/trunk/components/filedb/filedb.cpp35
-rw-r--r--sca-cpp/trunk/components/filedb/filedb.hpp27
4 files changed, 90 insertions, 1 deletions
diff --git a/sca-cpp/trunk/components/filedb/client-test.cpp b/sca-cpp/trunk/components/filedb/client-test.cpp
index 5694d97522..96c0212096 100644
--- a/sca-cpp/trunk/components/filedb/client-test.cpp
+++ b/sca-cpp/trunk/components/filedb/client-test.cpp
@@ -77,6 +77,32 @@ const bool testFileDB() {
assert(hasContent(val));
assert(content(val) == b);
}
+
+ const list<value> k = nilListValue + "content" + (nilListValue + "item"
+ + (nilListValue + "name" + string("Apple"))
+ + (nilListValue + "price" + string("$3.99")));
+ const list<value> c = nilListValue + (nilListValue + "entry"
+ + (nilListValue + "title" + string("item"))
+ + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+ + k);
+
+ {
+ const list<value> s = nilListValue + "content" +
+ (nilListValue + "patch" + string("(define (patch id e) (tree-subst-assoc '(price) '(price \"$3.99\") e))"));
+ const list<value> ps = nilListValue + (nilListValue + "entry"
+ + (nilListValue + "title" + string("item"))
+ + (nilListValue + "id" + string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))
+ + s);
+
+ const failable<value> r = http::patch(ps, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == trueValue);
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == c);
+ }
{
const failable<value> r = http::del(uri + p, cs);
assert(hasContent(r));
diff --git a/sca-cpp/trunk/components/filedb/file-test.cpp b/sca-cpp/trunk/components/filedb/file-test.cpp
index 5270967ccb..55272800f0 100644
--- a/sca-cpp/trunk/components/filedb/file-test.cpp
+++ b/sca-cpp/trunk/components/filedb/file-test.cpp
@@ -38,11 +38,14 @@ const bool testFileDB(const string& dbname, const string& format) {
const list<value> a = mklist<value>(nilListValue + "ns1:a" + (nilListValue + "@xmlns:ns1" + string("http://aaa")) + (nilListValue + "text" + string("Hey!")));
const list<value> b = mklist<value>(nilListValue + "ns1:b" + (nilListValue + "@xmlns:ns1" + string("http://bbb")) + (nilListValue + "text" + string("Hey!")));
+ const list<value> c = mklist<value>(nilListValue + "ns1:c" + (nilListValue + "@xmlns:ns1" + string("http://ccc")) + (nilListValue + "text" + string("Hey!")));
assert(hasContent(post(k, a, db)));
assert((get(k, db)) == value(a));
assert(hasContent(put(k, b, db)));
assert((get(k, db)) == value(b));
+ assert(hasContent(patch(k, c, db)));
+ assert((get(k, db)) == value(c));
assert(hasContent(del(k, db)));
assert(!hasContent(get(k, db)));
assert(hasContent(post(k, a, db)));
diff --git a/sca-cpp/trunk/components/filedb/filedb.cpp b/sca-cpp/trunk/components/filedb/filedb.cpp
index 37cb6c5260..b28cc9bedb 100644
--- a/sca-cpp/trunk/components/filedb/filedb.cpp
+++ b/sca-cpp/trunk/components/filedb/filedb.cpp
@@ -63,6 +63,39 @@ const failable<value> put(const list<value>& params, const filedb::FileDB& db) {
}
/**
+ * Patch an item in the database.
+ */
+const failable<value> patch(const list<value>& params, const filedb::FileDB& db) {
+ // Read patch
+ value p = assoc<value>("patch", assoc<value>("content", car<value>(cadr(params))));
+ if (isNil(p))
+ return mkfailure<value>("Couldn't read patch script");
+ const string script = cadr<value>(p);
+ debug(script, "filedb::patch::script");
+ istringstream is(script);
+
+ // Get existing value from database
+ const failable<value> ival = filedb::get(car(params), db);
+ if (!hasContent(ival) && rcode(ival) != 404)
+ return mkfailure<value>(ival);
+
+ // Apply patch
+ scheme::Env env = scheme::setupEnvironment();
+ const value pval = scheme::evalScript(cons<value>("patch", scheme::quotedParameters(mklist<value>(car(params), hasContent(ival)? content(ival) : (value)list<value>()))), is, env);
+ if (isNil(pval)) {
+ ostringstream os;
+ os << "Couldn't patch file database entry: " << car(params);
+ return mkfailure<value>(str(os), 404, false);
+ }
+
+ // Push patched value to database
+ const failable<bool> val = filedb::patch(car(params), pval, db);
+ if (!hasContent(val))
+ return mkfailure<value>(val);
+ return value(content(val));
+}
+
+/**
* Delete an item from the database.
*/
const failable<value> del(const list<value>& params, const filedb::FileDB& db) {
@@ -91,6 +124,8 @@ const failable<value> start(const list<value>& params) {
return post(cdr(params), db);
if (func == "put")
return put(cdr(params), db);
+ if (func == "patch")
+ return patch(cdr(params), db);
if (func == "delete")
return del(cdr(params), db);
return mkfailure<value>();
diff --git a/sca-cpp/trunk/components/filedb/filedb.hpp b/sca-cpp/trunk/components/filedb/filedb.hpp
index 2855cebfc6..41dde88bef 100644
--- a/sca-cpp/trunk/components/filedb/filedb.hpp
+++ b/sca-cpp/trunk/components/filedb/filedb.hpp
@@ -82,6 +82,7 @@ private:
friend const failable<value> read(istream& is, const string& format);
friend const failable<bool> post(const value& key, const value& val, const FileDB& db);
friend const failable<bool> put(const value& key, const value& val, const FileDB& db);
+ friend const failable<bool> patch(const value& key, const value& val, const FileDB& db);
friend const failable<value> get(const value& key, const FileDB& db);
friend const failable<bool> del(const value& key, const FileDB& db);
};
@@ -208,6 +209,30 @@ const failable<bool> put(const value& key, const value& val, const FileDB& db) {
}
/**
+ * Patch an item in the database. If the item doesn't exist it is added.
+ */
+const failable<bool> patch(const value& key, const value& val, const FileDB& db) {
+ debug(key, "filedb::patch::key");
+ debug(val, "filedb::patch::value");
+ debug(db.name, "filedb::patch::dbname");
+
+ if (isList(key))
+ mkdirs(key, db.name);
+ const string fn = filename(key, db.name);
+ debug(fn, "filedb::patch::filename");
+ ofstream os(fn);
+ if (os.fail()) {
+ ostringstream os;
+ os << "Couldn't patch file database entry: " << key;
+ return mkfailure<bool>(str(os));
+ }
+ const failable<bool> r = write(val, os, db.format);
+
+ debug(r, "filedb::patch::result");
+ return r;
+}
+
+/**
* Get an item from the database.
*/
const failable<value> get(const value& key, const FileDB& db) {
@@ -241,7 +266,7 @@ const failable<bool> del(const value& key, const FileDB& db) {
if (rc == -1) {
ostringstream os;
os << "Couldn't delete file database entry: " << key;
- return mkfailure<bool>(str(os));
+ return errno == ENOENT? mkfailure<bool>(str(os), 404, false) : mkfailure<bool>(str(os));
}
debug(true, "filedb::delete::result");