zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #21284
[Merge] lp:~zorba-coders/zorba/couchbase-fn-private into lp:zorba
Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/couchbase-fn-private into lp:zorba.
Commit message:
fn prefix not allowed in annotations
Requested reviews:
Markos Zaharioudakis (markos-za)
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/couchbase-fn-private/+merge/161468
fn prefix not allowed in annotations
--
https://code.launchpad.net/~zorba-coders/zorba/couchbase-fn-private/+merge/161468
Your team Zorba Coders is subscribed to branch lp:zorba.
=== added file 'CMakeLists.txt'
--- CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ CMakeLists.txt 2013-04-29 18:32:40 +0000
@@ -0,0 +1,54 @@
+# Copyright 2012 The FLWOR Foundation.
+#
+# Licensed 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.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT (zorba_couchbase_module)
+ENABLE_TESTING ()
+INCLUDE (CTest)
+
+IF (WIN32)
+ # On Windows we use proxy modules that try to guess first the location
+ # of the required third party libraries. This will search in order in:
+ # 1. the path pointed by ZORBA_THIRD_PARTY_REQUIREMENTS
+ # 2. the Program Files directory available on the users computer
+ # 3. the PATH environment variable
+ # The logic is implemented by the macros in the ProxyFindModule.cmake module.
+ LIST (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules/Windows")
+ENDIF (WIN32)
+LIST (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
+
+FIND_PACKAGE (Zorba REQUIRED HINTS "${ZORBA_BUILD_DIR}")
+MESSAGE(STATUS "Zorba_USE_FILE ${Zorba_USE_FILE}")
+INCLUDE ("${Zorba_USE_FILE}")
+
+IF (ZORBA_SUPPRESS_LIBCOUCHBASE)
+ MESSAGE (STATUS "ZORBA_SUPRESS_COUCHBASE is true - not searching for LibCouchbase.")
+ELSE (ZORBA_SUPRESS_LIBCOUCHBASE)
+
+ MESSAGE (STATUS "Looking for LibCouchbase")
+ FIND_PACKAGE ("LibCouchbase")
+
+ IF (LIBCOUCHBASE_FOUND)
+ MESSAGE (STATUS "Found LibCouchbase --" ${LIBCOUCHBASE_LIBRARIES})
+ INCLUDE_DIRECTORIES (${LIBCOUCHBASE_INCLUDE_DIR})
+
+ ADD_SUBDIRECTORY("src")
+ ADD_TEST_DIRECTORY("${PROJECT_SOURCE_DIR}/test")
+ ELSE (LIBCOUCHBASE_FOUND)
+ MESSAGE (STATUS "LibCouchbase library not found; couchbase module skipped")
+ ENDIF (LIBCOUCHBASE_FOUND)
+ENDIF (ZORBA_SUPPRESS_LIBCOUCHBASE)
+
+DONE_DECLARING_ZORBA_URIS()
=== renamed file 'CMakeLists.txt' => 'CMakeLists.txt.moved'
=== added directory 'cmake_modules'
=== renamed directory 'cmake_modules' => 'cmake_modules.moved'
=== added file 'cmake_modules/FindLibCouchbase.cmake'
--- cmake_modules/FindLibCouchbase.cmake 1970-01-01 00:00:00 +0000
+++ cmake_modules/FindLibCouchbase.cmake 2013-04-29 18:32:40 +0000
@@ -0,0 +1,47 @@
+# Copyright 2012 The FLWOR Foundation.
+#
+# Licensed 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.
+
+IF (LIBCOUCHBASE_INCLUDE_DIR)
+ SET (LIBCOUCHBASE_FIND_QUIETLY TRUE)
+ENDIF (LIBCOUCHBASE_INCLUDE_DIR)
+
+FIND_PATH (
+ LIBCOUCHBASE_INCLUDE_DIR
+ libcouchbase/couchbase.h
+ PATHS /opt/local/include)
+MARK_AS_ADVANCED (LIBCOUCHBASE_INCLUDE_DIR)
+
+FIND_LIBRARY (
+ LIBCOUCHBASE_LIBRARY
+ NAMES couchbase
+ PATHS /opt/local/lib)
+MARK_AS_ADVANCED (LIBCOUCHBASE_LIBRARY)
+
+IF (LIBCOUCHBASE_INCLUDE_DIR AND LIBCOUCHBASE_LIBRARY)
+ SET (LIBCOUCHBASE_FOUND 1)
+ SET (LIBCOUCHBASE_LIBRARIES ${LIBCOUCHBASE_LIBRARY})
+ SET (LIBCOUCHBASE_INCLUDE_DIRS ${LIBCOUCHBASE_INCLUDE_DIR})
+ IF (NOT LIBCOUCHBASE_FIND_QUIETLY)
+ MESSAGE (STATUS "Found libcouchbase library: " ${LIBCOUCHBASE_LIBRARY})
+ MESSAGE (STATUS "Found libcouchbase include path : " ${LIBCOUCHBASE_INCLUDE_DIR})
+ ENDIF (NOT LIBCOUCHBASE_FIND_QUIETLY)
+
+ SET(CMAKE_REQUIRED_INCLUDES "${LIBCOUCHBASE_INCLUDE_DIR}")
+ SET(CMAKE_REQUIRED_LIBRARIES "${LIBCOUCHBASE_LIBRARY}")
+
+ELSE (LIBCOUCHBASE_INCLUDE_DIR AND LIBCOUCHBASE_LIBRARY)
+ SET (LIBCOUCHBASE_FOUND 0)
+ SET (LIBCOUCHBASE_LIBRARIES)
+ SET (LIBCOUCHBASE_INCLUDE_DIRS)
+ENDIF (LIBCOUCHBASE_INCLUDE_DIR AND LIBCOUCHBASE_LIBRARY)
=== added directory 'cmake_modules/Windows'
=== added file 'cmake_modules/Windows/findLibCouchbase.cmake'
--- cmake_modules/Windows/findLibCouchbase.cmake 1970-01-01 00:00:00 +0000
+++ cmake_modules/Windows/findLibCouchbase.cmake 2013-04-29 18:32:40 +0000
@@ -0,0 +1,21 @@
+# Copyright 2012 The FLWOR Foundation.
+#
+# Licensed 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.
+
+FIND_PACKAGE_WIN32 (NAME LibCouchbase FOUND_VAR LIBCOUCHBASE_FOUND SEARCH_NAMES libcouchbase)
+
+IF (LIBCOUCHBASE_FOUND)
+ FIND_PACKAGE_DLLS_WIN32 (${FOUND_LOCATION} libcouchbase.dll)
+ SET(CMAKE_REQUIRED_INCLUDES "${LIBCOUCHBASE_INCLUDE_DIR}")
+ SET(CMAKE_REQUIRED_LIBRARIES "${LIBCOUCHBASE_LIBRARY}")
+ENDIF (LIBCOUCHBASE_FOUND)
=== added directory 'examples'
=== added file 'examples/example-put-data.xq'
--- examples/example-put-data.xq 1970-01-01 00:00:00 +0000
+++ examples/example-put-data.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,12 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace http = "http://www.zorba-xquery.com/modules/http-client";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : null,
+ "password" : null,
+ "bucket" : "default"});
+
+variable $json-zip := jn:parse-json(http:get-text("http://media.mongodb.org/zips.json")[2]);
+for $result in $json-zip
+ return cb:put-text($instance, $result("_id"), fn:serialize($result), {"expiration-time" : 60*60*24});
=== added file 'examples/example.xq'
--- examples/example.xq 1970-01-01 00:00:00 +0000
+++ examples/example.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,19 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace http = "http://www.zorba-xquery.com/modules/http-client";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : null,
+ "password" : null,
+ "bucket" : "default"});
+variable $view-name := cb:create-view($instance, "zip", "zip", {"key" : "doc.state", "values" : "doc.pop"});
+variable $data := cb:view($instance, $view-name, {"stale" : "false"});
+for $d in jn:members($data("rows"))
+let $state := $d("key")
+group by $state
+where $d("value") > 0
+let $population := sum($d("value"))
+order by $population
+where $population > 10000000
+return { "state" : $state, "total population" : $population }
+
=== added file 'examples/example2.xq'
--- examples/example2.xq 1970-01-01 00:00:00 +0000
+++ examples/example2.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,19 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace http = "http://www.zorba-xquery.com/modules/http-client";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : null,
+ "password" : null,
+ "bucket" : "default"});
+
+variable $view-name := cb:create-view($instance, "zip", "zip", {"key" : "doc.state", "values" : "doc.pop"});
+variable $data := cb:view($instance, $view-name);
+for $d in jn:members($data("rows"))
+let $state := $d("key")
+group by $state
+let $zip := $d("id")
+let $number-zip := count($zip)
+order by $number-zip descending
+return { "state" : $state, "zip count" : $number-zip }
+
=== added file 'examples/example3.xq'
--- examples/example3.xq 1970-01-01 00:00:00 +0000
+++ examples/example3.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,23 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace http = "http://www.zorba-xquery.com/modules/http-client";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : null,
+ "password" : null,
+ "bucket" : "default"});
+
+variable $view-name := cb:create-view($instance, "zip", "zip", {"key" : "doc.state", "values" : "doc.pop"});
+variable $data := cb:view($instance, $view-name);
+for $d in jn:members($data("rows"))
+let $state := $d("key")
+group by $state
+where $d("value") > 0
+let $zip := $d("id")
+let $population := sum($d("value"))
+let $number-zip := count($zip)
+let $avarage-pop := $population div $number-zip
+order by $avarage-pop descending
+return { "state" : $state , "avarage population" : round-half-to-even($avarage-pop, 2) }
+
+
=== added file 'examples/example4.xq'
--- examples/example4.xq 1970-01-01 00:00:00 +0000
+++ examples/example4.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,44 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace http = "http://www.zorba-xquery.com/modules/http-client";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : null,
+ "password" : null,
+ "bucket" : "default"});
+
+variable $view-name := cb:create-view($instance, "zip", "zip", {"key" : "doc.state", "values" : ["doc.pop", "doc.city"]});
+variable $data := cb:view($instance, $view-name);
+
+
+let $city-pop :=
+ for $d in jn:members($data("rows"))
+ let $state := $d("key")
+ let $pop := $d("value")(1)
+ let $city := $d("value")(2)
+ where $pop > 0
+ group by $city, $state
+ let $total-pop := sum($pop)
+ return {"state" : $state, "city" : $city, "pop" : $total-pop}
+let $result :=
+ for $i in $city-pop
+ let $state := $i("state")
+ let $city := $i("city")
+ let $pop := $i("pop")
+ group by $state
+ let $largest-city := max($pop)
+ let $smallest-city := min ($pop)
+ return
+ {
+ "state" : $state ,
+ "largest city" :
+ for $e in $city-pop
+ where $e("pop") eq $largest-city
+ return $e("city"),
+ "smallest city" :
+ for $e in $city-pop
+ where $e("pop") eq $smallest-city
+ return $e("city")
+ }
+return $result
+
=== added directory 'install_couchbase'
=== added file 'install_couchbase/install.cmake'
--- install_couchbase/install.cmake 1970-01-01 00:00:00 +0000
+++ install_couchbase/install.cmake 2013-04-29 18:32:40 +0000
@@ -0,0 +1,83 @@
+# Script for Downloading and configuring the Couchbase Server to
+#run with the Module tests.
+#
+# Usage: cmake [ -Dsystem=value ...]
+# -P install.cmake
+# Be sure all -D options come before -P !
+# Valid options:
+# system = system to indetify the couchbase server to download and
+# install, currently only ubuntu32 and ubuntu64 are valid
+# options.
+#
+# Example: cmake -Dsystem=ubuntu64 -P install.cmake
+
+
+# uninstalling couchbase server
+# run:
+# sudo dpkg -r couchbase-server
+# sudo --purge couchbase-server
+# sudo rm -rf /opt/couchbase/
+
+#Figure out what directory we're running in
+get_filename_component(cwd ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+FIND_PROGRAM(WGET wget DOC "tool for downloading couchbase server")
+
+IF(SKIP_COUCHBASE_DOWNLOAD)
+ SET(COUCHBASE_DOWNLOAD OFF)
+ELSE(SKIP_COUCHBASE_DOWNLOAD)
+ SET(COUCHBASE_DOWNLOAD ON)
+ENDIF(SKIP_COUCHBASE_DOWNLOAD)
+
+#Couchbase Configure
+ #Check what version of couchbase server to download
+ IF(system)
+ SET(DOWNLOAD_PATH "http://packages.couchbase.com/releases/2.0.0-beta")
+ IF (${system} STREQUAL "ubuntu32")
+ SET(COUCHBASE_DEB_NAME "couchbase-server-community_x86_2.0.0-beta.deb")
+ ELSE (${system} STREQUAL "ubuntu32")
+ IF (${system} STREQUAL "ubuntu64")
+ SET(COUCHBASE_DEB_NAME "couchbase-server-community_x86_64_2.0.0-beta.deb")
+ ELSE (${system} STREQUAL "ubuntu64")
+ MESSAGE(FATAL_ERROR "Invalid value for system (available values ubuntu32 and ubuntu64")
+ ENDIF (${system} STREQUAL "ubuntu64")
+ ENDIF (${system} STREQUAL "ubuntu32")
+ ELSE(system)
+ MESSAGE(FATAL_ERROR "the variable 'system' must be set")
+ ENDIF(system)
+
+#Couchbase Download
+IF(COUCHBASE_DOWNLOAD)
+ IF(WGET)
+ MESSAGE(STATUS "wget found")
+ MESSAGE(STATUS "Starting Download...")
+ EXECUTE_PROCESS(COMMAND "${WGET}" "${DOWNLOAD_PATH}/${COUCHBASE_DEB_NAME}")
+ ELSE(WGET)
+ MESSAGE(FATAL_ERROR "Wget was not found, cannot download Couchbase Server")
+ ENDIF(WGET)
+ENDIF(COUCHBASE_DOWNLOAD)
+
+#Couchbase Install
+MESSAGE(STATUS "Installing Couchbase Server...")
+EXECUTE_PROCESS(COMMAND sudo dpkg -i ${COUCHBASE_DEB_NAME})
+EXECUTE_PROCESS(COMMAND sudo apt-get install -f)
+
+#Couchbase C SDK Install
+MESSAGE(STATUS "Installing Couchbase C SDK...")
+EXECUTE_PROCESS(COMMAND sudo "${WGET}" -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1110.list)
+EXECUTE_PROCESS(COMMAND "${WGET}" -O- http://packages.couchbase.com/ubuntu/couchbase.key
+ COMMAND sudo apt-key add -)
+EXECUTE_PROCESS(COMMAND apt-get update)
+EXECUTE_PROCESS(COMMAND apt-get install libcouchbase2 libcouchbase-dev)
+
+#Couchbase Setup
+MESSAGE(STATUS "Starting Setup...")
+MESSAGE(STATUS "Running node-init...")
+EXECUTE_PROCESS(COMMAND /opt/couchbase/bin/couchbase-cli node-init -c 127.0.0.1 --node-init-data-path=/opt/couchbase/var/lib/couchbase/data/ -u admin -p password)
+MESSAGE(STATUS "Running cluster-init...")
+EXECUTE_PROCESS(COMMAND /opt/couchbase/bin/couchbase-cli cluster-init -c 127.0.0.1 --cluster-init-ramsize=2048 -u admin -p password)
+MESSAGE(STATUS "Running create-bucket...")
+EXECUTE_PROCESS(COMMAND /opt/couchbase/bin/couchbase-cli bucket-create -c 127.0.0.1 --bucket=default --bucket-type=couchbase --bucket-port=11211 --bucket-ramsize=200 --bucket-replica=1 -u admin -p password)
+MESSAGE(STATUS "Couchbase Server Configure for testing, Username=admin Password=password bucket-name=default")
+EXECUTE_PROCESS(COMMAND rm ${COUCHBASE_DEB_NAME})
+
=== added directory 'src'
=== renamed directory 'src' => 'src.moved'
=== added file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/CMakeLists.txt 2013-04-29 18:32:40 +0000
@@ -0,0 +1,22 @@
+# Copyright 2012 The FLWOR Foundation.
+#
+# Licensed 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.
+
+INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/couchbase.xq.src")
+
+DECLARE_ZORBA_MODULE (
+ URI "http://www.zorba-xquery.com/modules/couchbase"
+ VERSION 1.0
+ FILE "couchbase.xq"
+ LINK_LIBRARIES "${LIBCOUCHBASE_LIBRARIES}")
+
=== added file 'src/couchbase.xq'
--- src/couchbase.xq 1970-01-01 00:00:00 +0000
+++ src/couchbase.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,491 @@
+xquery version "3.0";
+
+(:
+ : Copyright 2012 The FLWOR Foundation.
+ :
+ : Licensed 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.
+ :)
+
+(:~
+ : This module provides minimal functionality to interact with the
+ : Couchbase NoSQL database.
+ :
+ : The module is built using the libcouchbase C client library and
+ : exposes most of its functionality in XQuery with JSONiq extensions.
+ : Beyond just allowing for basic key-value store operations (e.g.
+ : put-/get-text or put-/get-binary, this module also allows to work
+ : with Couchbase views in order to allow for complex JSON query
+ : operations.
+ :
+ : @author Juan Zacarias
+ :
+ :)
+module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+declare namespace jn = "http://jsoniq.org/functions";
+declare namespace an = "http://www.zorba-xquery.com/annotations";
+
+declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
+declare option ver:module-version "1.0";
+
+(:~
+ : Connect to the Couchbase server and return an opaque identifier
+ : representing the established connection.
+ :
+ : @param $host address of the couchbase server (e.g. "localhost:8091")
+ : @param $username username used for the connection
+ : @param $password password used for the connection
+ : @param $bucket name of the bucket to use (e.g. "default")
+ :
+ : @error cb:LCB0001 if the connection to the given host/bucket
+ : could not be established.
+ :
+ : @return an identifier for the established connection.
+ :)
+
+declare %an:sequential function cb:connect(
+ $host as xs:string,
+ $username as xs:string?,
+ $password as xs:string?,
+ $bucket as xs:string)
+ as xs:anyURI
+{
+ cb:connect({"host" : $host,
+ "username" : $username,
+ "password" : $password,
+ "bucket" : $bucket })
+};
+
+(:~
+ : Connect to the Couchbase server and return an opaque identifier
+ : representing the established connection.
+ :
+ : @param $options a JSONiq object that contains the host, bucket,
+ : and user information.
+ :
+ : @option "host" endpoint of the Couchbase server (mandatory)
+ : @option "username" username used for the connection (optional)
+ : @option "password" password used for the connection (optional)
+ : @option "bucket" name of an existing bucket (mandatory)
+ :
+ : @error cb:LCB0001 if the connection to the given host/bucket
+ : could not be established.
+ : @error cb:CB0001 if mandatory connection information is missing.
+ : @error cb:CB0007 if a given option is not supported.
+ :
+ : @return an identifier for the established connection.
+ :
+ : Example:
+ : <code>
+ : {
+ : "host": "localhost:8091",
+ : "username" : null,
+ : "password" : null,
+ : "bucket" : "default"
+ : }
+ : </code>
+ :)
+declare %an:sequential function cb:connect($options as object())
+ as xs:anyURI external;
+
+(:~
+ : Return the values of the given keys (type xs:string) as string.
+ :
+ : @param $db connection reference
+ : @param $key the requested keys
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return A sequence of string Items corresponding to the key
+ :)
+
+declare %an:sequential function cb:get-text(
+ $db as xs:anyURI,
+ $key as xs:string*)
+as xs:string* external;
+
+(:~
+ : Return the values of the given keys (type xs:string) as string.
+ :
+ : @param $db connection reference
+ : @param $key the requested keys
+ : @param $options JSONiq object with additional options
+ :
+ : @option "expiration-time" xs:integer value for refreshing the expiration
+ : time in seconds.
+ : @option "encoding" string with the name of the encoding of the returned
+ : string (if not UTF-8).
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0006 if the given encoding is not supported.
+ : @error cb:CB0007 if any of the options is not supported.
+ : @error cb:CB0009 if the given expiration time is not an xs:integer.
+ :
+ : @return a sequence of strings for the given keys.
+ :)
+
+declare %an:sequential function cb:get-text(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $options as object())
+as xs:string* external;
+
+(:~
+ : Return the values of the given keys (type xs:string) as base64Binary.
+ :
+ : @param $db connection reference
+ : @param $key the requested keys
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return a sequence of xs:base64Binary items for the given keys.
+ :)
+declare %an:sequential function cb:get-binary(
+ $db as xs:anyURI,
+ $key as xs:string*)
+as xs:base64Binary* external;
+
+(:~
+ : Return the values of the given keys (type xs:string) as base64Binary.
+ :
+ : @param $db connection reference
+ : @param $key the requested keys
+ : @param $options JSONiq object with additional options
+ :
+ : @option "expiration-time" xs:integer value for refreshing the expiration
+ : time in seconds.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0007 if any of the options is not supported.
+ : @error cb:CB0009 if the given expiration time is not an xs:integer.
+ :
+ : @return a sequence of xs:base64Binary items for the given keys.
+ :)
+declare %an:sequential function cb:get-binary(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $options as object())
+as xs:base64Binary* external;
+
+(:~
+ : Remove the values matching the given keys (xs:string) from the server.
+ :
+ : @param $db connection reference
+ : @param $key the keys of the values that should be removed.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:remove($db as xs:anyURI, $key as xs:string*)
+ as empty-sequence() external;
+
+(:~
+ : Store the given key-value bindings.
+ :
+ : The values are stored with the UTF-8 encoding and a default
+ : expiration time of 60 seconds.
+ :
+ : @param $db connection reference
+ : @param $key the keys to store
+ : @param $value the values (as xs:string) to be stored.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0005 if the number of keys doesn't match the number
+ : of values.
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:put-text(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $value as xs:string*)
+as empty-sequence()
+{
+ cb:put-text($db, $key, $value, { "expiration-time" : 60, "encoding" : "UTF-8" })
+};
+
+(:~
+ : Store the given key-value bindings.
+ :
+ : @param $db connection reference
+ : @param $key the keys to store
+ : @param $value the values (as xs:string) to be stored.
+ : @param $options JSONiq object with additional options
+ :
+ : @option "expiration-time" integer value that represent the
+ : expiration time in seconds.
+ : @option "operation" type of operation, possible values are
+ : "add", "replace", "set", "append" and "prepend".
+ : @option "encoding" the encoding that should be used for the
+ : value (default is UTF-8).
+ : @option "wait" variable for setting if a wait for persistancy in
+ : the storing key is needed, possible values are "persist"
+ : and "false".
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0005 if the number of keys doesn't match the number
+ : of values.
+ : @error cb:CB0006 if the given encoding is not supported.
+ : @error cb:CB0007 if any of the options is not supported.
+ : @error cb:CB0009 if the given expiration time is not an xs:integer.
+ : @error cb:CB0011 if the stored Variable was not stored
+ :
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:put-text(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $value as xs:string*,
+ $options as object())
+ as empty-sequence() external;
+
+(:~
+ : Store the given key-value bindings.
+ :
+ : @param $db connection reference
+ : @param $key the keys to store
+ : @param $value the values (as xs:base64binary) to be stored.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0005 if the number of keys doesn't match the number
+ : of values.
+ :
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:put-binary(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $value as xs:base64Binary*)
+as empty-sequence()
+{
+ cb:put-binary($db, $key, $value, { "expiration-time" : 60 })
+};
+
+(:~
+ : Store the given key-value bindings.
+ :
+ : @param $db connection reference
+ : @param $key the keys to store
+ : @param $value the values (as xs:base64binary) to be stored.
+ : @param $options JSONiq object with additional options
+
+ : @option "expiration-time" integer value that represent the
+ : expiration time in seconds.
+ : @option "operation" type of operation, possible values are
+ : "add", "replace", "set", "append" and "prepend".
+ : @option "wait" variable for setting if a wait for persistancy in
+ : the storing key is needed, possible values are "persist"
+ : and "false".
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0005 if the number of keys doesn't match the number
+ : of values.
+ : @error cb:CB0007 if any of the options is not supported.
+ : @error cb:CB0009 if the given expiration time is not an xs:integer.
+ : @error cb:CB0011 if the stored Variable was not stored
+ :
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:put-binary(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $value as xs:base64Binary*,
+ $options as object())
+as empty-sequence() external;
+
+
+(:~
+ : Remove all key/value pairs from the cluster
+ :
+ : @param $db connection reference
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:flush($db as xs:anyURI)
+as empty-sequence() external;
+
+(:~
+ : Refresh the expiration time of the given keys.
+ :
+ : @param $db connection reference
+ : @param $key the keys to touch
+ : @param $exp-time new expieration time in seconds
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return a empty sequence.
+ :)
+declare %an:sequential function cb:touch(
+ $db as xs:anyURI,
+ $key as xs:string*,
+ $exp-time as xs:integer)
+as empty-sequence() external;
+
+(:~
+ : Retrieve the content of existing views.
+ :
+ : @param $db connection reference
+ : @param $path contains the string of a view path
+ : (e.g. "_design/test/_view/vies").
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return a sequence of strings (as JSON) containing information of the views.
+ :)
+declare %an:sequential function cb:view($db as xs:anyURI, $path as xs:string*)
+ as object()*
+{
+ jn:parse-json(cb:view-text($db, $path))
+};
+
+declare %fn:private %an:sequential function cb:view-text($db as xs:anyURI, $path as xs:string*)
+ as xs:string* external;
+
+
+(:~
+ : Retrieve the content of existing views.
+ :
+ : @param $db connection reference
+ : @param $path contains the string of a view path
+ : (e.g. "_design/test/_view/vies").
+ : @param $options JSONiq object with additional options
+ :
+ : @option Json object whith options for the querying the view. available options:
+ : "encoding" string with the name of the encoding of the returned
+ : strings (if not UTF-8).
+ : "stale" option's value is a string with the type of stale to be used.
+ : Valid values:
+ : "ok" : the view is not updated
+ : "false" : the view is updated before the function view is executed,
+ : this options needs the key to be on disk before the call of the
+ : view function.
+ : "update_after" : the view is updated after the call of view
+ : "limit" option's value is an integer which sets a number of how many
+ : rows the view will show.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0007 if any of the options is not supported.
+ :
+ : @return a sequence of strings (as JSON) containing information of the views.
+ :)
+declare %an:sequential function cb:view(
+ $db as xs:anyURI,
+ $path as xs:string*,
+ $options as object())
+as object()*
+{
+ jn:parse-json(cb:view-text($db, $path, $options))
+};
+
+declare %fn:private %an:sequential function cb:view-text(
+ $db as xs:anyURI,
+ $path as xs:string*,
+ $options as object())
+as xs:string* external;
+
+
+(:~
+ : Create a document/view.
+
+ : If the document already exists, it is replaced. A document can hold several
+ : views that must be specified in the same call of cb:create-view.
+ :
+ : @param $db connection reference
+ : @param $doc-name name of the document to create.
+ : @param $view-names names of the views to create in the document.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return the names of the paths for the views that have been
+ : created.
+ :)
+declare %an:sequential function cb:create-view(
+ $db as xs:anyURI,
+ $doc-name as xs:string,
+ $view-names as xs:string*)
+as xs:string* external;
+
+(:~
+ : Create a document/view.
+
+ : If the document already exists, it is replaced. A document can hold several
+ : views that must be specified in the same call of cb:create-view.
+ :
+ : @param $db connection reference
+ : @param $doc-name name of the document to create.
+ : @param $view-names names of the views to create in the document.
+ : @param $options options describing how to create the view.
+ :
+ : @option "key" value must be a string containing the name of the value
+ : in the json object stored in couchbase that is wanted to be
+ : displayed as the value of "key" in the resulting json.
+ : @option "values" value must be a string or an array of strings containing
+ : the name of the value in the json object stored in couchbase that
+ : is wanted to be displayed as the value of "value" in the resulting
+ : json.
+ : @option "function" string with a javascript function describing the
+ : map function of the view. cb:create-view won't throw an error
+ : if the javascript function is not compilable or functional. If
+ : this option is set the "key" and "values" options are ignored.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ : @error cb:CB0005 if the number of options doesn't match the number of
+ : view-names.
+ : @error cb:CB0007 if any of the options is not supported.
+ : @error cb:CB0010 if any of the given options has an invalid type.
+ :
+ : @return the names of the paths for the views that have been
+ : created.
+ :)
+declare %an:sequential function cb:create-view(
+ $db as xs:anyURI,
+ $doc-name as xs:string,
+ $view-names as xs:string*,
+ $options as object()*)
+as xs:string* external;
+
+
+(:~
+ : Delete a document/view.
+
+ : If the document doesn't exists, function does nothing. All the views hold in the
+ : Document are deleted, this function can't delete single views.
+ :
+ : @param $db connection reference
+ : @param $doc-name name of the document to create.
+ :
+ : @error cb:LCB0002 if any error occurs in the communication with
+ : the server.
+ :
+ : @return empty sequence.
+ :)
+declare %an:sequential function cb:delete-view(
+ $db as xs:anyURI,
+ $doc as xs:string*)
+as xs:string* external;
=== added directory 'src/couchbase.xq.src'
=== added file 'src/couchbase.xq.src/couchbase.cpp'
--- src/couchbase.xq.src/couchbase.cpp 1970-01-01 00:00:00 +0000
+++ src/couchbase.xq.src/couchbase.cpp 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1474 @@
+
+/*
+ * Copyright 2012 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+
+#include <zorba/item_factory.h>
+#include <zorba/singleton_item_sequence.h>
+#include <zorba/empty_sequence.h>
+#include <zorba/store_manager.h>
+#include <zorba/user_exception.h>
+#include <zorba/transcode_stream.h>
+#include <zorba/serializer.h>
+#include <zorba/vector_item_sequence.h>
+#include <stdio.h>
+#include <iostream>
+#include <algorithm>
+
+
+#include <zorba/util/uuid.h>
+
+
+#include <libcouchbase/couchbase.h>
+
+#include "couchbase.h"
+
+namespace zorba { namespace couchbase {
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ExternalFunction*
+ CouchbaseModule::getExternalFunction(const zorba::String& localname)
+{
+ FuncMap_t::iterator lIte = theFunctions.find(localname);
+
+ ExternalFunction*& lFunc = theFunctions[localname];
+
+ if (lIte == theFunctions.end())
+ {
+ if (localname == "connect")
+ {
+ lFunc = new ConnectFunction(this);
+ }
+ else if (localname == "get-text")
+ {
+ lFunc = new GetTextFunction(this);
+ }
+ else if (localname == "get-binary")
+ {
+ lFunc = new GetBinaryFunction(this);
+ }
+ else if (localname == "put-text")
+ {
+ lFunc = new PutTextFunction(this);
+ }
+ else if (localname == "put-binary")
+ {
+ lFunc = new PutBinaryFunction(this);
+ }
+ else if (localname == "remove")
+ {
+ lFunc = new RemoveFunction(this);
+ }
+ else if (localname == "flush")
+ {
+ lFunc = new FlushFunction(this);
+ }
+ else if (localname == "touch")
+ {
+ lFunc = new TouchFunction(this);
+ }
+ else if (localname == "view-text")
+ {
+ lFunc = new ViewFunction(this);
+ }
+ else if (localname == "create-view")
+ {
+ lFunc = new CreateViewFunction(this);
+ }
+ else if (localname == "delete-view")
+ {
+ lFunc = new DeleteViewFunction(this);
+ }
+ }
+
+ return lFunc;
+}
+
+void CouchbaseModule::destroy()
+{
+ delete this;
+}
+
+CouchbaseModule::~CouchbaseModule()
+{
+ for (FuncMap_t::const_iterator lIter = theFunctions.begin();
+ lIter != theFunctions.end(); ++lIter)
+ {
+ delete lIter->second;
+ }
+ theFunctions.clear();
+
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+CouchbaseFunction::CouchbaseFunction(const CouchbaseModule* aModule)
+ : theModule(aModule)
+{
+}
+
+CouchbaseFunction::~CouchbaseFunction()
+{
+}
+
+String
+CouchbaseFunction::getURI() const
+{
+ return theModule->getURI();
+}
+
+String
+CouchbaseFunction::getOneStringArgument(const Arguments_t& aArgs, int aPos) const
+{
+ Item lItem = getOneItemArgument(aArgs, aPos);
+ String lTmpString = lItem.getStringValue();
+ return lTmpString;
+}
+
+Item
+CouchbaseFunction::getOneItemArgument(const Arguments_t& aArgs, int aPos) const
+{
+ Item lItem;
+ Iterator_t args_iter = getIterArgument(aArgs, aPos);
+ args_iter->open();
+ args_iter->next(lItem);
+ args_iter->close();
+ return lItem;
+}
+
+Iterator_t
+CouchbaseFunction::getIterArgument(const Arguments_t& aArgs, int aPos) const
+{
+ Iterator_t args_iter = aArgs[aPos]->getIterator();
+ return args_iter;
+}
+
+void
+CouchbaseFunction::throwError(const char *aLocalName, const char* aErrorMessage)
+{
+ String errName(aLocalName);
+ Item errQName = CouchbaseModule::getItemFactory()->createQName(COUCHBASE_MODULE_NAMESPACE, errName);
+ String errDescription(aErrorMessage);
+ throw USER_EXCEPTION(errQName, errDescription);
+}
+
+void
+CouchbaseFunction::isNotJSONError()
+{
+ throwError("CB0002", "Options parameter is not a JSON object");
+}
+
+void
+CouchbaseFunction::libCouchbaseError(lcb_t aInstance, lcb_error_t aError)
+{
+ throwError("LCB0002", lcb_strerror(aInstance, aError));
+}
+
+
+lcb_t
+CouchbaseFunction::getInstance(const DynamicContext* aDctx, const String& aIdent) const
+{
+ InstanceMap* lInstanceMap;
+ lcb_t lInstance;
+ if ((lInstanceMap = dynamic_cast<InstanceMap*>(aDctx->getExternalFunctionParameter("couchbaseInstanceMap"))))
+ {
+ if ((lInstance = lInstanceMap->getInstance(aIdent)))
+ return lInstance;
+ }
+ throwError("CB0000", "No instance of couchbase with the given identifier was found.");
+ return NULL;
+}
+
+String
+ CouchbaseFunction::ViewOptions::getPathOptions()
+{
+ String lPathOptions("?");
+ bool lAmp = false;
+ if (theStaleOption != "")
+ {
+ lPathOptions.append(theStaleOption);
+ lAmp = true;
+ }
+ if (theLimitOption != "")
+ {
+ if(lAmp)
+ lPathOptions.append("&");
+ lPathOptions.append(theLimitOption);
+ lAmp = true;
+ }
+
+ if (lPathOptions == "?")
+ lPathOptions = "";
+
+ return lPathOptions;
+}
+
+void
+ CouchbaseFunction::ViewOptions::setOptions(Item& aOptions)
+{
+ if (!aOptions.isJSONItem())
+ isNotJSONError();
+
+ Iterator_t lIter = aOptions.getObjectKeys();
+ Item lItem;
+ lIter->open();
+ while (lIter->next(lItem))
+ {
+ String lStrKey = lItem.getStringValue();
+ std::transform(
+ lStrKey.begin(), lStrKey.end(),
+ lStrKey.begin(), tolower);
+ if (lStrKey == "encoding")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ theEncoding = lValue.getStringValue();
+ if (!transcode::is_supported(theEncoding.c_str()))
+ {
+ std::ostringstream lMsg;
+ lMsg << theEncoding << ": unsupported encoding";
+ throwError("CB0006", lMsg.str().c_str());
+ }
+ }
+ else if (lStrKey == "stale")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ String lString = lValue.getStringValue();
+ if (lString == "false")
+ {
+ theStaleOption ="stale=false";
+ }
+ else if (lString == "ok")
+ {
+ theStaleOption ="stale=ok";
+ }
+ else if (lString == "update_after")
+ {
+ theStaleOption ="stale=update_after";
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << "=" << lString << ": option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ else if (lStrKey == "limit")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ try
+ {
+ int lLimit = lValue.getIntValue();
+ theLimitOption = "limit=" + lLimit;
+ }
+ catch (ZorbaException& e)
+ {
+ throwError("CB0009", " limit option must be an integer value");
+ }
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ lIter->close();
+}
+
+void
+ CouchbaseFunction::GetOptions::setOptions(Item& aOptions)
+{
+ if (!aOptions.isJSONItem())
+ isNotJSONError();
+
+ Iterator_t lIter = aOptions.getObjectKeys();
+ Item lItem;
+ lIter->open();
+ while (lIter->next(lItem))
+ {
+ String lStrKey = lItem.getStringValue();
+ std::transform(
+ lStrKey.begin(), lStrKey.end(),
+ lStrKey.begin(), tolower);
+ if (lStrKey == "type")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ String lStrValue = lValue.getStringValue();
+ std::transform(
+ lStrValue.begin(), lStrValue.end(),
+ lStrValue.begin(), tolower);
+ if (lStrValue == "text")
+ {
+ theType = LCB_TEXT;
+ }
+ else if (lStrValue == "binary")
+ {
+ theType = LCB_BASE64;
+ }
+ }
+ else if (lStrKey == "expiration-time")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ try
+ {
+ theExpTime = lValue.getUnsignedIntValue();
+ }
+ catch (ZorbaException& e)
+ {
+ throwError("CB0009", " expiration-time option must be an integer value");
+ }
+ }
+ else if (lStrKey == "encoding")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ theEncoding = lValue.getStringValue();
+ if (!transcode::is_supported(theEncoding.c_str()))
+ {
+ std::ostringstream lMsg;
+ lMsg << theEncoding << ": unsupported encoding";
+ throwError("CB0006", lMsg.str().c_str());
+ }
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ lIter->close();
+
+}
+
+void
+CouchbaseFunction::PutOptions::setOptions(Item& aOptions)
+{
+ if (!aOptions.isJSONItem())
+ isNotJSONError();
+
+ Iterator_t lIter = aOptions.getObjectKeys();
+ Item lItem;
+ lIter->open();
+ while (lIter->next(lItem))
+ {
+ String lStrKey = lItem.getStringValue();
+ std::transform(
+ lStrKey.begin(), lStrKey.end(),
+ lStrKey.begin(), tolower);
+ if (lStrKey == "operation")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ String lStrValue = lValue.getStringValue();
+ std::transform(
+ lStrValue.begin(), lStrValue.end(),
+ lStrValue.begin(), tolower);
+ if (lStrValue == "add")
+ {
+ theOperation = LCB_ADD;
+ }
+ else if (lStrValue == "replace")
+ {
+ theOperation = LCB_REPLACE;
+ }
+ else if (lStrValue == "set")
+ {
+ theOperation = LCB_SET;
+ }
+ else if (lStrValue == "append")
+ {
+ theOperation = LCB_APPEND;
+ }
+ else if (lStrValue == "prepend")
+ {
+ theOperation = LCB_PREPEND;
+ }
+ }
+ else if (lStrKey == "type")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ String lStrValue = lValue.getStringValue();
+ if (lStrValue == "text")
+ {
+ theType = LCB_TEXT;
+ }
+ else if (lStrValue == "binary")
+ {
+ theType = LCB_BASE64;
+ }
+ }
+ else if (lStrKey == "expiration-time")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+
+ try
+ {
+ theExpTime = lValue.getUnsignedIntValue();
+ }
+ catch (ZorbaException& e)
+ {
+ throwError("CB0009", " expiration-time option must be an integer value");
+ }
+ }
+ else if (lStrKey == "encoding")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ theEncoding = lValue.getStringValue();
+ if (!transcode::is_supported(theEncoding.c_str()))
+ {
+ std::ostringstream lMsg;
+ lMsg << theEncoding << ": unsupported encoding";
+ throwError("CB0006", lMsg.str().c_str());
+ }
+ }
+ else if (lStrKey == "wait")
+ {
+ Item lValue = aOptions.getObjectValue(lStrKey);
+ String lStrValue = lValue.getStringValue();
+ std::transform(
+ lStrValue.begin(), lStrValue.end(),
+ lStrValue.begin(), tolower);
+ if (lStrValue == "persist")
+ {
+ theWaitType = CB_WAIT_PERSIST;
+ }
+ else if (lStrValue == "false")
+ {
+ theWaitType = CB_WAIT_FALSE;
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << "=" << lStrValue << " : option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ lIter->close();
+
+}
+/*******************************************************************************
+ ******************************************************************************/
+
+InstanceMap::InstanceMap()
+{
+ InstanceMap::instanceMap = new InstanceMap_t();
+}
+
+bool
+InstanceMap::storeInstance(const String& aKeyName, lcb_t aInstance)
+{
+ std::pair<InstanceMap_t::iterator, bool> ret;
+ ret = instanceMap->insert(std::pair<String, lcb_t>(aKeyName, aInstance));
+ return ret.second;
+}
+
+lcb_t
+InstanceMap::getInstance(const String& aKeyName)
+{
+ InstanceMap::InstanceMap_t::iterator lIter = instanceMap->find(aKeyName);
+
+ if (lIter == instanceMap->end())
+ return NULL;
+
+ lcb_t lInstance = lIter->second;
+
+ return lInstance;
+}
+
+bool
+InstanceMap::deleteInstance(const String& aKeyName)
+{
+ InstanceMap::InstanceMap_t::iterator lIter = instanceMap->find(aKeyName);
+
+ if (lIter == instanceMap->end())
+ return false;
+
+ lcb_destroy(lIter->second);
+
+ instanceMap->erase(lIter);
+
+ return true;
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+ConnectFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ DynamicContext* lDctx = const_cast<DynamicContext*>(aDctx);
+
+ InstanceMap* lInstanceMap;
+ if (!(lInstanceMap = dynamic_cast<InstanceMap*>(lDctx->getExternalFunctionParameter("couchbaseInstanceMap"))))
+ {
+ lInstanceMap = new InstanceMap();
+ lDctx->addExternalFunctionParameter("couchbaseInstanceMap", lInstanceMap);
+ }
+
+ Item lHost;
+ Item lUserName;
+ Item lPassword;
+ Item lBucket;
+
+ Item lOptions = getOneItemArgument(aArgs, 0);
+
+ if (lOptions.isJSONItem())
+ {
+ Iterator_t lKeys = lOptions.getObjectKeys();
+ lKeys->open();
+ Item lKey;
+ while (lKeys->next(lKey))
+ {
+ String lStrKey = lKey.getStringValue();
+ if (lStrKey == "host")
+ {
+ lHost = lOptions.getObjectValue(lStrKey);
+ }
+ else if (lStrKey == "username")
+ {
+ lUserName = lOptions.getObjectValue(lStrKey);
+ }
+ else if (lStrKey == "password")
+ {
+ lPassword = lOptions.getObjectValue(lStrKey);
+ }
+ else if (lStrKey == "bucket")
+ {
+ lBucket = lOptions.getObjectValue(lStrKey);
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ lKeys->close();
+ }
+ else
+ {
+ isNotJSONError();
+ }
+
+ struct lcb_create_st create_options;
+ memset(&create_options, 0, sizeof(create_options));
+
+ if (lHost.isNull())
+ throwError ("CB0001", "Missing declaration of the couchbase server host");
+ String lStrHost = lHost.getStringValue();
+ create_options.v.v0.host = lStrHost.c_str();
+
+ if (lBucket.isNull())
+ throwError ("CB0001", "Missing declaration of the couchbase bucket");
+ String lStrBucket = lBucket.getStringValue();
+ create_options.v.v0.bucket = lStrBucket.c_str();
+
+ if (!lUserName.isNull())
+ {
+ String lStrUserName = lUserName.getStringValue();
+ if (lStrUserName != "null")
+ create_options.v.v0.user = lStrUserName.c_str();
+ }
+
+ if (!lPassword.isNull())
+ {
+ String lStrPassword = lPassword.getStringValue();
+ if (lStrPassword != "null")
+ create_options.v.v0.passwd = lStrPassword.c_str();
+ }
+
+ lcb_t lInstance;
+ lcb_error_t lError;
+
+ lError = lcb_create(&lInstance, &create_options);
+ if (lError != LCB_SUCCESS)
+ {
+ throwError("LCB0001", "Error creating a libcouchbase Instance");
+ lcb_strerror(NULL, lError);
+ }
+
+ //Connect to couchbase
+ if ((lError = lcb_connect(lInstance)) != LCB_SUCCESS)
+ {
+ throwError("LCB0001", "Error connecting to the couchbase server");
+ lcb_strerror(NULL, lError);
+ }
+
+ lcb_wait(lInstance);
+
+ uuid lUUID;
+ uuid::create(&lUUID);
+
+ std::stringstream lStream;
+ lStream << lUUID;
+
+ String lStrUUID = lStream.str();
+
+ lInstanceMap->storeInstance(lStrUUID, lInstance);
+
+ return ItemSequence_t(new SingletonItemSequence(CouchbaseModule::getItemFactory()->createAnyURI(lStrUUID)));
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+RemoveFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ Iterator_t lKeys = getIterArgument(aArgs, 1);
+
+
+ lcb_error_t lError;
+ Item lKey;
+ lKeys->open();
+ while (lKeys->next(lKey))
+ {
+ lcb_remove_cmd_st lCmd;
+ String lStrKey = lKey.getStringValue();
+ lCmd.v.v0.key = lStrKey.c_str();
+ lCmd.v.v0.nkey = lStrKey.size();
+ lcb_remove_cmd_st *lCommand[1] = {&lCmd};
+
+ lError = lcb_remove(lInstance, NULL, 1, lCommand);
+ if (lError != LCB_SUCCESS)
+ {
+ CouchbaseFunction::libCouchbaseError (lInstance, lError);
+ }
+
+ lcb_wait(lInstance);
+ }
+ lKeys->close();
+
+ return ItemSequence_t(new EmptySequence());
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+void
+CouchbaseFunction::GetItemSequence::get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp)
+{
+ if (error != LCB_SUCCESS)
+ {
+ libCouchbaseError (instance, error);
+ }
+
+ GetOptions* lRes = (GetOptions*)cookie;
+
+ lcb_storage_type_t lType = lRes->getGetType();
+
+ if (lType == LCB_TEXT)
+ {
+ String lEncoding = lRes->getEncoding();
+ String lTmp((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
+ if (lEncoding != "" && transcode::is_necessary(lEncoding.c_str()))
+ {
+ transcode::stream<std::istringstream> lTranscoder(lEncoding.c_str(), lTmp.c_str());
+ lTmp.clear();
+
+ char buf[1024];
+ while (lTranscoder.good())
+ {
+ lTranscoder.read(buf, 1024);
+ lTmp.append(buf, lTranscoder.gcount());
+ }
+ }
+ lRes->theItem = CouchbaseModule::getItemFactory()->createString(lTmp);
+ }
+ else if (lType == LCB_BASE64)
+ {
+ //unsigned char lData[resp->v.v0.nbytes];
+ //size_t lLen = resp->v.v0.nbytes;
+ //memcpy(lData, resp->v.v0.bytes, lLen);
+ lRes->theItem = CouchbaseModule::getItemFactory()->createBase64Binary((const unsigned char*)resp->v.v0.bytes, resp->v.v0.nbytes);
+ }
+ else
+ {
+ throwError ("CB0004", "The requested collection has a not recognized type");
+ }
+}
+
+void
+CouchbaseFunction::GetItemSequence::GetIterator::open()
+{
+ lcb_set_get_callback(theInstance, GetItemSequence::get_callback);
+ theKeys->open();
+}
+
+void
+CouchbaseFunction::GetItemSequence::GetIterator::close()
+{
+ theKeys->close();
+}
+
+bool
+CouchbaseFunction::GetItemSequence::GetIterator::next(Item& aItem)
+{
+ Item lKey;
+ if (theKeys->next(lKey))
+ {
+ GetOptions* lValue = &theOptions;
+ String lStrKey = lKey.getStringValue();
+ lcb_get_cmd_st lGet;
+ lGet.v.v0.key = lStrKey.c_str();
+ lGet.v.v0.nkey = lStrKey.size();
+ unsigned int lExpTime = theOptions.getExpTime();
+ if (lExpTime > 0)
+ {
+ lGet.v.v0.exptime = lExpTime;
+ }
+
+ lcb_get_cmd_st *lCommand[1] = {&lGet};
+
+ theError = lcb_get(theInstance, lValue, 1, lCommand);
+
+ if (theError != LCB_SUCCESS)
+ {
+ libCouchbaseError (theInstance, theError);
+ }
+ lcb_wait(theInstance);
+
+ if (lValue->theItem.isNull())
+ return false;
+
+ aItem = lValue->theItem;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+GetTextFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ Iterator_t lKeys = getIterArgument(aArgs, 1);
+ GetOptions lOptions(LCB_TEXT);
+ if (aArgs.size() > 2)
+ {
+ Item lOptionsArg = getOneItemArgument(aArgs, 2);
+ lOptions.setOptions(lOptionsArg);
+ }
+
+ return ItemSequence_t(new GetItemSequence(lInstance,lKeys, lOptions));
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+GetBinaryFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ Iterator_t lKeys = getIterArgument(aArgs, 1);
+ GetOptions lOptions(LCB_BASE64);
+ if (aArgs.size() > 2)
+ {
+ Item lOptionsArg = getOneItemArgument(aArgs, 2);
+ lOptions.setOptions(lOptionsArg);
+ }
+
+ return ItemSequence_t(new GetItemSequence(lInstance,lKeys, lOptions));
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+void CouchbaseFunction::observe_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_observe_resp_t *resp)
+{
+ if (error != LCB_SUCCESS)
+ {
+ libCouchbaseError (instance, error);
+ }
+
+ PutOptions* lWait = (PutOptions*) cookie;
+ //verify is coming from the master
+ if (resp->v.v0.from_master > 0)
+ {
+ lcb_observe_t lStatus = resp->v.v0.status;if (lStatus == LCB_OBSERVE_NOT_FOUND)
+ {
+ throwError("CB0011", "Variable stored not found.");
+ }
+ //check for flag of persisntancy
+ lWait->setWaiting(lStatus & LCB_OBSERVE_PERSISTED?false:true);
+ }
+}
+
+void CouchbaseFunction::put (lcb_t aInstance, Iterator_t aKeys, Iterator_t aValues, PutOptions aOptions)
+{
+ lcb_error_t lError;
+ Item lKey;
+ Item lValue;
+
+ aKeys->open();
+ aValues->open();
+ while (aKeys->next(lKey))
+ {
+ if (!aValues->next(lValue))
+ throwError("CB0005", "The number of key/value's on the save function is not the same.");
+
+ String lStrKey = lKey.getStringValue();
+
+ //TODO: add more options
+ lcb_store_cmd_st lPut;
+ lPut.v.v0.key = lStrKey.c_str();
+ lPut.v.v0.nkey = lStrKey.size();
+
+ const char* lData;
+ size_t lLen = 0;
+ lPut.v.v0.datatype = aOptions.getOperationType();
+ String lStrValue;
+ if (lPut.v.v0.datatype == LCB_TEXT)
+ {
+ String lEncoding = aOptions.getEncoding();
+ lStrValue = lValue.getStringValue();
+ if (lEncoding != "" && transcode::is_necessary(lEncoding.c_str()))
+ {
+ std::stringstream lStream;
+ transcode::attach(lStream, lEncoding.c_str());
+ lStream << lStrValue.c_str();
+ lStrValue.clear();
+ lStrValue = lStream.str();
+ lData = lStrValue.c_str();
+ lLen = lStrValue.size();
+ }
+ else
+ {
+ lData = lStrValue.c_str();
+ lLen = lStrValue.size();
+ }
+ }
+ else if (lPut.v.v0.datatype == LCB_BASE64)
+ {
+ lData = lValue.getBase64BinaryValue(lLen);
+ }
+ else
+ {
+ throwError ("CB0004", " Storing type not recognized");
+ }
+
+ lPut.v.v0.bytes = lData;
+ lPut.v.v0.nbytes = lLen;
+ lPut.v.v0.operation = aOptions.getOperation();
+ unsigned int lExpTime = aOptions.getExmpTime();
+ if (lExpTime > 0)
+ {
+ lPut.v.v0.exptime = lExpTime;
+ }
+
+ lcb_store_cmd_st *lCommands[1] = {&lPut};
+ lError = lcb_store(aInstance, NULL, 1, lCommands);
+
+ if (lError != LCB_SUCCESS)
+ {
+ libCouchbaseError (aInstance, lError);
+ }
+ //Wait for store
+ lcb_wait(aInstance);
+ //Check if wait for disk
+ if (aOptions.getWaitType() != CB_WAIT_FALSE)
+ {
+ lcb_set_observe_callback(aInstance, observe_callback);
+ PutOptions* lOptions = &aOptions;
+ do {
+ lcb_observe_cmd_t lObserve;
+ lObserve.version = 0;
+ lObserve.v.v0.key = lStrKey.c_str();
+ lObserve.v.v0.nkey = lStrKey.size();
+ lcb_observe_cmd_t* lCommands[1] = { &lObserve };
+ lcb_observe(aInstance, lOptions, 1, lCommands);
+ lcb_wait(aInstance);
+ }while(lOptions->isWaiting());
+ }
+ }
+
+ if (aValues->next(lValue))
+ throwError("CB0005", "The number of key/value's on the save function is not the same.");
+
+ aKeys->close();
+ aValues->close();
+
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+PutTextFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = CouchbaseFunction::getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ Iterator_t lKeys = getIterArgument(aArgs, 1);
+ Iterator_t lValues = getIterArgument(aArgs, 2);
+
+ PutOptions lOptions(LCB_TEXT);
+ if (aArgs.size() > 3)
+ {
+ Item lOptionsArg = getOneItemArgument(aArgs, 3);
+ lOptions.setOptions(lOptionsArg);
+ }
+
+ put(lInstance, lKeys, lValues, lOptions);
+ return ItemSequence_t(new EmptySequence());
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+PutBinaryFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = CouchbaseFunction::getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ Iterator_t lKeys = getIterArgument(aArgs, 1);
+ Iterator_t lValues = getIterArgument(aArgs, 2);
+
+ PutOptions lOptions(LCB_BASE64);
+ if (aArgs.size() > 3)
+ {
+ Item lOptionsArg = getOneItemArgument(aArgs, 3);
+ lOptions.setOptions(lOptionsArg);
+ }
+
+ put(lInstance, lKeys, lValues, lOptions);
+ return ItemSequence_t(new EmptySequence());
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+FlushFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = CouchbaseFunction::getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ lcb_error_t lError;
+
+
+ lcb_flush_cmd_st lFlush;
+ lFlush.version=0;
+ lcb_flush_cmd_st* lCommand[] = {&lFlush};
+
+ lError = lcb_flush(lInstance, NULL, 1, lCommand);
+ if (lError != LCB_SUCCESS)
+ {
+ std::stringstream lErrorMessage;
+ lErrorMessage << "Flush error : " << lcb_strerror(lInstance, lError);
+ throwError("LCB0003", lErrorMessage.str().c_str());
+ }
+
+ lcb_wait(lInstance);
+
+ return ItemSequence_t(new EmptySequence());
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+TouchFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+ Iterator_t lKeys = getIterArgument(aArgs, 1);
+ Item lExp = getOneItemArgument(aArgs, 2);
+ unsigned int lInt;
+ try
+ {
+ lInt = lExp.getUnsignedIntValue();
+ }
+ catch (ZorbaException& e)
+ {
+ throwError("CB0009", " expiration-time option must be an integer value");
+ }
+ lcb_error_t lError;
+ Item lKey;
+ lKeys->open();
+ while (lKeys->next(lKey))
+ {
+ lcb_touch_cmd_t lCmd;
+ String lStrKey = lKey.getStringValue();
+ lCmd.v.v0.key = lStrKey.c_str();
+ lCmd.v.v0.nkey = lStrKey.size();
+ lCmd.v.v0.exptime = lInt;
+ lcb_touch_cmd_t *lCommand[1] = {&lCmd};
+
+ lError = lcb_touch(lInstance, NULL, 1, lCommand);
+ if (lError != LCB_SUCCESS)
+ {
+ libCouchbaseError (lInstance, lError);
+ }
+
+ lcb_wait(lInstance);
+ }
+ lKeys->close();
+
+ return ItemSequence_t(new EmptySequence());
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+static void streamReleaser(std::istream* aStream)
+{
+ delete aStream;
+}
+
+void CouchbaseFunction::ViewItemSequence::view_callback( lcb_http_request_t request, lcb_t instance, const void* cookie, lcb_error_t error, const lcb_http_resp_t* resp)
+{
+ if (error != LCB_SUCCESS)
+ {
+ libCouchbaseError (instance, error);
+ }
+
+ ViewOptions* lRes = (ViewOptions*) cookie;
+
+ String lEncoding = lRes->getEncoding();
+ if (resp->v.v0.nbytes > 0)
+ {
+ String lTmp = String((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
+
+ if (transcode::is_necessary(lEncoding.c_str()))
+ {
+ transcode::stream<std::istringstream> lTranscoder(lEncoding.c_str(), lTmp.c_str());
+ lTmp.clear();
+
+ char buf[1024];
+ while (lTranscoder.good())
+ {
+ lTranscoder.read(buf, 1024);
+ lTmp.append(buf, lTranscoder.gcount());
+ }
+ }
+
+ if(!lRes->theStream)
+ {
+ lRes->theStream = new std::unique_ptr<std::stringstream>(new std::stringstream(""));
+ }
+
+ *(lRes->theStream->get()) << lTmp.c_str();
+
+ }
+}
+
+void
+CouchbaseFunction::ViewItemSequence::ViewIterator::open()
+{
+ lcb_set_http_data_callback(theInstance, ViewItemSequence::view_callback);
+ thePaths->open();
+}
+
+void
+CouchbaseFunction::ViewItemSequence::ViewIterator::close()
+{
+ thePaths->close();
+}
+
+bool
+CouchbaseFunction::ViewItemSequence::ViewIterator::next(Item& aItem)
+{
+ Item lPath;
+ if (thePaths->next(lPath))
+ {
+ ViewOptions* lOptions = &theOptions;
+ String lPathOptions = lOptions->getPathOptions();
+ String lPathString = lPath.getStringValue();
+ if (lPathOptions != "")
+ {
+ lPathString.append(lPathOptions);
+ }
+ lcb_http_request_t lReq;
+ lcb_http_cmd_t lCmd;
+ lCmd.version = 0;
+ lCmd.v.v0.path = lPathString.c_str();
+ lCmd.v.v0.npath = lPathString.size();
+ lCmd.v.v0.body = NULL;
+ lCmd.v.v0.nbody = 0;
+ lCmd.v.v0.method = LCB_HTTP_METHOD_GET;
+ lCmd.v.v0.chunked = 1;
+ lCmd.v.v0.content_type = "application/json";
+ lcb_error_t err = lcb_make_http_request(theInstance, lOptions, LCB_HTTP_TYPE_VIEW, &lCmd, &lReq);
+ if (err != LCB_SUCCESS)
+ {
+ libCouchbaseError (theInstance, err);
+ }
+
+ lcb_wait(theInstance);
+
+ if (lOptions->theStream)
+ aItem = CouchbaseModule::getItemFactory()->createStreamableString(*lOptions->theStream->release(), &streamReleaser);
+
+ if (aItem.isNull())
+ return false;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+
+zorba::ItemSequence_t
+ViewFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+
+ Iterator_t lPaths = getIterArgument(aArgs, 1);
+ ViewOptions lOptions;
+
+ if (aArgs.size() > 2)
+ {
+ Item lOptionsArg = getOneItemArgument(aArgs, 2);
+ lOptions.setOptions(lOptionsArg);
+ }
+
+ return ItemSequence_t(new ViewItemSequence(lInstance, lPaths, lOptions));
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+void DeleteViewFunction::delete_view_callback(lcb_http_request_t request, lcb_t instance, const void* cookie, lcb_error_t error, const lcb_http_resp_t* resp)
+{
+ if (resp->v.v0.status == 401)
+ {
+ std::ostringstream lMsg;
+ lMsg << "The item requested was not available using the supplied authorization, or authorization was not supplied.";
+ throwError("CB0012", lMsg.str().c_str());
+ } else if (resp->v.v0.status == 404)
+ {
+ std::ostringstream lMsg;
+ lMsg << "The requested content could not be found. The returned content will include further information, as a JSON object, if available.";
+ throwError("CB0012", lMsg.str().c_str());
+ }
+ else if (resp->v.v0.status > 400)
+ {
+ std::ostringstream lMsg;
+ lMsg << "HTTP communication with couchbase server throwed error " << (int)resp->v.v0.status << ".";
+ throwError("CB0012", lMsg.str().c_str());
+ }
+}
+
+zorba::ItemSequence_t
+DeleteViewFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+
+ Iterator_t lDocNames = getIterArgument(aArgs, 1);
+ Item lDoc;
+ lDocNames->open();
+ while(lDocNames->next(lDoc))
+ {
+ lcb_set_http_complete_callback(lInstance, DeleteViewFunction::delete_view_callback);
+ String lPath = "_design/" + lDoc.getStringValue();
+ lcb_http_request_t req;
+ lcb_http_cmd_t cmd;
+ cmd.version = 0;
+ cmd.v.v0.path = lPath.c_str();
+ cmd.v.v0.npath = lPath.size();
+ cmd.v.v0.body = NULL;
+ cmd.v.v0.nbody = 0;
+ cmd.v.v0.method = LCB_HTTP_METHOD_DELETE;
+ cmd.v.v0.chunked = 0;
+ cmd.v.v0.content_type = "application/json";
+ lcb_error_t err = lcb_make_http_request(lInstance, NULL,
+ LCB_HTTP_TYPE_VIEW, &cmd, &req);
+
+ if (err != LCB_SUCCESS)
+ libCouchbaseError (lInstance, err);
+
+ lcb_wait(lInstance);
+ }
+ lDocNames->close();
+
+ return ItemSequence_t(new EmptySequence());
+}
+
+/*******************************************************************************
+ ******************************************************************************/
+void CreateViewFunction::create_view_callback(lcb_http_request_t request, lcb_t instance, const void* cookie, lcb_error_t error, const lcb_http_resp_t* resp)
+{
+ if (resp->v.v0.status == 401)
+ {
+ std::ostringstream lMsg;
+ lMsg << "The item requested was not available using the supplied authorization, or authorization was not supplied.";
+ throwError("CB0012", lMsg.str().c_str());
+ } else if (resp->v.v0.status == 404)
+ {
+ std::ostringstream lMsg;
+ lMsg << "The requested content could not be found. The returned content will include further information, as a JSON object, if available.";
+ throwError("CB0012", lMsg.str().c_str());
+ }
+ else if (resp->v.v0.status > 400)
+ {
+ std::ostringstream lMsg;
+ lMsg << "HTTP communication with couchbase server throwed error " << (int)resp->v.v0.status << ".";
+ throwError("CB0012", lMsg.str().c_str());
+ }
+}
+
+zorba::ItemSequence_t
+CreateViewFunction::evaluate(
+ const Arguments_t& aArgs,
+ const zorba::StaticContext* aSctx,
+ const zorba::DynamicContext* aDctx) const
+{
+ String lInstanceID = getOneStringArgument(aArgs, 0);
+ lcb_t lInstance = getInstance(aDctx, lInstanceID);
+
+ String lDocName = getOneStringArgument(aArgs, 1);
+ String lPath = "_design/" + lDocName;
+
+ String lBody = "{\"views\": {";
+ Iterator_t lViewNames = getIterArgument(aArgs, 2);
+ Item lView;
+
+ std::vector<Item> lResult;
+
+ Iterator_t lOptions;
+ if (aArgs.size() > 3)
+ {
+ lOptions = getIterArgument(aArgs, 3);
+ Item lOption;
+ lOptions->open();
+ lViewNames->open();
+ bool lIsFirstView = true;
+ while (lViewNames->next(lView))
+ {
+ if (!lOptions->next(lOption))
+ throwError("CB0005", "The number of options is not the same as the number of views.");
+
+ //variables used to form the body
+ String lBodyKey;
+ String lBodyValues;
+ String lBodyFunction;
+
+ String lViewName = lView.getStringValue();
+ if (lOption.isJSONItem())
+ {
+ Iterator_t lKeys = lOption.getObjectKeys();
+ lKeys->open();
+ Item lKey;
+ while (lKeys->next(lKey))
+ {
+ String lStrKey = lKey.getStringValue();
+ std::transform(
+ lStrKey.begin(), lStrKey.end(),
+ lStrKey.begin(), tolower);
+ if (lStrKey == "key")
+ {
+ Item lValue = lOption.getObjectValue(lStrKey);
+ if (lValue.isJSONItem())
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": value must be of type string.";
+ throwError("CB0010", lMsg.str().c_str());
+ }
+ String lStrValue = lValue.getStringValue();
+ std::transform(
+ lStrValue.begin(), lStrValue.end(),
+ lStrValue.begin(), tolower);
+ lBodyKey = lStrValue;
+ }
+ else if (lStrKey == "values")
+ {
+ Item lValue = lOption.getObjectValue(lStrKey);
+ if (lValue.isJSONItem())
+ {
+ lBodyValues = "[";
+ bool lIsFirstView = true;
+ int lSize = lValue.getArraySize()+1;
+ for (int i = 1; i < lSize; i++)
+ {
+ Item lArrValue = lValue.getArrayValue(i);
+ String lStrArrValue = lArrValue.getStringValue();
+ std::transform(
+ lStrArrValue.begin(), lStrArrValue.end(),
+ lStrArrValue.begin(), tolower);
+
+ if (lIsFirstView)
+ lIsFirstView = false;
+ else
+ lBodyValues += ", ";
+
+ lBodyValues += lStrArrValue;
+ }
+ lBodyValues += "]";
+ }
+ else
+ {
+ String lStrValue = lValue.getStringValue();
+ std::transform(
+ lStrValue.begin(), lStrValue.end(),
+ lStrValue.begin(), tolower);
+ lBodyValues = lStrValue;
+ }
+ }
+ else if (lStrKey == "function")
+ {
+ Item lValue = lOption.getObjectValue(lStrKey);
+ if (lValue.isJSONItem())
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": value must be of type string.";
+ throwError("CB0010", lMsg.str().c_str());
+ }
+ String lStrValue = lValue.getStringValue();
+ std::transform(
+ lStrValue.begin(), lStrValue.end(),
+ lStrValue.begin(), tolower);
+ lBodyFunction = lStrValue;
+ }
+ else
+ {
+ std::ostringstream lMsg;
+ lMsg << lStrKey << ": option not supported";
+ throwError("CB0007", lMsg.str().c_str());
+ }
+ }
+ lKeys->close();
+ }
+ if (lIsFirstView)
+ lIsFirstView = false;
+ else
+ lBody += " , ";
+ if (lBodyFunction.size() < 1)
+ {
+ if (lBodyKey.size() < 1)
+ lBodyKey = "null";
+ if (lBodyValues.size() <1)
+ lBodyValues = "null";
+ lBodyFunction = "function(doc, meta) { emit("+lBodyKey+", "+lBodyValues+");}";
+ }
+ lBody += "\"" + lViewName + "\": {\"map\": \""+lBodyFunction+"\"}";
+
+ String lStrRes = "_design/" + lDocName + "/_view/" + lViewName;
+ Item lRes = CouchbaseModule::getItemFactory()->createString(lStrRes);
+ lResult.push_back(lRes);
+
+ }
+ if (lOptions->next(lOption))
+ throwError("CB0005", "The number of options is not the same as the number of views.");
+ lViewNames->close();
+ lOptions->close();
+ lBody += "}}";
+ }
+ else
+ {
+ bool lIsFirstView = true;
+ lViewNames->open();
+ while (lViewNames->next(lView))
+ {
+ if (lIsFirstView)
+ lIsFirstView = false;
+ else
+ lBody += " , ";
+ String lViewName = lView.getStringValue();
+ lBody += "\"" + lViewName + "\": {\"map\": \"function(doc, meta) { emit(meta.id, null);}\"}";
+
+ String lStrRes = "_design/" + lDocName + "/_view/" + lViewName;
+ Item lRes = CouchbaseModule::getItemFactory()->createString(lStrRes);
+ lResult.push_back(lRes);
+
+ }
+ lViewNames->close();
+ lBody += "}}";
+ }
+ lcb_set_http_complete_callback(lInstance, CreateViewFunction::create_view_callback);
+ lcb_http_request_t lReq;
+ lcb_http_cmd_t lCmd;
+ lCmd.v.v0.path = lPath.c_str();
+ lCmd.v.v0.npath = lPath.size();
+ lCmd.v.v0.content_type = "application/json";
+ lCmd.v.v0.method = LCB_HTTP_METHOD_PUT;
+ lCmd.v.v0.body = lBody.c_str();
+ lCmd.v.v0.nbody = lBody.size();
+ lCmd.v.v0.chunked = 0;
+ lcb_error_t err = lcb_make_http_request(lInstance, NULL, LCB_HTTP_TYPE_VIEW, &lCmd, &lReq);
+
+ if (err != LCB_SUCCESS)
+ libCouchbaseError (lInstance, err);
+
+ lcb_wait(lInstance);
+
+ return ItemSequence_t(new VectorItemSequence(lResult));
+}
+
+
+} /*namespace couchbase*/ } /*namespace zorba*/
+
+
+#ifdef WIN32
+# define DLL_EXPORT __declspec(dllexport)
+#else
+# define DLL_EXPORT __attribute__ ((visibility("default")))
+#endif
+
+extern "C" DLL_EXPORT zorba::ExternalModule* createModule() {
+ return new zorba::couchbase::CouchbaseModule();
+}
=== added file 'src/couchbase.xq.src/couchbase.h'
--- src/couchbase.xq.src/couchbase.h 1970-01-01 00:00:00 +0000
+++ src/couchbase.xq.src/couchbase.h 2013-04-29 18:32:40 +0000
@@ -0,0 +1,628 @@
+/*
+ * Copyright 2012 The FLWOR Foundation.
+ *
+ * Licensed 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.
+ */
+
+#ifndef _COM_ZORBA_WWW_MODULES_COUCHBASE_H_
+#define _COM_ZORBA_WWW_MODULES_COUCHBASE_H_
+
+#include <map>
+
+#include <zorba/zorba.h>
+#include <zorba/external_module.h>
+#include <zorba/function.h>
+#include <zorba/dynamic_context.h>
+
+#define COUCHBASE_MODULE_NAMESPACE "http://www.zorba-xquery.com/modules/couchbase"
+
+namespace zorba { namespace couchbase {
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class CouchbaseModule : public ExternalModule {
+ protected:
+ class ltstr
+ {
+ public:
+ bool operator()(const String& s1, const String& s2) const
+ {
+ return s1.compare(s2) < 0;
+ }
+ };
+
+ typedef std::map<String, ExternalFunction*, ltstr> FuncMap_t;
+ FuncMap_t theFunctions;
+
+ public:
+
+ virtual ~CouchbaseModule();
+
+ virtual String
+ getURI() const { return COUCHBASE_MODULE_NAMESPACE; }
+
+ virtual zorba::ExternalFunction*
+ getExternalFunction(const String& localName);
+
+ virtual void destroy();
+
+ static ItemFactory*
+ getItemFactory()
+ {
+ return Zorba::getInstance(0)->getItemFactory();
+ }
+
+ static XmlDataManager*
+ getXmlDataManager()
+ {
+ return Zorba::getInstance(0)->getXmlDataManager();
+ }
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class CouchbaseFunction : public ContextualExternalFunction
+{
+ protected:
+
+ typedef enum
+ {
+ LCB_TEXT = 0x01,
+ LCB_JSON = 0x02,
+ LCB_XML = 0x03,
+ LCB_BASE64 = 0x04
+
+ } lcb_storage_type_t;
+
+ typedef enum
+ {
+ CB_WAIT_FALSE = 0x00,
+ CB_WAIT_PERSIST = 0x01,
+ CB_WAIT_REPLICATE = 0x02
+ } cb_wait_type_t;
+
+ class ViewOptions
+ {
+ protected:
+ String theEncoding;
+ String thePath;
+ String theStaleOption;
+ String theLimitOption;
+
+ public:
+ std::unique_ptr<std::stringstream>* theStream;
+
+ ViewOptions() : theEncoding("UTF-8"), thePath(""), theStaleOption(""), theLimitOption("") { theStream = NULL; }
+
+ ViewOptions(String& aPath) : theEncoding("UTF-8"), thePath(aPath) {}
+
+ void setOptions(Item& aOptions);
+
+ ~ViewOptions() { if(theStream) delete theStream; }
+
+ String getEncoding() { return theEncoding; }
+
+ String getPath() { return thePath; }
+
+ String getPathOptions();
+ };
+
+ class GetOptions
+ {
+ protected:
+ lcb_storage_type_t theType;
+ unsigned int theExpTime;
+ String theEncoding;
+
+ public:
+ Item theItem;
+
+ GetOptions() : theType(LCB_JSON), theExpTime(0), theEncoding("") {}
+
+ GetOptions(lcb_storage_type_t aType) : theType(aType), theExpTime(0) {}
+
+ void setOptions(Item& aOptions);
+
+ ~GetOptions() {}
+
+ lcb_storage_type_t getGetType() { return theType; }
+
+ unsigned int getExpTime() { return theExpTime; }
+
+ String getEncoding() { return theEncoding; }
+
+ };
+
+ class PutOptions
+ {
+ protected:
+ lcb_storage_t theOperation;
+ lcb_storage_type_t theType;
+ unsigned int theExpTime;
+ String theEncoding;
+ cb_wait_type_t theWaitType;
+ bool theIsWaiting;
+
+ public:
+
+ PutOptions() : theOperation(LCB_ADD), theType(LCB_JSON), theExpTime(0), theEncoding(""), theWaitType(CB_WAIT_FALSE), theIsWaiting(false){ }
+
+ PutOptions(lcb_storage_type_t aType) : theOperation(LCB_SET), theType(aType), theExpTime(0), theWaitType(CB_WAIT_FALSE), theIsWaiting(false) { }
+
+ void setOptions(Item& aOptions);
+
+ ~PutOptions() {}
+
+ lcb_storage_t getOperation() { return theOperation; }
+
+ lcb_storage_type_t getOperationType() { return theType; }
+
+ unsigned int getExmpTime() { return theExpTime; }
+
+ String getEncoding() { return theEncoding; }
+
+ cb_wait_type_t getWaitType() { return theWaitType; }
+
+ bool isWaiting() { return theIsWaiting; }
+
+ void setWaiting(bool isWaiting) { theIsWaiting = isWaiting; }
+ };
+
+ class ViewItemSequence : public ItemSequence
+ {
+ protected:
+ lcb_t theInstance;
+ Iterator_t thePaths;
+ ViewOptions theOptions;
+
+ public:
+
+ class ViewIterator : public Iterator
+ {
+ protected:
+ lcb_t theInstance;
+ Iterator_t thePaths;
+ lcb_error_t theError;
+ ViewOptions theOptions;
+
+ public:
+ ViewIterator(lcb_t& aInstance, Iterator_t& aPaths, ViewOptions& aOptions)
+ : theInstance(aInstance),
+ thePaths(aPaths),
+ theOptions(aOptions){}
+
+ void
+ open();
+
+ bool
+ next(zorba::Item &aItem);
+
+ void
+ close();
+
+ bool
+ isOpen() const{ return thePaths->isOpen(); }
+
+ };
+
+ ViewItemSequence(lcb_t& aInstance, Iterator_t& aPaths, ViewOptions aOptions)
+ : theInstance(aInstance),
+ thePaths(aPaths),
+ theOptions(aOptions) {}
+
+ virtual ~ViewItemSequence() {}
+
+ zorba::Iterator_t
+ getIterator() { return new ViewIterator(theInstance, thePaths, theOptions); }
+
+ protected:
+ static void
+ view_callback(
+ lcb_http_request_t request,
+ lcb_t instance,
+ const void *cookie,
+ lcb_error_t error,
+ const lcb_http_resp_t *resp);
+ };
+
+ class GetItemSequence : public ItemSequence
+ {
+ protected:
+ lcb_t theInstance;
+ Iterator_t theKeys;
+ GetOptions theOptions;
+
+ public:
+
+ class GetIterator : public Iterator
+ {
+ protected:
+ lcb_t theInstance;
+ lcb_error_t theError;
+ Iterator_t theKeys;
+ GetOptions theOptions;
+
+ public:
+ GetIterator(lcb_t& aInstance, Iterator_t& aKeys, GetOptions& aOptions)
+ : theInstance(aInstance),
+ theKeys(aKeys),
+ theOptions(aOptions) {}
+
+ virtual ~GetIterator() {}
+
+ void
+ open();
+
+ bool
+ next(zorba::Item &aItem);
+
+ void
+ close();
+
+ bool
+ isOpen() const { return theKeys->isOpen(); }
+ };
+
+ public:
+ GetItemSequence(lcb_t& aInstance, Iterator_t& aKeys, GetOptions aOptions)
+ : theInstance(aInstance),
+ theKeys(aKeys),
+ theOptions(aOptions){}
+
+ virtual ~GetItemSequence(){}
+
+ zorba::Iterator_t
+ getIterator() { return new GetIterator(theInstance, theKeys, theOptions); }
+
+ protected:
+ static void
+ get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp);
+ };
+
+ const CouchbaseModule* theModule;
+
+ String
+ getOneStringArgument(const Arguments_t&, int) const;
+
+ Item
+ getOneItemArgument(const Arguments_t&, int) const;
+
+ Iterator_t
+ getIterArgument(const Arguments_t&, int) const;
+
+ static void
+ throwError(const char*, const char*);
+
+ static void
+ isNotJSONError();
+
+ static void
+ libCouchbaseError(lcb_t aInstance, lcb_error_t aError);
+
+ lcb_t
+ getInstance (const DynamicContext*, const String& aIdent) const;
+
+ static void
+ put (lcb_t aInstance, Iterator_t aKeys, Iterator_t aValues, PutOptions aOptions);
+
+
+ static void
+ observe_callback(
+ lcb_t instance,
+ const void *cookie,
+ lcb_error_t error,
+ const lcb_observe_resp_t *resp);
+
+ public:
+
+ CouchbaseFunction(const CouchbaseModule* module);
+
+ virtual ~CouchbaseFunction();
+
+ virtual String
+ getURI() const;
+
+};
+
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class InstanceMap : public ExternalFunctionParameter
+{
+ private:
+ typedef std::map<String, lcb_t> InstanceMap_t;
+ InstanceMap_t* instanceMap;
+
+ public:
+ InstanceMap();
+
+ bool
+ storeInstance(const String&, lcb_t);
+
+ lcb_t
+ getInstance(const String&);
+
+ bool
+ deleteInstance(const String&);
+
+ virtual void
+ destroy() throw()
+ {
+ if (instanceMap)
+ {
+ for (InstanceMap_t::const_iterator lIter = instanceMap->begin();
+ lIter != instanceMap->end(); ++lIter)
+ {
+ lcb_destroy(lIter->second);
+ }
+ instanceMap->clear();
+ delete instanceMap;
+ }
+ delete this;
+ };
+
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class ConnectFunction : public CouchbaseFunction
+{
+ public:
+ ConnectFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~ConnectFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "connect"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class GetTextFunction : public CouchbaseFunction
+{
+ public:
+ GetTextFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule)
+ {
+ }
+
+ virtual ~GetTextFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "get-text"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+
+ static void get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp);
+ static std::vector<Item> theVectorItem;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class GetBinaryFunction : public CouchbaseFunction
+{
+ public:
+ GetBinaryFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule)
+ {
+ }
+
+ virtual ~GetBinaryFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "get-binary"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+
+ static void get_callback(lcb_t instance, const void *cookie, lcb_error_t error, const lcb_get_resp_t *resp);
+ static std::vector<Item> theVectorItem;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class RemoveFunction : public CouchbaseFunction
+{
+ public:
+ RemoveFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~RemoveFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "remove"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class PutTextFunction : public CouchbaseFunction
+{
+ public:
+ PutTextFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~PutTextFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "put-text"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class PutBinaryFunction : public CouchbaseFunction
+{
+ public:
+ PutBinaryFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~PutBinaryFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "put-binary"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class FlushFunction : public CouchbaseFunction
+{
+ public:
+ FlushFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~FlushFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "flush"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class TouchFunction : public CouchbaseFunction
+{
+ public:
+ TouchFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~TouchFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "touch"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class ViewFunction : public CouchbaseFunction
+{
+ public:
+ ViewFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~ViewFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "view-text"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class CreateViewFunction : public CouchbaseFunction
+{
+ private:
+ static void create_view_callback(
+ lcb_http_request_t request,
+ lcb_t instance,
+ const void* cookie,
+ lcb_error_t error,
+ const lcb_http_resp_t* resp);
+
+ public:
+ CreateViewFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~CreateViewFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "create-view"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+
+/*******************************************************************************
+ ******************************************************************************/
+
+class DeleteViewFunction : public CouchbaseFunction
+{
+ private:
+ static void delete_view_callback(
+ lcb_http_request_t request,
+ lcb_t instance,
+ const void* cookie,
+ lcb_error_t error,
+ const lcb_http_resp_t* resp);
+
+ public:
+ DeleteViewFunction(const CouchbaseModule* aModule)
+ : CouchbaseFunction(aModule) {}
+
+ virtual ~DeleteViewFunction(){}
+
+ virtual zorba::String
+ getLocalName() const { return "delete-view"; }
+
+ virtual zorba::ItemSequence_t
+ evaluate( const Arguments_t&,
+ const zorba::StaticContext*,
+ const zorba::DynamicContext*) const;
+};
+} /*namespace couchbase*/ } /*namespace zorba*/
+
+
+#endif //_COM_ZORBA_WWW_MODULES_COUCHBASE_H_
+
=== added directory 'test'
=== renamed directory 'test' => 'test.moved'
=== added directory 'test/ExpQueryResults'
=== added directory 'test/ExpQueryResults/couchbase_module'
=== added file 'test/ExpQueryResults/couchbase_module/append-text.xml.res'
--- test/ExpQueryResults/couchbase_module/append-text.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/append-text.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+foofoo2
=== added file 'test/ExpQueryResults/couchbase_module/connect.xml.res'
--- test/ExpQueryResults/couchbase_module/connect.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/connect.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+true
=== added file 'test/ExpQueryResults/couchbase_module/create-view.xml.res'
--- test/ExpQueryResults/couchbase_module/create-view.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/create-view.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+_design/dev_view/_view/test1 _design/dev_view/_view/test2
=== added file 'test/ExpQueryResults/couchbase_module/create-view2.xml.res'
--- test/ExpQueryResults/couchbase_module/create-view2.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/create-view2.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+_design/dev_view2/_view/test1 _design/dev_view2/_view/test2
=== added file 'test/ExpQueryResults/couchbase_module/expiration-time.xml.res'
--- test/ExpQueryResults/couchbase_module/expiration-time.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/expiration-time.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+foo
=== added file 'test/ExpQueryResults/couchbase_module/prepend-text.xml.res'
--- test/ExpQueryResults/couchbase_module/prepend-text.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/prepend-text.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+foo2foo
=== added file 'test/ExpQueryResults/couchbase_module/replace-text.xml.res'
--- test/ExpQueryResults/couchbase_module/replace-text.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/replace-text.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+foo2
=== added file 'test/ExpQueryResults/couchbase_module/store-binary.xml.res'
--- test/ExpQueryResults/couchbase_module/store-binary.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/store-binary.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+aW1wb3J0IG1vZHVsZSBuYW1lc3BhY2UgY2IgPSAiaHR0cDovL3d3dy56b3JiYS14cXVlcnkuY29tL21vZHVsZXMvY291Y2hiYXNlIjsKCnZhcmlhYmxlICRpbnN0YW5jZSA6PSBjYjpjb25uZWN0KHsKICAiaG9zdCI6ICJsb2NhbGhvc3Q6ODA5MSIsCiAgInVzZXJuYW1lIiA6IGpuOm51bGwoKSwKICAicGFzc3dvcmQiIDogam46bnVsbCgpLAogICJidWNrZXQiIDogImRlZmF1bHQifSk7CmlmICgkaW5zdGFuY2UpCiB0aGVuIHRydWUoKQogZWxzZSBmYWxzZSgpCgo=
=== added file 'test/ExpQueryResults/couchbase_module/store-binary2.xml.res'
--- test/ExpQueryResults/couchbase_module/store-binary2.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/store-binary2.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,11 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+if ($instance)
+ then true()
+ else false()
+
=== added file 'test/ExpQueryResults/couchbase_module/store-text-encoding.xml.res'
--- test/ExpQueryResults/couchbase_module/store-text-encoding.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/store-text-encoding.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+true
=== added file 'test/ExpQueryResults/couchbase_module/store-text-encoding2.xml.res'
--- test/ExpQueryResults/couchbase_module/store-text-encoding2.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/store-text-encoding2.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+false
=== added file 'test/ExpQueryResults/couchbase_module/store-text.xml.res'
--- test/ExpQueryResults/couchbase_module/store-text.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/store-text.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+foo
=== added file 'test/ExpQueryResults/couchbase_module/touch.xml.res'
--- test/ExpQueryResults/couchbase_module/touch.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/touch.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+foo
=== added file 'test/ExpQueryResults/couchbase_module/view.xml.res'
--- test/ExpQueryResults/couchbase_module/view.xml.res 1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/couchbase_module/view.xml.res 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+{ "id" : "view", "key" : 1, "value" : null }
=== added directory 'test/Queries'
=== added directory 'test/Queries/couchbase_module'
=== added file 'test/Queries/couchbase_module/append-text.xq'
--- test/Queries/couchbase_module/append-text.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/append-text.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,12 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "append", "foo");
+cb:put-text($instance, "append", "foo2", { "operation" : "append" });
+variable $result := cb:get-text($instance, "append");
+$result
=== added file 'test/Queries/couchbase_module/connect.xq'
--- test/Queries/couchbase_module/connect.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/connect.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,11 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+if ($instance)
+ then true()
+ else false()
+
=== added file 'test/Queries/couchbase_module/connect2.spec'
--- test/Queries/couchbase_module/connect2.spec 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/connect2.spec 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/modules/couchbase:LCB0001
=== added file 'test/Queries/couchbase_module/connect2.xq'
--- test/Queries/couchbase_module/connect2.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/connect2.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,11 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "12492873009",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+if ($instance)
+ then true()
+ else false()
+
=== added file 'test/Queries/couchbase_module/create-view.xq'
--- test/Queries/couchbase_module/create-view.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/create-view.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,10 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+variable $view-name := cb:create-view($instance, "dev_view", ("test1", "test2"));
+$view-name
=== added file 'test/Queries/couchbase_module/create-view2.xq'
--- test/Queries/couchbase_module/create-view2.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/create-view2.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,10 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+variable $view-name := cb:create-view($instance, "dev_view2", ("test1", "test2"), ({"key" : "meta.id", "values" : "doc.value"},{ "key" : "meta.id", "values" : ["doc.value", "doc.value2"] }));
+$view-name
=== added file 'test/Queries/couchbase_module/expiration-time.xq'
--- test/Queries/couchbase_module/expiration-time.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/expiration-time.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,11 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "exp-time", "foo", { "expiration-time" : 1 });
+variable $result := cb:get-text($instance, "exp-time");
+$result
=== added file 'test/Queries/couchbase_module/prepend-text.xq'
--- test/Queries/couchbase_module/prepend-text.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/prepend-text.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,12 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "prepend", "foo");
+cb:put-text($instance, "prepend", "foo2", { "operation" : "prepend" });
+variable $result := cb:get-text($instance, "prepend");
+$result
=== added file 'test/Queries/couchbase_module/remove.spec'
--- test/Queries/couchbase_module/remove.spec 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/remove.spec 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/modules/couchbase:LCB0002
=== added file 'test/Queries/couchbase_module/remove.xq'
--- test/Queries/couchbase_module/remove.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/remove.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,12 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "remove", "foo");
+cb:remove($instance, "remove");
+variable $result := cb:get-text($instance, "remove");
+$result
=== added file 'test/Queries/couchbase_module/replace-text.xq'
--- test/Queries/couchbase_module/replace-text.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/replace-text.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,12 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "replace", "foo");
+cb:put-text($instance, "replace", "foo2", { "operation" : "replace" });
+variable $result := cb:get-text($instance, "replace");
+$result
=== added file 'test/Queries/couchbase_module/store-binary.xq'
--- test/Queries/couchbase_module/store-binary.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-binary.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,13 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace f = "http://expath.org/ns/file";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+variable $binary := f:read-binary(resolve-uri("connect.xq"));
+cb:put-binary($instance, "binary-file", $binary);
+variable $result := cb:get-binary($instance, "binary-file");
+$result
=== added file 'test/Queries/couchbase_module/store-binary2.xq'
--- test/Queries/couchbase_module/store-binary2.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-binary2.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,13 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+import module namespace f = "http://expath.org/ns/file";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+variable $binary := f:read-binary(resolve-uri("connect.xq"));
+cb:put-binary($instance, "binary-file2", $binary);
+variable $result := cb:get-text($instance, "binary-file2");
+$result
=== added file 'test/Queries/couchbase_module/store-text-encoding.xq'
--- test/Queries/couchbase_module/store-text-encoding.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-text-encoding.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,13 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "encoding", "äüö", { "encoding" : "ISO-8859-1" });
+variable $result := cb:get-text($instance, "encoding", { "encoding" : "ISO-8859-1" });
+if ($result = "äüö")
+then true()
+else false()
=== added file 'test/Queries/couchbase_module/store-text-encoding2.xq'
--- test/Queries/couchbase_module/store-text-encoding2.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-text-encoding2.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,13 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "encoding2", "äüö", { "encoding" : "ISO-8859-1" });
+variable $result := cb:get-text($instance, "encoding2", { "encoding" : "UTF-8" });
+if ($result = "äüö")
+then true()
+else false()
=== added file 'test/Queries/couchbase_module/store-text.xq'
--- test/Queries/couchbase_module/store-text.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-text.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,11 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "store", "foo");
+variable $result := cb:get-text($instance, "store");
+$result
=== added file 'test/Queries/couchbase_module/store-text2.spec'
--- test/Queries/couchbase_module/store-text2.spec 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-text2.spec 2013-04-29 18:32:40 +0000
@@ -0,0 +1,1 @@
+Error: http://www.zorba-xquery.com/modules/couchbase:CB0006
=== added file 'test/Queries/couchbase_module/store-text2.xq'
--- test/Queries/couchbase_module/store-text2.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/store-text2.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,11 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "store2", "foo", { "encoding" : "foo" });
+variable $result := cb:get-text($instance, "store2", { "encoding" : "UTF-8" });
+$result
=== added file 'test/Queries/couchbase_module/touch.xq'
--- test/Queries/couchbase_module/touch.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/touch.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,12 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:put-text($instance, "touch", "foo");
+cb:touch($instance, "touch", 1);
+variable $result := cb:get-text($instance, "touch");
+$result
=== added file 'test/Queries/couchbase_module/view.xq'
--- test/Queries/couchbase_module/view.xq 1970-01-01 00:00:00 +0000
+++ test/Queries/couchbase_module/view.xq 2013-04-29 18:32:40 +0000
@@ -0,0 +1,19 @@
+import module namespace cb = "http://www.zorba-xquery.com/modules/couchbase";
+
+variable $instance := cb:connect({
+ "host": "localhost:8091",
+ "username" : jn:null(),
+ "password" : jn:null(),
+ "bucket" : "default"});
+
+cb:remove($instance, "view");
+cb:put-text($instance, "view", '{ "view" : 1 }', { "wait" : "persist" });
+
+variable $cb-document := "dev_test_view";
+variable $cb-view := "view";
+variable $view-name := cb:create-view($instance, $cb-document, $cb-view, {"key":"doc.view"});
+variable $data := cb:view($instance, $view-name, {"stale" : "false"});
+for $d in jn:members($data("rows"))
+let $key := $d("key")
+where not(jn:is-null($key)) and $key >0
+return $d