diff options
Diffstat (limited to 'sca-cpp/trunk/components/sqldb')
-rw-r--r-- | sca-cpp/trunk/components/sqldb/Makefile.am | 18 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/client-test.cpp | 130 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql | 25 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-start | 37 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/pgsql-stop | 28 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql-test.cpp | 82 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/pgsql.hpp | 184 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/server-test | 43 | ||||
-rwxr-xr-x | sca-cpp/trunk/components/sqldb/sqldb-test | 31 | ||||
-rw-r--r-- | sca-cpp/trunk/components/sqldb/sqldb.cpp | 133 |
10 files changed, 701 insertions, 10 deletions
diff --git a/sca-cpp/trunk/components/sqldb/Makefile.am b/sca-cpp/trunk/components/sqldb/Makefile.am index 0bea7b5eb1..b7c8a4eeaf 100644 --- a/sca-cpp/trunk/components/sqldb/Makefile.am +++ b/sca-cpp/trunk/components/sqldb/Makefile.am @@ -26,18 +26,18 @@ comp_DATA = pgsql.prefix pgsql.prefix: $(top_builddir)/config.status echo ${PGSQL_PREFIX} >pgsql.prefix -#comp_LTLIBRARIES = libsqldb.la libqueue-listener.la +comp_LTLIBRARIES = libsqldb.la -#libsqldb_la_SOURCES = sqldb.cpp -#libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpgsql +libsqldb_la_SOURCES = sqldb.cpp +libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq -#pgsql_test_SOURCES = pgsql-test.cpp -#pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpgsql +pgsql_test_SOURCES = pgsql-test.cpp +pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq -#client_test_SOURCES = client-test.cpp -#client_test_LDFLAGS = -lxml2 -lcurl -lmozjs +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -#noinst_PROGRAMS = pgsql-test client-test -#TESTS = sql-test server-test +noinst_PROGRAMS = pgsql-test client-test +TESTS = sqldb-test server-test endif diff --git a/sca-cpp/trunk/components/sqldb/client-test.cpp b/sca-cpp/trunk/components/sqldb/client-test.cpp new file mode 100644 index 0000000000..271ec08bed --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/client-test.cpp @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Test SQLDB component. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" + +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "perf.hpp" +#include "../../modules/http/curl.hpp" + +namespace tuscany { +namespace sqldb { + +const string uri("http://localhost:8090/sqldb"); + +bool testSqlDb() { + http::CURLSession cs; + + const list<value> i = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99")); + const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + + const failable<value> id = http::post(a, uri, cs); + assert(hasContent(id)); + + const string p = path(content(id)); + { + const failable<value> val = http::get(uri + p, cs); + assert(hasContent(val)); + assert(content(val) == a); + } + + const list<value> j = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$3.55")); + const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j); + + { + const failable<value> r = http::put(b, uri + p, cs); + assert(hasContent(r)); + assert(content(r) == value(true)); + } + { + const failable<value> val = http::get(uri + p, cs); + assert(hasContent(val)); + assert(content(val) == b); + } + { + const failable<value> r = http::del(uri + p, cs); + assert(hasContent(r)); + assert(content(r) == value(true)); + } + { + const failable<value> val = http::get(uri + p, cs); + assert(!hasContent(val)); + } + + return true; +} + +struct getLoop { + const string path; + const value entry; + http::CURLSession cs; + getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) { + } + const bool operator()() const { + const failable<value> val = http::get(uri + path, cs); + assert(hasContent(val)); + assert(content(val) == entry); + return true; + } +}; + +bool testGetPerf() { + const list<value> i = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$4.55")); + const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + + http::CURLSession cs; + const failable<value> id = http::post(a, uri, cs); + assert(hasContent(id)); + const string p = path(content(id)); + + const lambda<bool()> gl = getLoop(p, a, cs); + cout << "Sqldb get test " << time(gl, 5, 200) << " ms" << endl; + + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::sqldb::testSqlDb(); + tuscany::sqldb::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/trunk/components/sqldb/pgsql b/sca-cpp/trunk/components/sqldb/pgsql new file mode 100755 index 0000000000..3cd1904e32 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql @@ -0,0 +1,25 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Run SQL command +here=`readlink -f $0`; here=`dirname $here` +pgsql_prefix=`cat $here/pgsql.prefix` + +$pgsql_prefix/bin/psql -c "$1" db + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-start b/sca-cpp/trunk/components/sqldb/pgsql-start new file mode 100755 index 0000000000..b87313073d --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-start @@ -0,0 +1,37 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Start postgresql +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +pgsql_prefix=`cat $here/pgsql.prefix` +mkdir -p $root/sqldb +mkdir -p $root/logs +if [ ! -f $root/sqldb/postgresql.conf ]; then + $pgsql_prefix/bin/pg_ctl init -D $root/sqldb + createdb="true" +fi + +$pgsql_prefix/bin/pg_ctl start -D $root/sqldb -l $root/logs/postgresql +sleep 1 +if [ "$createdb" = "true" ]; then + $pgsql_prefix/bin/createdb db +fi + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-stop b/sca-cpp/trunk/components/sqldb/pgsql-stop new file mode 100755 index 0000000000..f840a85e0c --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-stop @@ -0,0 +1,28 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Stop postgresql +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +pgsql_prefix=`cat $here/pgsql.prefix` +mkdir -p $root/sqldb +mkdir -p $root/logs +$pgsql_prefix/bin/pg_ctl stop -D $root/sqldb + diff --git a/sca-cpp/trunk/components/sqldb/pgsql-test.cpp b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp new file mode 100644 index 0000000000..7fb6b0c814 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/pgsql-test.cpp @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Test PostgreSQL access functions. + */ + +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "perf.hpp" +#include "pgsql.hpp" + +namespace tuscany { +namespace pgsql { + +bool testPGSql() { + PGSql pg("dbname=db", "test"); + const value k = mklist<value>("a"); + + assert(hasContent(post(k, string("AAA"), pg))); + assert((get(k, pg)) == value(string("AAA"))); + assert(hasContent(put(k, string("aaa"), pg))); + assert((get(k, pg)) == value(string("aaa"))); + assert(hasContent(del(k, pg))); + assert(!hasContent(get(k, pg))); + + return true; +} + +struct getLoop { + const value k; + PGSql& pg; + getLoop(const value& k, PGSql& pg) : k(k), pg(pg) { + } + const bool operator()() const { + assert((get(k, pg)) == value(string("CCC"))); + return true; + } +}; + +bool testGetPerf() { + const value k = mklist<value>("c"); + PGSql pg("dbname=db", "test"); + assert(hasContent(post(k, string("CCC"), pg))); + + const lambda<bool()> gl = getLoop(k, pg); + cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl; + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::pgsql::testPGSql(); + tuscany::pgsql::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/trunk/components/sqldb/pgsql.hpp b/sca-cpp/trunk/components/sqldb/pgsql.hpp index 6743a4a3f5..b6b2cab331 100644 --- a/sca-cpp/trunk/components/sqldb/pgsql.hpp +++ b/sca-cpp/trunk/components/sqldb/pgsql.hpp @@ -22,13 +22,195 @@ #ifndef tuscany_pgsql_hpp #define tuscany_pgsql_hpp +#include <libpq-fe.h> + #include "string.hpp" #include "list.hpp" #include "value.hpp" #include "monad.hpp" +#include "../../modules/scheme/eval.hpp" namespace tuscany { -namespace sqldb { +namespace pgsql { + +/** + * Return and clear a Postgres result failure. + */ +const string pgfailure(PGresult* r) { + const string e = PQresultErrorMessage(r); + PQclear(r); + return e; +} + +/** + * Represents a PGSql connection. + */ +class PGSql { +public: + PGSql() : owner(false) { + } + + PGSql(const string& conninfo, const string& table) : owner(true), conninfo(conninfo), table(table) { + init(); + } + + PGSql(const PGSql& c) : owner(false) { + conninfo = c.conninfo; + conn = c.conn; + table = c.table; + } + + ~PGSql() { + if (!owner) + return; + PQfinish(conn); + } + +private: + bool owner; + PGconn *conn; + string conninfo; + string table; + + friend const failable<bool> post(const value& key, const value& val, const PGSql& pgsql); + friend const failable<bool> put(const value& key, const value& val, const PGSql& pgsql); + friend const failable<value> get(const value& key, const PGSql& pgsql); + friend const failable<bool> del(const value& key, const PGSql& pgsql); + + /** + * Initialize the database connection + */ + const failable<bool> init() { + conn = PQconnectdb(c_str(conninfo)); + if (PQstatus(conn) != CONNECTION_OK) + return mkfailure<bool>(string("Could not connect to database: ") + PQerrorMessage(conn)); + + // Find the name of the first column in the target table + // Assume that's the key we need to use + string ks = string("select a.attname from pg_attribute a, pg_class c where a.attrelid = c.relfilenode and c.relname = '") + table + string("' and a.attnum in (1, 2) order by a.attnum;"); + PGresult* kr = PQexec(conn, c_str(ks)); + if (PQresultStatus(kr) != PGRES_TUPLES_OK) + return mkfailure<bool>(string("Could not execute column select statement: ") + pgfailure(kr)); + if (PQntuples(kr) != 2) { + PQclear(kr); + return mkfailure<bool>(string("Could not find table key and value column names")); + } + const string kname = PQgetvalue(kr, 0, 0); + const string vname = PQgetvalue(kr, 1, 0); + PQclear(kr); + + // Prepare the post, put, get and delete statements + { + PGresult* r = PQprepare(conn, "post", c_str(string("insert into ") + table + string(" values($1, $2);")), 2, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare post SQL statement: ") + pgfailure(r)); + PQclear(r); + } + { + PGresult* r = PQprepare(conn, "put", c_str(string("update ") + table + string(" set ") + vname + string(" = $2 where ") + kname + string(" = $1;")), 2, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare put SQL statement: ") + pgfailure(r)); + PQclear(r); + } + { + PGresult* r = PQprepare(conn, "get", c_str(string("select * from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare get SQL statement: ") + pgfailure(r)); + PQclear(r); + } + { + PGresult* r = PQprepare(conn, "delete", c_str(string("delete from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not prepare delete SQL statement: ") + pgfailure(r)); + PQclear(r); + } + return true; + } +}; + +/** + * Post a new item to the database. + */ +const failable<bool> post(const value& key, const value& val, const PGSql& pgsql) { + debug(key, "pgsql::post::key"); + debug(val, "pgsql::post::value"); + debug(pgsql.table, "pgsql::post::table"); + + const string ks(scheme::writeValue(key)); + const string vs(scheme::writeValue(val)); + const char* params[2] = { c_str(ks), c_str(vs) }; + PGresult* r = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not execute post SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::post::result"); + return true; +} + +/** + * Update an item in the database. If the item doesn't exist it is added. + */ +const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) { + debug(key, "pgsql::put::key"); + debug(val, "pgsql::put::value"); + debug(pgsql.table, "pgsql::put::table"); + + const string ks(scheme::writeValue(key)); + const string vs(scheme::writeValue(val)); + const char* params[2] = { c_str(ks), c_str(vs) }; + PGresult* r = PQexecPrepared(pgsql.conn, "put", 2, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not execute put SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::put::result"); + return true; +} + +/** + * Get an item from the database. + */ +const failable<value> get(const value& key, const PGSql& pgsql) { + debug(key, "pgsql::get::key"); + debug(pgsql.table, "pgsql::get::table"); + + const string ks(scheme::writeValue(key)); + const char* params[1] = { c_str(ks) }; + PGresult* r = PQexecPrepared(pgsql.conn, "get", 1, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_TUPLES_OK) + return mkfailure<value>(string("Could not execute get SQL statement: ") + pgfailure(r)); + if (PQntuples(r) < 1) { + PQclear(r); + return mkfailure<value>(string("Could not get entry: ") + PQerrorMessage(pgsql.conn)); + } + const char* data = PQgetvalue(r, 0, 1); + const value val(scheme::readValue(string(data))); + PQclear(r); + + debug(val, "pgsql::get::result"); + return val; +} + +/** + * Delete an item from the database + */ +const failable<bool> del(const value& key, const PGSql& pgsql) { + debug(key, "pgsql::delete::key"); + debug(pgsql.table, "pgsql::delete::table"); + + const string ks(scheme::writeValue(key)); + const char* params[1] = { c_str(ks) }; + PGresult* r = PQexecPrepared(pgsql.conn, "delete", 1, params, NULL, NULL, 0); + if (PQresultStatus(r) != PGRES_COMMAND_OK) + return mkfailure<bool>(string("Could not execute delete SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::delete::result"); + return true; +} +} +} #endif /* tuscany_pgsql_hpp */ diff --git a/sca-cpp/trunk/components/sqldb/server-test b/sca-cpp/trunk/components/sqldb/server-test new file mode 100755 index 0000000000..bcd8f266d7 --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/server-test @@ -0,0 +1,43 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Setup +../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs +../../modules/server/server-conf tmp +../../modules/server/scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite sqldb.composite +EOF + +./pgsql-start tmp +./pgsql "drop table test" 1>/dev/null 2>&1 +./pgsql "create table test(key varchar(80), value varchar(200));" 1>/dev/null 2>&1 +../../modules/http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +./pgsql-stop tmp +sleep 2 +return $rc diff --git a/sca-cpp/trunk/components/sqldb/sqldb-test b/sca-cpp/trunk/components/sqldb/sqldb-test new file mode 100755 index 0000000000..c51e51df0c --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/sqldb-test @@ -0,0 +1,31 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Setup +./pgsql-start tmp +./pgsql "drop table test" 1>/dev/null 2>&1 +./pgsql "create table test(key varchar(80), value varchar(80));" 1>/dev/null 2>&1 + +# Test +./pgsql-test 2>/dev/null +rc=$? + +# Cleanup +./pgsql-stop tmp +return $rc diff --git a/sca-cpp/trunk/components/sqldb/sqldb.cpp b/sca-cpp/trunk/components/sqldb/sqldb.cpp new file mode 100644 index 0000000000..bec4c47a2b --- /dev/null +++ b/sca-cpp/trunk/components/sqldb/sqldb.cpp @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * PostgreSQL-based database component implementation. + */ + +#include <apr_uuid.h> + +#include "string.hpp" + +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "pgsql.hpp" + +namespace tuscany { +namespace sqldb { + +/** + * Get an item from the database. + */ +const failable<value> get(const list<value>& params, pgsql::PGSql& pg) { + return pgsql::get(car(params), pg); +} + +/** + * Post an item to the database. + */ +const value uuidValue() { + apr_uuid_t uuid; + apr_uuid_get(&uuid); + char buf[APR_UUID_FORMATTED_LENGTH]; + apr_uuid_format(buf, &uuid); + return value(string(buf, APR_UUID_FORMATTED_LENGTH)); +} + +const failable<value> post(const list<value>& params, pgsql::PGSql& pg) { + const value id = append<value>(car(params), mklist(uuidValue())); + const failable<bool> val = pgsql::post(id, cadr(params), pg); + if (!hasContent(val)) + return mkfailure<value>(reason(val)); + return id; +} + +/** + * Put an item into the database. + */ +const failable<value> put(const list<value>& params, pgsql::PGSql& pg) { + const failable<bool> val = pgsql::put(car(params), cadr(params), pg); + if (!hasContent(val)) + return mkfailure<value>(reason(val)); + return value(content(val)); +} + +/** + * Delete an item from the database. + */ +const failable<value> del(const list<value>& params, pgsql::PGSql& pg) { + const failable<bool> val = pgsql::del(car(params), pg); + if (!hasContent(val)) + return mkfailure<value>(reason(val)); + return value(content(val)); +} + +/** + * Component implementation lambda function. + */ +class applySqldb { +public: + applySqldb(pgsql::PGSql& pg) : pg(pg) { + } + + const value operator()(const list<value>& params) const { + const value func(car(params)); + if (func == "get") + return get(cdr(params), pg); + if (func == "post") + return post(cdr(params), pg); + if (func == "put") + return put(cdr(params), pg); + if (func == "delete") + return del(cdr(params), pg); + return tuscany::mkfailure<tuscany::value>(); + } + +private: + pgsql::PGSql& pg; +}; + +/** + * Start the component. + */ +const failable<value> start(unused const list<value>& params) { + // Connect to the database + pgsql::PGSql& pg = *(new (gc_new<pgsql::PGSql>()) pgsql::PGSql("dbname=db", "test")); + + // Return the component implementation lambda function + return value(lambda<value(const list<value>&)>(applySqldb(pg))); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "start") + return tuscany::sqldb::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} |