[ignore] fixed problem with REST servlet if called as /exist/servlet instead of /exist/rest

svn path=/trunk/eXist/; revision=8804

(: 	This is the main controller for the web application. It is called from the
	XQueryURLRewrite filter configured in web.xml. :)
xquery version "1.0";

declare namespace c="http://exist-db.org/xquery/controller";

import module namespace request="http://exist-db.org/xquery/request";
import module namespace xdb = "http://exist-db.org/xquery/xmldb";

declare function c:admin($path as xs:string, $name as xs:string) {
    if (starts-with($path, "/admin/backups")) then
        let $user := xdb:get-current-user()
        return
            if (not(xdb:is-admin-user($user))) then
                <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
        			<redirect url="../admin.xql"/>
        		</dispatch>
        	else
                <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
                    <forward url="/admin/retrieve-backup.xql">
                        <add-parameter name="archive" value="{$name}"/>
                    </forward>
                </dispatch>
    else if (matches($path, "admin/?$")) then
        <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<redirect url="admin.xql"/>
		</dispatch>
    else if ($name eq "admin.xql") then
	    <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
	        <forward url="/admin/admin.xql"/>
	    </dispatch>
    else
        <ignore xmlns="http://exist.sourceforge.net/NS/exist">
            <cache-control cache="yes"/>
		</ignore>
};

let $uri := request:get-uri()
let $context := request:get-context-path()
let $path := substring-after($uri, $context)
let $name := replace($uri, '^.*/([^/]+)$', '$1')
let $query := request:get-parameter("q", ())
return
	(: redirect webapp root to index.xml :)
    if ($path eq '/') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<redirect url="index.xml"/>
		</dispatch>
	(: /rest and /webdav will be ignored :)
	else if (matches($path, "/(rest|servlet|webdav|cocoon|test.xml)")) then
		<ignore xmlns="http://exist.sourceforge.net/NS/exist">
            <cache-control cache="yes"/>
		</ignore>
	(: redirect sandbox root to sandbox.xql :)
	else if (matches($uri, "sandbox/?$")) then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<redirect url="sandbox.xql"/>
		</dispatch>
	else if (starts-with($path, "/admin")) then
	    c:admin($path, $name)
	else if ($name = ('search.xql', 'functions.xql', 'svnlog.xql')) then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<forward url="{$path}">
				<!-- query results are passed to XSLT servlet via request attribute -->
				<set-attribute name="xquery.attribute"
					value="xslt.model"/>
			</forward>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>
	else if ($name eq 'acronyms.xql') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<!-- query results are passed to XSLT servlet via request attribute -->
			<set-attribute name="xquery.attribute"
				value="xslt.model"/>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="xquery/stylesheets/acronyms.xsl"/>
				</forward>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value=""/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>
	else if ($name eq 'biblio.xql') then
		let $display := request:get-parameter("display", "overview")
		let $xsl :=
			if ($display eq "details") then "detailed.xsl" else "overview.xsl"
		return
			<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
				<set-attribute name="xquery.attribute" value="xslt.model"/>
				<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="xquery/stylesheets/{$xsl}"/>
				</forward>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value=""/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/doc2html-2.xsl"/>
				</forward>

				</view>
			</dispatch>

	else if ($name eq 'twitter.xql') then
	    <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
	        <view>
	            <forward url="twitter-view.xql"/>
            </view>
	    </dispatch>

	else if ($name eq 'applications.xml') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<!-- query results are passed to XSLT servlet via request attribute -->
			<set-attribute name="xquery.attribute"
				value="xslt.model"/>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="apps/applications.xsl"/>
				</forward>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value=""/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>

	else if ($name eq 'articles') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<forward url="/xquery/exist-articles.xql">
				<!-- query results are passed to XSLT servlet via request attribute -->
				<set-attribute name="xquery.attribute"
					value="xslt.model"/>
			</forward>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>

	(: the following xml files use different stylesheets :)
	else if ($name = ('index.xml', 'examples.xml', 'roadmap.xml', 'facts.xml', 'biblio.xml')) then
		let $stylesheet :=
			if ($name eq 'roadmap.xml') then
				"stylesheets/roadmap.xsl"
			else if ($name eq "facts.xml") then
				"stylesheets/facts.xsl"
			else
				"stylesheets/doc2html-2.xsl"
		return
			<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
				<view>
					<forward servlet="XSLTServlet">
						<set-attribute name="xslt.stylesheet"
							value="{$stylesheet}"/>
					</forward>
				</view>
				<cache-control cache="yes"/>
			</dispatch>
	else if (ends-with($uri, '.xml')) then
		(: 	check if the requested document was selected from a query result.
			if yes, pass it to docs.xql to get the match highlighting. :)
		if ($query) then
			let $docName := replace($uri, '^.*/([^/]+)$', '$1')
			return
				<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
					<forward url="docs.xql">
						<add-parameter name="path" value="/db/xqdocs/{$docName}"/>
					</forward>
				</dispatch>
		else
			<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
				<view>
					<forward servlet="XSLTServlet">
						<set-attribute name="xslt.stylesheet"
							value="stylesheets/db2html.xsl"/>
					</forward>
				</view>
            	<cache-control cache="yes"/>
			</dispatch>
	else
		<ignore xmlns="http://exist.sourceforge.net/NS/exist">
            <cache-control cache="yes"/>
		</ignore>

(: 	This is the main controller for the web application. It is called from the
	XQueryURLRewrite filter configured in web.xml. :)
xquery version "1.0";

declare namespace c="http://exist-db.org/xquery/controller";

import module namespace request="http://exist-db.org/xquery/request";
import module namespace xdb = "http://exist-db.org/xquery/xmldb";

declare function c:admin($path as xs:string, $name as xs:string) {
    if (starts-with($path, "/admin/backups")) then
        let $user := xdb:get-current-user()
        return
            if (not(xdb:is-admin-user($user))) then
                <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
        			<redirect url="../admin.xql"/>
        		</dispatch>
        	else
                <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
                    <forward url="/admin/retrieve-backup.xql">
                        <add-parameter name="archive" value="{$name}"/>
                    </forward>
                </dispatch>
    else if (matches($path, "admin/?$")) then
        <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<redirect url="admin.xql"/>
		</dispatch>
    else if ($name eq "admin.xql") then
	    <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
	        <forward url="/admin/admin.xql"/>
	    </dispatch>
    else
        <ignore xmlns="http://exist.sourceforge.net/NS/exist">
            <cache-control cache="yes"/>
		</ignore>
};

let $uri := request:get-uri()
let $context := request:get-context-path()
let $path := substring-after($uri, $context)
let $name := replace($uri, '^.*/([^/]+)$', '$1')
let $query := request:get-parameter("q", ())
return
	(: redirect webapp root to index.xml :)
    if ($path eq '/') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<redirect url="index.xml"/>
		</dispatch>
	(: /rest and /webdav will be ignored :)
	else if (matches($path, "/(rest|webdav|cocoon|test.xml)")) then
		<ignore xmlns="http://exist.sourceforge.net/NS/exist">
            <cache-control cache="yes"/>
		</ignore>
	(: redirect sandbox root to sandbox.xql :)
	else if (matches($uri, "sandbox/?$")) then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<redirect url="sandbox.xql"/>
		</dispatch>
	else if (starts-with($path, "/admin")) then
	    c:admin($path, $name)
	else if ($name = ('search.xql', 'functions.xql', 'svnlog.xql')) then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<forward url="{$path}">
				<!-- query results are passed to XSLT servlet via request attribute -->
				<set-attribute name="xquery.attribute"
					value="xslt.model"/>
			</forward>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>
	else if ($name eq 'acronyms.xql') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<!-- query results are passed to XSLT servlet via request attribute -->
			<set-attribute name="xquery.attribute"
				value="xslt.model"/>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="xquery/stylesheets/acronyms.xsl"/>
				</forward>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value=""/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>
	else if ($name eq 'biblio.xql') then
		let $display := request:get-parameter("display", "overview")
		let $xsl :=
			if ($display eq "details") then "detailed.xsl" else "overview.xsl"
		return
			<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
				<set-attribute name="xquery.attribute" value="xslt.model"/>
				<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="xquery/stylesheets/{$xsl}"/>
				</forward>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value=""/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/doc2html-2.xsl"/>
				</forward>

				</view>
			</dispatch>

	else if ($name eq 'twitter.xql') then
	    <dispatch xmlns="http://exist.sourceforge.net/NS/exist">
	        <view>
	            <forward url="twitter-view.xql"/>
            </view>
	    </dispatch>

	else if ($name eq 'applications.xml') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<!-- query results are passed to XSLT servlet via request attribute -->
			<set-attribute name="xquery.attribute"
				value="xslt.model"/>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="apps/applications.xsl"/>
				</forward>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value=""/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>

	else if ($name eq 'articles') then
		<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
			<forward url="/xquery/exist-articles.xql">
				<!-- query results are passed to XSLT servlet via request attribute -->
				<set-attribute name="xquery.attribute"
					value="xslt.model"/>
			</forward>
			<view>
				<forward servlet="XSLTServlet">
					<set-attribute name="xslt.input"
						value="xslt.model"/>
					<set-attribute name="xslt.stylesheet"
						value="stylesheets/db2html.xsl"/>
				</forward>
			</view>
		</dispatch>

	(: the following xml files use different stylesheets :)
	else if ($name = ('index.xml', 'examples.xml', 'roadmap.xml', 'facts.xml', 'biblio.xml')) then
		let $stylesheet :=
			if ($name eq 'roadmap.xml') then
				"stylesheets/roadmap.xsl"
			else if ($name eq "facts.xml") then
				"stylesheets/facts.xsl"
			else
				"stylesheets/doc2html-2.xsl"
		return
			<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
				<view>
					<forward servlet="XSLTServlet">
						<set-attribute name="xslt.stylesheet"
							value="{$stylesheet}"/>
					</forward>
				</view>
				<cache-control cache="yes"/>
			</dispatch>
	else if (ends-with($uri, '.xml')) then
		(: 	check if the requested document was selected from a query result.
			if yes, pass it to docs.xql to get the match highlighting. :)
		if ($query) then
			let $docName := replace($uri, '^.*/([^/]+)$', '$1')
			return
				<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
					<forward url="docs.xql">
						<add-parameter name="path" value="/db/xqdocs/{$docName}"/>
					</forward>
				</dispatch>
		else
			<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
				<view>
					<forward servlet="XSLTServlet">
						<set-attribute name="xslt.stylesheet"
							value="stylesheets/db2html.xsl"/>
					</forward>
				</view>
            	<cache-control cache="yes"/>
			</dispatch>
	else
		<ignore xmlns="http://exist.sourceforge.net/NS/exist">
            <cache-control cache="yes"/>
		</ignore>


[test] More tests for XQuery 3.1 arrow operator.

xquery version "3.0";

module namespace ao="http://exist-db.org/xquery/test/arrowop";

declare namespace test="http://exist-db.org/xquery/xqsuite";

declare
    %test:assertEquals("Hello world")
function ao:func-by-name1() {
    "Hello" => concat(" ", "world")
};

declare
    %test:assertEquals(3)
function ao:func-by-name2() {
    ('A', 'B', 'C') => count()
};

declare
    %test:assertEquals(3)
function ao:func-inline() {
    ('A', 'B', 'C') => (function( $sequence) { count( $sequence)})()
};

declare
    %test:assertEquals(11)
function ao:func-in-sequence1() {
    "Hello" => concat(" world") => string-length()
};

declare
    %test:assertEquals("HELLO", "WORLD")
function ao:func-in-sequence2() {
    "hello world"=>upper-case()=>normalize-unicode()=>tokenize("\s+")
};

declare
    %test:assertEquals("W-E-L-C-O-M-E")
function ao:func-in-sequence3() {
    'w e l c o m e' => upper-case() => tokenize(" ") => string-join('-')
};

declare
    %test:assertEquals("HELLO", "WORLD")
function ao:func-in-sequence-inner() {
    "hello world"=>(function($in) { $in=>upper-case()=>tokenize("\s+") })()
};

xquery version "3.0";

module namespace ao="http://exist-db.org/xquery/test/arrowop";

declare namespace test="http://exist-db.org/xquery/xqsuite";

declare
    %test:assertEquals("Hello world")
function ao:func-by-name() {
    "Hello" => concat(" ", "world")
};

declare
    %test:assertEquals(11)
function ao:func-in-sequence1() {
    "Hello" => concat(" world") => string-length()
};

declare
    %test:assertEquals("HELLO", "WORLD")
function ao:func-in-sequence2() {
    "hello world"=>upper-case()=>normalize-unicode()=>tokenize("\s+")
};

declare
    %test:assertEquals("HELLO", "WORLD")
function ao:func-in-sequence2() {
    "hello world"=>(function($in) { $in=>upper-case()=>tokenize("\s+") })()
};


[testsuite] range index tests: tear down was commented out, leading to followup errors in other tests. Closes #1201

xquery version "3.0";

(:~
 : Test query rewriting for range index.
 :
 : Expressions use the @test:stats annotation to retrieve execution statistics
 : for each test function. All comparisons should be fully optimized.
 :)
module namespace ot="http://exist-db.org/xquery/range/optimizer/test";

import module namespace range="http://exist-db.org/xquery/range" at "java:org.exist.xquery.modules.range.RangeIndexModule";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace stats="http://exist-db.org/xquery/profiling";

declare variable $ot:COLLECTION_CONFIG :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:tei="http://www.tei-c.org/ns/1.0">
            <lucene>
                <text field="lucene-name" qname="name"/>
            </lucene>
            <range>
                <create match="//tei:placeName">
                    <field name="name" type="xs:string" nested="no"/>
                    <field name="type" match="@type" type="xs:string"/>
                    <field name="subtype" match="@subtype" type="xs:string"/>
                </create>
                <create qname="tei:orth" type="xs:string" collation="?lang=sr&strength=primary" case="no"/>
                <create match="//address">
                    <filter class="org.apache.lucene.analysis.core.LowerCaseFilter"/>
                    <field name="address-city" match="city" type="xs:string"/>
                    <field name="address-street" match="street" type="xs:string"/>
                    <field name="address-email" match="contact/email" type="xs:string"/>
                    <field name="address-name" match="name3" type="xs:string"/>
                </create>
                <create match="/test/address/name"/>
                <create match="/test/address/name2">
                    <filter class="org.apache.lucene.analysis.core.LowerCaseFilter"/>
                    <filter class="org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter"/>
                </create>
                <create match="/test/address/city/@code" type="xs:integer"/>
                <create qname="@id" type="xs:string"/>
            </range>
        </index>
    </collection>;

declare variable $ot:DATA_NESTED :=
    <place xmlns="http://www.tei-c.org/ns/1.0">
        <placeName xml:id="ODB_S00004004_NAM001" xml:lang="de-DE" type="ref" subtype="inofficial">Hofthiergarten<note type="source">
                <date ana="#notBefore">1750</date>
                <date ana="#notAfter">1820</date>
            </note>
        </placeName>
        <placeName xml:id="ODB_S00004004_NAM002" xml:lang="de-DE" type="main" subtype="official">Hofthiergarten<note type="source">
                <date ana="#when">2011-08-24</date>
            </note>
        </placeName>
        <placeName xml:id="ODB_A00000393_NAM001" xml:lang="de-DE" type="main" subtype="official">Dorfprozelten<note type="source">
                <date ana="#when">2001-04-07</date>
                <bibl>
                    <ptr target="#HAB/Laube"/>
                </bibl>
            </note>
        </placeName>
    </place>;

declare variable $ot:DATA :=
    <test>
        <address id="muh">
            <name>Berta Muh</name>
            <name2>Berta Muh</name2>
            <name3>Berta Muh</name3>
            <street>Wiesenweg 14</street>
            <city code="65463">Almweide</city>
            <contact>
                <email>berta@milchvieh.org</email>
            </contact>
        </address>
        <address id="rüssel">
            <name>Rudi Rüssel</name>
            <name2>Rudi Rüssel</name2>
            <name3>Rudi Rüssel</name3>
            <street>Elefantenweg 67</street>
            <city code="65428">Rüsselsheim</city>
            <contact>
                <email>rudi@trompeter.de</email>
            </contact>
        </address>
        <address id="amsel">
            <name>Albert Amsel</name>
            <name2>Albert Amsel</name2>
            <name3>Albert Amsel</name3>
            <street>Birkenstraße 77</street>
            <city code="76878">Waldstadt</city>
            <contact>
                <email>albert@zwitschern.de</email>
            </contact>
        </address>
        <address id="reh">
            <name>Pü Reh</name>
            <name2>Pü Reh</name2>
            <name3>Pü Reh</name3>
            <street>Am Waldrand 4</street>
            <city code="89283">Wiesental</city>
            <contact>
                <email>pü@wildsau.net</email>
            </contact>
        </address>
    </test>;

declare variable $ot:DATA_SR_WITH_DIACRITICS :=
    <TEI xmlns="http://www.tei-c.org/ns/1.0">
        <teiHeader>
            <fileDesc>
                <titleStmt><title>sr with diacritics</title></titleStmt>
                <publicationStmt><distributor>sr with diacritics</distributor></publicationStmt>
                <sourceDesc><listOrg><org><name>test</name></org></listOrg></sourceDesc>
            </fileDesc>
        </teiHeader>
        <text>
            <body>
                <div>
                    <entryFree>
                        <form type="lemma">
                            <orth>Мла̀тишума</orth>
                        </form>
                        <form type="lemma">
                            <orth>Млатишума</orth>
                        </form>
                    </entryFree>
                </div>
            </body>
        </text>
    </TEI>;

declare variable $ot:COLLECTION_NAME := "optimizertest";
declare variable $ot:COLLECTION := "/db/" || $ot:COLLECTION_NAME;

declare
    %test:setUp
function ot:setup() {
    xmldb:create-collection("/db/system/config/db", $ot:COLLECTION_NAME),
    xmldb:store("/db/system/config/db/" || $ot:COLLECTION_NAME, "collection.xconf", $ot:COLLECTION_CONFIG),
    xmldb:create-collection("/db", $ot:COLLECTION_NAME),
    xmldb:store($ot:COLLECTION, "test.xml", $ot:DATA),
    xmldb:store($ot:COLLECTION, "nested.xml", $ot:DATA_NESTED),
    xmldb:store($ot:COLLECTION, "diacritics.xml", $ot:DATA_SR_WITH_DIACRITICS)
};

declare
    %test:tearDown
function ot:cleanup() {
    xmldb:remove($ot:COLLECTION),
    xmldb:remove("/db/system/config/db/" || $ot:COLLECTION_NAME)
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name = $name]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name != $name]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-string2($name as xs:string) {
    collection($ot:COLLECTION)//address[name ne $name]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-string-self($name as xs:string) {
    collection($ot:COLLECTION)//address/name[. ne $name]
};

declare
    %test:stats
    %test:args("Rudi")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-starts-with-string($name as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(name, $name)]
};

declare
    %test:stats
    %test:args("Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ends-with-string($name as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(name, $name)]
};

declare
    %test:stats
    %test:args("udi ")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-contains-string($name as xs:string) {
    collection($ot:COLLECTION)//address[contains(name, $name)]
};

declare
    %test:stats
    %test:args("[rR]udi .*")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-matches-string($name as xs:string) {
    collection($ot:COLLECTION)//address[range:matches(name, $name)]
};

declare
    %test:stats
    %test:args("[rR]udi .*")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 1]")
function ot:optimize-matches-string-filtered($name as xs:string) {
    let $address := collection($ot:COLLECTION)//address
    return
        $address[range:matches(name, $name)]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-string-self($name as xs:string) {
    collection($ot:COLLECTION)//address/name[. = $name]
};

declare
    %test:args("Rudi Rüssel")
function ot:eq-string-self-filtered($name as xs:string) {
    let $n := collection($ot:COLLECTION)//address/name
    return
        $n[. = $name]
};

declare
    %test:stats
    %test:args(65428)
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-int-attribute($code as xs:integer) {
    collection($ot:COLLECTION)//address/city[@code = $code]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-lt-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name < $name]
};

declare
    %test:args("Rudi Rüssel")
    %test:assertEquals(3)
function ot:ne-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name != $name])
};

declare
    %test:args("Rudi Rüssel")
    %test:assertEquals(3)
function ot:ne-string-self($name as xs:string) {
    count(collection($ot:COLLECTION)//address/name[. != $name])
};

declare
    %test:args("Berta Muh")
    %test:assertEquals(1)
function ot:lt-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name < $name])
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-le-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name <= $name]
};

declare
    %test:args("Berta Muh")
    %test:assertEquals(2)
function ot:le-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name <= $name])
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-gt-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name > $name]
};

declare
    %test:args("Pü Reh")
    %test:assertEquals(1)
function ot:gt-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name > $name])
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ge-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name > $name]
};

declare
    %test:args("Pü Reh")
    %test:assertEquals(2)
function ot:ge-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name >= $name])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city = $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(1)
function ot:eq-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city = $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city != $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(3)
function ot:ne-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city != $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-gt-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city > $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(2)
function ot:gt-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city > $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ge-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city >= $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(3)
function ot:ge-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city >= $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-lt-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city < $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(1)
function ot:lt-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city < $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-le-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city <= $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(2)
function ot:le-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city <= $city])
};

declare
    %test:stats
    %test:args("Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-starts-with-field($city as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(city, $city)]
};

declare
    %test:stats
    %test:args("heim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ends-with-field($city as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(city, $city)]
};

declare
    %test:stats
    %test:args("üssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-contains-field($city as xs:string) {
    collection($ot:COLLECTION)//address[contains(city, $city)]
};

declare
    %test:stats
    %test:args("[rR]üssel.*")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-matches-field($city as xs:string) {
    collection($ot:COLLECTION)//address[range:matches(city, $city)]
};

declare
    %test:args("[rR]üssel.*")
function ot:matches-field-filtered($city as xs:string) {
    let $address := collection($ot:COLLECTION)//address
    return
        $address[range:matches(city, $city)]
};

declare
    %test:stats
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-field-multi($city as xs:string, $street as xs:string) {
    collection($ot:COLLECTION)//address[city = $city][street = $street]
};

declare
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(1)
function ot:eq-field-multi($city as xs:string, $street as xs:string) {
    count(collection($ot:COLLECTION)//address[city = $city][street = $street])
};

declare
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(1)
function ot:eq-field-multi-filtered($city as xs:string, $street as xs:string) {
    let $address := collection($ot:COLLECTION)//address
    return
        count($address[city = $city][street = $street])
};

declare
    %test:stats
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-mixed-op-field($city as xs:string, $street as xs:string) {
    collection($ot:COLLECTION)//address[city > $city][street = $street]
};

declare
    %test:args("rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(0)
function ot:mixed-op-field1($city as xs:string, $street as xs:string) {
    count(collection($ot:COLLECTION)//address[city > $city][street = $street])
};

declare
    %test:args("rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(1)
function ot:mixed-op-field2($city as xs:string, $street as xs:string) {
    count(collection($ot:COLLECTION)//address[city >= $city][street = $street])
};

declare
    %test:stats
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:no-optimize-field-multi($city as xs:string, $street as xs:string) {
    collection($ot:COLLECTION)//address[street = $street][1]
};

declare
    %test:stats
    %test:args("berta@milchview.org")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-field-nested($email as xs:string) {
    collection($ot:COLLECTION)//address[contact/email = $email]
};

declare
    %test:stats
    %test:args("berta@milchview.org")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-lt-field-nested($email as xs:string) {
    collection($ot:COLLECTION)//address[contact/email < $email]
};

declare
    %test:args("main", "official", "Hofthiergarten")
    %test:assertEquals("Hofthiergarten")
    %test:args("ref", "inofficial", "Hofthiergarten")
    %test:assertEquals("Hofthiergarten")
    %test:args("main", "official", "Dorfprozelten")
    %test:assertEquals("Dorfprozelten")
function ot:equality-field-nested($type as xs:string, $subtype as xs:string, $name as xs:string) {
    //tei:placeName[@type = $type][@subtype = $subtype][. = $name]/text()
};

declare
    %test:stats
    %test:args("main", "official", "Hofthiergarten")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-field-self($type as xs:string, $subtype as xs:string, $name as xs:string) {
    //tei:placeName[@type = $type][@subtype = $subtype][. = $name]/text()
};

(: Filters :)

declare
    %test:args("rudi russel")
    %test:assertEquals("Rudi Rüssel")
    %test:args("rudi rüssel")
    %test:assertEquals("Rudi Rüssel")
function ot:eq-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[name2 = $name]/name2/text()
};

declare
    %test:args("Rudi Russel")
    %test:assertEquals(3)
function ot:ne-string-filtered($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name2 != $name])
};

declare
    %test:args("russel")
    %test:assertEquals("Rudi Rüssel")
function ot:contains-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[contains(name2, $name)]/name2/text()
};

declare
    %test:args("Rudi Rus")
    %test:assertEquals("Rudi Rüssel")
function ot:starts-with-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(name2, $name)]/name2/text()
};

declare
    %test:args("ussel")
    %test:assertEquals("Rudi Rüssel")
function ot:ends-with-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(name2, $name)]/name2/text()
};

declare
    %test:args("Rudi rüssel")
    %test:assertEquals("Rudi Rüssel")
    %test:args("rudi rüssel")
    %test:assertEquals("Rudi Rüssel")
function ot:eq-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[name3 = $name]/name3/text()
};

declare
    %test:args("rudi rüssel")
    %test:assertEquals(3)
function ot:ne-field-string-filtered($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name3 != $name])
};

declare
    %test:args("rüssel")
    %test:assertEquals("Rudi Rüssel")
function ot:contains-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[contains(name3, $name)]/name3/text()
};

declare
    %test:args("rudi rüs")
    %test:assertEquals("Rudi Rüssel")
function ot:starts-with-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(name3, $name)]/name3/text()
};

declare
    %test:args("üssel")
    %test:assertEquals("Rudi Rüssel")
function ot:ends-with-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(name3, $name)]/name3/text()
};

(: Collations :)

declare
    %test:args("Мла̀тишума")
    %test:assertEquals(2)
    %test:args("Млатишума")
    %test:assertEquals(2)
function ot:eq-string-collation-with-diacritics($name) {
    count(//tei:form[tei:orth = $name])
};

declare
    %test:args("Мла̀тишума")
    %test:assertError("range:EXXQDYFT0001")
    %test:args("Млатишума")
    %test:assertError("range:EXXQDYFT0001")
function ot:contains-string-collation-with-diacritics($name) {
    count(//tei:form[contains(tei:orth, $name)])
};

declare
    %test:args("Мла̀тишума")
    %test:assertEquals(0)
    %test:args("Млатишума")
    %test:assertEquals(0)
function ot:ne-string-collation-with-diacritics($name) {
    count(//tei:form[tei:orth != $name])
};

xquery version "3.0";

(:~
 : Test query rewriting for range index.
 :
 : Expressions use the @test:stats annotation to retrieve execution statistics
 : for each test function. All comparisons should be fully optimized.
 :)
module namespace ot="http://exist-db.org/xquery/range/optimizer/test";

import module namespace range="http://exist-db.org/xquery/range" at "java:org.exist.xquery.modules.range.RangeIndexModule";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace stats="http://exist-db.org/xquery/profiling";

declare variable $ot:COLLECTION_CONFIG :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:tei="http://www.tei-c.org/ns/1.0">
            <lucene>
                <text field="lucene-name" qname="name"/>
            </lucene>
            <range>
                <create match="//tei:placeName">
                    <field name="name" type="xs:string" nested="no"/>
                    <field name="type" match="@type" type="xs:string"/>
                    <field name="subtype" match="@subtype" type="xs:string"/>
                </create>
                <create qname="tei:orth" type="xs:string" collation="?lang=sr&strength=primary" case="no"/>
                <create match="//address">
                    <filter class="org.apache.lucene.analysis.core.LowerCaseFilter"/>
                    <field name="address-city" match="city" type="xs:string"/>
                    <field name="address-street" match="street" type="xs:string"/>
                    <field name="address-email" match="contact/email" type="xs:string"/>
                    <field name="address-name" match="name3" type="xs:string"/>
                </create>
                <create match="/test/address/name"/>
                <create match="/test/address/name2">
                    <filter class="org.apache.lucene.analysis.core.LowerCaseFilter"/>
                    <filter class="org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter"/>
                </create>
                <create match="/test/address/city/@code" type="xs:integer"/>
                <create qname="@id" type="xs:string"/>
            </range>
        </index>
    </collection>;

declare variable $ot:DATA_NESTED :=
    <place xmlns="http://www.tei-c.org/ns/1.0">
        <placeName xml:id="ODB_S00004004_NAM001" xml:lang="de-DE" type="ref" subtype="inofficial">Hofthiergarten<note type="source">
                <date ana="#notBefore">1750</date>
                <date ana="#notAfter">1820</date>
            </note>
        </placeName>
        <placeName xml:id="ODB_S00004004_NAM002" xml:lang="de-DE" type="main" subtype="official">Hofthiergarten<note type="source">
                <date ana="#when">2011-08-24</date>
            </note>
        </placeName>
        <placeName xml:id="ODB_A00000393_NAM001" xml:lang="de-DE" type="main" subtype="official">Dorfprozelten<note type="source">
                <date ana="#when">2001-04-07</date>
                <bibl>
                    <ptr target="#HAB/Laube"/>
                </bibl>
            </note>
        </placeName>
    </place>;

declare variable $ot:DATA :=
    <test>
        <address id="muh">
            <name>Berta Muh</name>
            <name2>Berta Muh</name2>
            <name3>Berta Muh</name3>
            <street>Wiesenweg 14</street>
            <city code="65463">Almweide</city>
            <contact>
                <email>berta@milchvieh.org</email>
            </contact>
        </address>
        <address id="rüssel">
            <name>Rudi Rüssel</name>
            <name2>Rudi Rüssel</name2>
            <name3>Rudi Rüssel</name3>
            <street>Elefantenweg 67</street>
            <city code="65428">Rüsselsheim</city>
            <contact>
                <email>rudi@trompeter.de</email>
            </contact>
        </address>
        <address id="amsel">
            <name>Albert Amsel</name>
            <name2>Albert Amsel</name2>
            <name3>Albert Amsel</name3>
            <street>Birkenstraße 77</street>
            <city code="76878">Waldstadt</city>
            <contact>
                <email>albert@zwitschern.de</email>
            </contact>
        </address>
        <address id="reh">
            <name>Pü Reh</name>
            <name2>Pü Reh</name2>
            <name3>Pü Reh</name3>
            <street>Am Waldrand 4</street>
            <city code="89283">Wiesental</city>
            <contact>
                <email>pü@wildsau.net</email>
            </contact>
        </address>
    </test>;

declare variable $ot:DATA_SR_WITH_DIACRITICS :=
    <TEI xmlns="http://www.tei-c.org/ns/1.0">
        <teiHeader>
            <fileDesc>
                <titleStmt><title>sr with diacritics</title></titleStmt>
                <publicationStmt><distributor>sr with diacritics</distributor></publicationStmt>
                <sourceDesc><listOrg><org><name>test</name></org></listOrg></sourceDesc>
            </fileDesc>
        </teiHeader>
        <text>
            <body>
                <div>
                    <entryFree>
                        <form type="lemma">
                            <orth>Мла̀тишума</orth>
                        </form>
                        <form type="lemma">
                            <orth>Млатишума</orth>
                        </form>
                    </entryFree>
                </div>
            </body>
        </text>
    </TEI>;

declare variable $ot:COLLECTION_NAME := "optimizertest";
declare variable $ot:COLLECTION := "/db/" || $ot:COLLECTION_NAME;

declare
    %test:setUp
function ot:setup() {
    xmldb:create-collection("/db/system/config/db", $ot:COLLECTION_NAME),
    xmldb:store("/db/system/config/db/" || $ot:COLLECTION_NAME, "collection.xconf", $ot:COLLECTION_CONFIG),
    xmldb:create-collection("/db", $ot:COLLECTION_NAME),
    xmldb:store($ot:COLLECTION, "test.xml", $ot:DATA),
    xmldb:store($ot:COLLECTION, "nested.xml", $ot:DATA_NESTED),
    xmldb:store($ot:COLLECTION, "diacritics.xml", $ot:DATA_SR_WITH_DIACRITICS)
};

(: declare
    %test:tearDown
function ot:cleanup() {
    xmldb:remove($ot:COLLECTION),
    xmldb:remove("/db/system/config/db/" || $ot:COLLECTION_NAME)
}; :)

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name = $name]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name != $name]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-string2($name as xs:string) {
    collection($ot:COLLECTION)//address[name ne $name]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-string-self($name as xs:string) {
    collection($ot:COLLECTION)//address/name[. ne $name]
};

declare
    %test:stats
    %test:args("Rudi")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-starts-with-string($name as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(name, $name)]
};

declare
    %test:stats
    %test:args("Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ends-with-string($name as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(name, $name)]
};

declare
    %test:stats
    %test:args("udi ")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-contains-string($name as xs:string) {
    collection($ot:COLLECTION)//address[contains(name, $name)]
};

declare
    %test:stats
    %test:args("[rR]udi .*")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-matches-string($name as xs:string) {
    collection($ot:COLLECTION)//address[range:matches(name, $name)]
};

declare
    %test:stats
    %test:args("[rR]udi .*")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 1]")
function ot:optimize-matches-string-filtered($name as xs:string) {
    let $address := collection($ot:COLLECTION)//address
    return
        $address[range:matches(name, $name)]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-string-self($name as xs:string) {
    collection($ot:COLLECTION)//address/name[. = $name]
};

declare
    %test:args("Rudi Rüssel")
function ot:eq-string-self-filtered($name as xs:string) {
    let $n := collection($ot:COLLECTION)//address/name
    return
        $n[. = $name]
};

declare
    %test:stats
    %test:args(65428)
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-int-attribute($code as xs:integer) {
    collection($ot:COLLECTION)//address/city[@code = $code]
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-lt-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name < $name]
};

declare
    %test:args("Rudi Rüssel")
    %test:assertEquals(3)
function ot:ne-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name != $name])
};

declare
    %test:args("Rudi Rüssel")
    %test:assertEquals(3)
function ot:ne-string-self($name as xs:string) {
    count(collection($ot:COLLECTION)//address/name[. != $name])
};

declare
    %test:args("Berta Muh")
    %test:assertEquals(1)
function ot:lt-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name < $name])
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-le-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name <= $name]
};

declare
    %test:args("Berta Muh")
    %test:assertEquals(2)
function ot:le-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name <= $name])
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-gt-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name > $name]
};

declare
    %test:args("Pü Reh")
    %test:assertEquals(1)
function ot:gt-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name > $name])
};

declare
    %test:stats
    %test:args("Rudi Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ge-string($name as xs:string) {
    collection($ot:COLLECTION)//address[name > $name]
};

declare
    %test:args("Pü Reh")
    %test:assertEquals(2)
function ot:ge-string($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name >= $name])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city = $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(1)
function ot:eq-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city = $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ne-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city != $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(3)
function ot:ne-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city != $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-gt-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city > $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(2)
function ot:gt-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city > $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ge-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city >= $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(3)
function ot:ge-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city >= $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-lt-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city < $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(1)
function ot:lt-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city < $city])
};

declare
    %test:stats
    %test:args("Rüsselsheim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-le-field($city as xs:string) {
    collection($ot:COLLECTION)//address[city <= $city]
};

declare
    %test:args("Rüsselsheim")
    %test:assertEquals(2)
function ot:le-field($city as xs:string) {
    count(collection($ot:COLLECTION)//address[city <= $city])
};

declare
    %test:stats
    %test:args("Rüssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-starts-with-field($city as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(city, $city)]
};

declare
    %test:stats
    %test:args("heim")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-ends-with-field($city as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(city, $city)]
};

declare
    %test:stats
    %test:args("üssel")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-contains-field($city as xs:string) {
    collection($ot:COLLECTION)//address[contains(city, $city)]
};

declare
    %test:stats
    %test:args("[rR]üssel.*")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-matches-field($city as xs:string) {
    collection($ot:COLLECTION)//address[range:matches(city, $city)]
};

declare
    %test:args("[rR]üssel.*")
function ot:matches-field-filtered($city as xs:string) {
    let $address := collection($ot:COLLECTION)//address
    return
        $address[range:matches(city, $city)]
};

declare
    %test:stats
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-field-multi($city as xs:string, $street as xs:string) {
    collection($ot:COLLECTION)//address[city = $city][street = $street]
};

declare
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(1)
function ot:eq-field-multi($city as xs:string, $street as xs:string) {
    count(collection($ot:COLLECTION)//address[city = $city][street = $street])
};

declare
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(1)
function ot:eq-field-multi-filtered($city as xs:string, $street as xs:string) {
    let $address := collection($ot:COLLECTION)//address
    return
        count($address[city = $city][street = $street])
};

declare
    %test:stats
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-mixed-op-field($city as xs:string, $street as xs:string) {
    collection($ot:COLLECTION)//address[city > $city][street = $street]
};

declare
    %test:args("rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(0)
function ot:mixed-op-field1($city as xs:string, $street as xs:string) {
    count(collection($ot:COLLECTION)//address[city > $city][street = $street])
};

declare
    %test:args("rüsselsheim", "Elefantenweg 67")
    %test:assertEquals(1)
function ot:mixed-op-field2($city as xs:string, $street as xs:string) {
    count(collection($ot:COLLECTION)//address[city >= $city][street = $street])
};

declare
    %test:stats
    %test:args("Rüsselsheim", "Elefantenweg 67")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:no-optimize-field-multi($city as xs:string, $street as xs:string) {
    collection($ot:COLLECTION)//address[street = $street][1]
};

declare
    %test:stats
    %test:args("berta@milchview.org")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-eq-field-nested($email as xs:string) {
    collection($ot:COLLECTION)//address[contact/email = $email]
};

declare
    %test:stats
    %test:args("berta@milchview.org")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-lt-field-nested($email as xs:string) {
    collection($ot:COLLECTION)//address[contact/email < $email]
};

declare
    %test:args("main", "official", "Hofthiergarten")
    %test:assertEquals("Hofthiergarten")
    %test:args("ref", "inofficial", "Hofthiergarten")
    %test:assertEquals("Hofthiergarten")
    %test:args("main", "official", "Dorfprozelten")
    %test:assertEquals("Dorfprozelten")
function ot:equality-field-nested($type as xs:string, $subtype as xs:string, $name as xs:string) {
    //tei:placeName[@type = $type][@subtype = $subtype][. = $name]/text()
};

declare
    %test:stats
    %test:args("main", "official", "Hofthiergarten")
    %test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ot:optimize-field-self($type as xs:string, $subtype as xs:string, $name as xs:string) {
    //tei:placeName[@type = $type][@subtype = $subtype][. = $name]/text()
};

(: Filters :)

declare
    %test:args("rudi russel")
    %test:assertEquals("Rudi Rüssel")
    %test:args("rudi rüssel")
    %test:assertEquals("Rudi Rüssel")
function ot:eq-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[name2 = $name]/name2/text()
};

declare
    %test:args("Rudi Russel")
    %test:assertEquals(3)
function ot:ne-string-filtered($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name2 != $name])
};

declare
    %test:args("russel")
    %test:assertEquals("Rudi Rüssel")
function ot:contains-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[contains(name2, $name)]/name2/text()
};

declare
    %test:args("Rudi Rus")
    %test:assertEquals("Rudi Rüssel")
function ot:starts-with-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(name2, $name)]/name2/text()
};

declare
    %test:args("ussel")
    %test:assertEquals("Rudi Rüssel")
function ot:ends-with-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(name2, $name)]/name2/text()
};

declare
    %test:args("Rudi rüssel")
    %test:assertEquals("Rudi Rüssel")
    %test:args("rudi rüssel")
    %test:assertEquals("Rudi Rüssel")
function ot:eq-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[name3 = $name]/name3/text()
};

declare
    %test:args("rudi rüssel")
    %test:assertEquals(3)
function ot:ne-field-string-filtered($name as xs:string) {
    count(collection($ot:COLLECTION)//address[name3 != $name])
};

declare
    %test:args("rüssel")
    %test:assertEquals("Rudi Rüssel")
function ot:contains-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[contains(name3, $name)]/name3/text()
};

declare
    %test:args("rudi rüs")
    %test:assertEquals("Rudi Rüssel")
function ot:starts-with-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[starts-with(name3, $name)]/name3/text()
};

declare
    %test:args("üssel")
    %test:assertEquals("Rudi Rüssel")
function ot:ends-with-field-string-filtered($name as xs:string) {
    collection($ot:COLLECTION)//address[ends-with(name3, $name)]/name3/text()
};

(: Collations :)

declare
    %test:args("Мла̀тишума")
    %test:assertEquals(2)
    %test:args("Млатишума")
    %test:assertEquals(2)
function ot:eq-string-collation-with-diacritics($name) {
    count(//tei:form[tei:orth = $name])
};

declare
    %test:args("Мла̀тишума")
    %test:assertError("range:EXXQDYFT0001")
    %test:args("Млатишума")
    %test:assertError("range:EXXQDYFT0001")
function ot:contains-string-collation-with-diacritics($name) {
    count(//tei:form[contains(tei:orth, $name)])
};

declare
    %test:args("Мла̀тишума")
    %test:assertEquals(0)
    %test:args("Млатишума")
    %test:assertEquals(0)
function ot:ne-string-collation-with-diacritics($name) {
    count(//tei:form[tei:orth != $name])
};


- test output was correct. modified test-case so it probably does what was intended

let $r := <root><a/><b/><c><d/></c></root>
let $a := $r/*, $nids := ( for $i in $a return pf:nid($i) )
for $o in id($nids,exactly-one($r))
return <r>{$o}<eq>{$o is exactly-one($a[1])}</eq></r>

let $a := (<a/>,<b/>,<c><d/></c>)
, $nids := ( for $i in $a return pf:nid($i) )
for $o in id($nids,<a/>)
return <r>{$o}<eq>{$o is exactly-one($a[1])}</eq></r>


Add login tests

Add login tests

xquery version "3.0";

module namespace mongoMain = "http://exist-db.org/mongodb/test/main";

import module namespace mongodb = "http://expath.org/ns/mongo";

import module namespace support = "http://exist-db.org/mongrel/test/support"
                at "resource:org/exist/mongodb/test/db/support.xqm";

import module namespace test = "http://exist-db.org/xquery/xqsuite"
                at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

(: Connect to mongodb, store token :)
declare %test:setUp function mongoMain:setup()
{
    support:setup()
};

(: Disconnect from mongodb, cleanup token :)
declare %test:tearDown function mongoMain:cleanup()
{
    support:cleanup()
};

(:
 : Actual tests below this line
 :)
declare
    %test:assertError("mongodb:id")
function mongoMain:login_illegal_token() {
    let $mongodbClientId := "aa"
    return mongodb:drop($mongodbClientId, $support:database, $support:mongoCollection)
};

declare
    %test:assertEquals(3)
function mongoMain:count_clients() {
     let $count1 := count( mongodb:list-mongodb-clientids() )
     let $token1 := mongodb:connect("mongodb://localhost")
     let $count2 := count(mongodb:list-mongodb-clientids())
     let $token2 := mongodb:connect("mongodb://localhost")
     let $token3 := mongodb:connect("mongodb://localhost")
     let $count3 := count(mongodb:list-mongodb-clientids())

     return ($count3 - $count1)
};

xquery version "3.0";

module namespace mongoMain = "http://exist-db.org/mongodb/test/main";

import module namespace mongodb = "http://expath.org/ns/mongo";
import module namespace support = "http://exist-db.org/mongrel/test/support"
                at "resource:org/exist/mongodb/test/db/support.xqm";
import module namespace test = "http://exist-db.org/xquery/xqsuite"
                at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

(: Connect to mongodb, store token :)
declare %test:setUp function mongoMain:setup()
{
    support:setup()
};

(: Disconnect from mongodb, cleanup token :)
declare %test:tearDown function mongoMain:cleanup()
{
    support:cleanup()
};

(:
 : Actual tests below this line
 :)
declare
    %test:assertEquals("<test n='4'/>")
function mongoMain:show_token() {
    let $token := support:getToken()
    return <test n='4'/>
};

declare
    %test:assertError("mongodb:id")
function mongoMain:login_illegal_token() {
    let $mongodbClientId := "aa"
    return mongodb:drop($mongodbClientId, $support:database, $support:mongoCollection)
};


Fix gene lookup for probe count over 1

Fix gene lookup for probe count over 1

; matchGenesWithProbes
(fn [dataset names]
  (let [probemap (:probemap (car (query {:select [:probemap] :from [:dataset] :where [:= :dataset.name dataset]})))
        getfield (fn [field]
                   (:id (car (query {:select [:field.id]
                                     :from [:dataset]
                                     :join [:field [:= :dataset.id :field.dataset_id]]
                                     :where [:and [:= :field.name field] [:= :dataset.name probemap]]}))))
        genes (getfield "genes")
        matches (map :gene (query {:select [:%distinct.gene]
                                   :from [:field_gene]
                                   :join [{:table [[[:name :varchar names]] :T]} [:= :T.name :gene]]
                                   :where [:= :field_gene.field_id genes]}))
        probes (map (fn [gene]
                      (let [probes
                            ((xena-query {:select ["name"]
                                          :from [probemap]
                                          :where [:in :any "genes" [gene]]}) "name")]
                        (:count (car (query {:select [[:%count.field.name :count]]
                                             :limit 1
                                             :from [:field]
                                             :join [:dataset [:= :dataset.id :dataset_id]
                                                    {:table [[[:name :varchar probes]] :T]} [:= :T.name :field.name]]
                                             :where [:= :dataset.name dataset]})))))
                    matches)
        filtered (map :name (query {:select [:name]
                                    :from [{:table [[[:name :varchar matches] [:count :int probes]] :T]}]
                                    :where [:<> :count 0]}))]
    filtered))

; matchGenesWithProbes
(fn [dataset names]
  (let [probemap (:probemap (car (query {:select [:probemap] :from [:dataset] :where [:= :dataset.name dataset]})))
        getfield (fn [field]
                   (:id (car (query {:select [:field.id]
                                     :from [:dataset]
                                     :join [:field [:= :dataset.id :field.dataset_id]]
                                     :where [:and [:= :field.name field] [:= :dataset.name probemap]]}))))
        genes (getfield "genes")
        matches (map :gene (query {:select [:%distinct.gene]
                                   :from [:field_gene]
                                   :join [{:table [[[:name :varchar names]] :T]} [:= :T.name :gene]]
                                   :where [:= :field_gene.field_id genes]}))
        probes (map (fn [gene]
                      (let [probes
                            ((xena-query {:select ["name"]
                                          :from [probemap]
                                          :where [:in :any "genes" [gene]]}) "name")]
                        (:count (car (query {:select [[:%count.field.name :count]]
                                             :limit 1
                                             :from [:field]
                                             :join [:dataset [:= :dataset.id :dataset_id]
                                                    {:table [[[:name :varchar probes]] :T]} [:= :T.name :field.name]]
                                             :where [:= :dataset.name dataset]})))))
                    matches)
        filtered (map :name (query {:select [:name]
                                    :from [{:table [[[:name :varchar matches] [:count :int probes]] :T]}]
                                    :where [:= :count 1]}))]
    filtered))


[ignore] jquery lib: cleanup generated javascript.

svn path=/trunk/eXist/; revision=12603

(:~
    jQuery module: a set of functions to extend HTML forms with AJAX
    functionality, based on the jQuery javascript library.

    Use: each function takes an XML configuration element as parameter.
    You can either call functions directly from another XQuery module
    or pass a template page to the jquery:process-templates function.
    jquery:process-templates will parse the template page and expand all
    jquery:* elements it knows.

:)
module namespace jquery="http://exist-db.org/xquery/jquery";

import module namespace util="http://exist-db.org/xquery/util";
import module namespace request="http://exist-db.org/xquery/request";
import module namespace session="http://exist-db.org/xquery/session";

declare function jquery:script($node as element()?) as xs:string? {
    string-join($node/node(), "")
};

(:~
    Outputs the HTML script and link tags which are required by jQuery.
    You need to call this function once in your HTML head.

<![CDATA[<jquery:header base="scripts/jquery" cssbase="scripts/jquery/css"/>]]>

:)
declare function jquery:header($config as element(jquery:header)) as element()* {
    let $base := $config/@base/string()
    let $cssbase := if ($config/@cssbase) then $config/@cssbase/string() else $base
    return (

        case element(jquery:script) return
            ()
        case element() return
            element { node-name($node) } {
                $node/@*,
                for $child in $node/node() return jquery:cleanup-javascript($child, $scripts)
            }
        default return
            $node
};

declare function jquery:cleanup-javascript($root as element()) {
    let $scripts := $root//jquery:script
    return
        jquery:cleanup-javascript($root, $scripts)
};

(:~
    jQuery module: a set of functions to extend HTML forms with AJAX
    functionality, based on the jQuery javascript library.

    Use: each function takes an XML configuration element as parameter.
    You can either call functions directly from another XQuery module
    or pass a template page to the jquery:process-templates function.
    jquery:process-templates will parse the template page and expand all
    jquery:* elements it knows.

:)
module namespace jquery="http://exist-db.org/xquery/jquery";

import module namespace util="http://exist-db.org/xquery/util";
import module namespace request="http://exist-db.org/xquery/request";
import module namespace session="http://exist-db.org/xquery/session";

declare function jquery:script($node as element()?) as xs:string? {
    string-join($node/node(), "")
};

(:~
    Outputs the HTML script and link tags which are required by jQuery.
    You need to call this function once in your HTML head.

<![CDATA[<jquery:header base="scripts/jquery" cssbase="scripts/jquery/css"/>]]>

:)
declare function jquery:header($config as element(jquery:header)) as element()* {
    let $base := $config/@base/string()
    let $cssbase := if ($config/@cssbase) then $config/@cssbase/string() else $base
    return (

            }

};

(:~
    Creates a repeatable set of form fields. Clicking the trigger will
    clone a given part of the form. The new element is inserted immediately
    after the cloned element.

    The element to be cloned should have a class 'repeat'. It can be an arbitrary
    HTML node. Form fields within the repeated element should have a name attribute
    ending with a number (usually 1), e.g. "input1", "phone1". After inserting a new
    clone, the script will change the names for all form elements in the inserted
    element. So "phone1" will become "phone2" and so on.

    The function expects a configuration element jquery:form-repeat as parameter.
    Two attributes should be specified:

form: a jQuery selector pointing to the HTML form element

trigger: a jQuery selector pointing to the HTML element on which
       the user should click to insert a new row into the form

    Example:

<jquery:form-repeat trigger="#add-field" form="#search-form"/>

    @param $config the jquery:form-repeat configuration element
:)
declare function jquery:form-repeat($config as element(jquery:form-repeat)) as element() {
    let $formSelector := $config/@form/string()
    let $trigger := $config/@trigger/string()
    let $delete := $config/@delete/string()
    let $onReady := $config/@on-ready/string()
    return

};

(:~
    Toggles an HTML block upon the click on a link or button.
    The contents of the HTML block are retrieved via AJAX from
    the URL given in attribute "href".

<![CDATA[
        <jquery:toggle href="filters.xql?type=date"
            trigger="#filters li:nth-child(3) .expand"/>
    ]]>

href: the URL to load the HTML content block from

trigger: jQuery selector pointing to the trigger element
            on which the user should click

callback: optional callback javascript function which will
            be called once the contents of the toggle block are loaded.
            The function receives the trigger element as first parameter,
            the id of the toggle block as second.

:)
declare function jquery:toggle($config as element(jquery:toggle)) as element()+ {
    let $id0 := $config/@id/string()
    let $id := if ($id0) then $id0 else util:uuid()
    let $trigger := $config/@trigger/string()
    let $href := $config/@href/string()
    let $callback := $config/@callback/string()
    let $beforeCallback := $config/@beforeCallback/string()
    return (
        if (empty($id0)) then

        else (),

    )
};

(:~
    <jquery:paginate id="results" attribute="results"
        href="retrieve" navcontainer="#results-head .navbar"/>
:)
declare function jquery:paginate($config as element(jquery:paginate)) as element()+ {
    let $hits := session:get-attribute($config/@attribute)
    let $id := if ($config/@id) then $config/@id else 'jquery-paginate'
    let $onReady := $config/@on-ready/string()
    return (

,

    )
};

(:~
    Helper function for jquery:input-field()
:)
declare function jquery:extra-params($id as xs:string, $auto as element(jquery:autocomplete)) {
    if ($auto/jquery:param) then
        string-join(
            for $param in $auto/jquery:param
            return
                concat($param/@name, ': function () { ',
                    " return ", $param/@function, '.call($("#', $id, '"));}'),
            ', '
        )
    else
        ()
};

(:~
    Create an HTML input element. Copies all attributes of the jquery:input
    element. If no value attribute is present, the function will look up the
    parameter in the HTTP request, and if the parameter is set, add it as value
    attribute.

<![CDATA[<jquery:input name="input1"/>]]>

:)
declare function jquery:input-field($node as element(jquery:input)) as element()+ {
    let $name := $node/@name/string()
    let $id := if ($node/@id) then $node/@id/string() else util:uuid()
    return (
        if ($node/jquery:autocomplete) then
            let $auto := $node/jquery:autocomplete
            let $width := if ($auto/@width) then $auto/@width/string() else 200
            let $multiple := if ($auto/@multiple) then $auto/@multiple/string() else "false"
            let $matchContains := if ($auto/@matchContains) then $auto/@matchContains/string() else "false"
            let $minLength := if ($auto/@minLength) then $auto/@minLength/string() else "3"
            return

        else
            (),
        <input>
        { $node/@* }
        { if (empty($node/@id)) then attribute id { $id } else () }
        {
            if (empty($node/@value)) then
                attribute value { request:get-parameter($name, "") }
            else
                ()
        }
        </input>
    )
};

(:~
    { jquery:extra-params($id, $auto) }
                        width: { $width },
                        minChars: 3
    Create an HTML select element. Copies all attributes of the jquery:select
    element. jquery:select should contain zero or more jquery:option elements
    which are transformed into HTML option elements. Each option must have a
    value attribute and may have an optional text content. Both are copied to
    the generated HTML option.

    For each option, the HTTP request is checked for a corresponding parameter
    value. If present, the option will be selected.

<![CDATA[
        <jquery:select name="sort">
            <jquery:option value="Author"/>
            <jquery:option value="Title"/>
            <jquery:option value="Date Issued"/>
        </jquery:select>
    ]]>

:)
declare function jquery:select-field($node as element(jquery:select)) as element() {
    let $name := $node/@name/string()
    let $value := request:get-parameter($name, "")
    return
        <select>
        { $node/@* }
        {
            for $option in $node/jquery:option
            return
                <option>
                { $option/@value }
                { if ($option/@value eq $value) then attribute selected { "selected" } else () }
                { if ($option/text()) then $option/text() else $option/@value/string() }
                </option>
        }
        </select>
};

declare function jquery:button($node as element(jquery:button)) as element()+ {
    let $id := if ($node/@id) then $node/@id/string() else util:uuid()
    return (
        <button id="{$id}">{$node/@*[not(local-name(.) = 'id')], $node/node()}</button>,

    )
};

declare function jquery:accordion($config as element(jquery:ajax-accordion)) as element()+ {
    let $id := if ($config/@id) then $config/@id else 'jquery-accordion'
    return (

        {
            for $panel in $config/jquery:panel
            return (

{$panel/@id}{$panel/@title/string()}
,

                {
                    for $child in $panel/node() return
                        jquery:process-templates($child)
                }

            )
        }

,

    )
};

declare function jquery:dialog($config as element(jquery:dialog)) as node()* {
    let $trigger := $config/@trigger
    let $id := $config/@id
    let $modal := $config/@modal = 'true'
    let $buttons :=
        string-join(
            for $button in $config/jquery:button
            return
                if ($button/@id eq 'cancel') then
                    string-join(('"', $button/@label, '": function() { $(this).dialog("close"); }'), "")
                else if ($button/@id eq 'submit') then
                    string-join(('"', $button/@label, '": function() { $("#', $id/string(), ' form").submit(); }'), "")
                else if ($button/@function) then
                    string-join(('"', $button/@label, '": function () { ', $button/@function, '($(this)); }'), "")
                else
                    string-join(('"', $button/@label, '": function() {', $button/node(), '}'), "")
            , ", ")
    return

            { $id, for $child in $config/*[not(self::jquery:*)] return jquery:process-templates($child) }

            {
                if($trigger)then
                (

                )else()
            }

};

(:~
    Main function to process an HTML template. All jquery:* elements
    in the template are expanded, if known.
:)
declare function jquery:process-templates($node as node()) as node()* {
    typeswitch ($node)
        case element(jquery:form-repeat) return
            jquery:form-repeat($node)
        case element(jquery:tabset) return
            jquery:tabset($node)
        case element(jquery:toggle) return
            jquery:toggle($node)
        case element(jquery:paginate) return
            jquery:paginate($node)
        case element(jquery:input) return
            jquery:input-field($node)
        case element(jquery:select) return
            jquery:select-field($node)
        case element(jquery:button) return
            jquery:button($node)
        case element(jquery:ajax-accordion) return
            jquery:accordion($node)
        case element(jquery:dialog) return
            jquery:dialog($node)
        case element(jquery:header) return
            jquery:header($node)
        case element() return
            element { node-name($node) } {
                $node/@*,
                for $child in $node/node()
                return
                    jquery:process-templates($child)
            }
        default return
            $node
};


remove uneeded file

remove uneeded file

module namespace page = 'http://basex.org/modules/web-page';

import module namespace csd_psd = "https://github.com/openhie/openinfoman/csd_psd";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_lsc = "https://github.com/openhie/openinfoman/csd_lsc" ;
import module namespace csd_qus =  "https://github.com/openhie/openinfoman/csd_qus";
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";

declare function page:redirect($redirect as xs:string) as element(restxq:redirect)
{
  <restxq:redirect>{ $redirect }</restxq:redirect>
};

declare function page:nocache($response) {
(<http:response status="200" message="OK">

  <http:header name="Cache-Control" value="must-revalidate,no-cache,no-store"/>
</http:response>,
$response)
};

declare updating
  %rest:path("/CSD/cacheService/init_cache_meta")
  %rest:GET
  function page:init_cache_meta()
{
  (csd_lsc:init_cache_meta($csd_webconf:db)
  ,
  db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/cacheService")))
  )

};

declare
  %rest:path("/CSD/cacheService")
  %rest:GET
  %output:method("xhtml")
  function page:poll_service_list()
{
if ( not(csd_lsc:cache_meta_exists($csd_webconf:db))) then
  page:redirect(concat($csd_webconf:baseurl,"CSD/cacheService/init_cache_meta"))
else
  let $services := csd_psd:registered_directories($csd_webconf:db)
  let $response :=

Global Operations

 Get all cache Meta-Data

    {
    if ( csd_lsc:cache_meta_exists($csd_webconf:db)) then

Service Directory Operations

	    {for $name in $services
	    let $mtime := csd_lsc:get_service_directory_mtime($csd_webconf:db,$name)
	    order by $name
	    return

	      {$name} last cached on {$mtime}:

	      {page:services_menu($name)}

	    }

    else ()
    }

  return page:nocache(  csd_webconf:wrapper($response))

};

declare function page:services_menu($name) {
  let $url := csd_psd:get_service_directory_url($csd_webconf:db,$name)
  let $mtime := csd_lsc:get_service_directory_mtime($csd_webconf:db,$name)
  return

    {if (not(csd_lsc:directory_exists($csd_webconf:db,$name))) then

Create cache of {$name}

  else
    (

Empty local cache of {$name}
,

Get local cache  of {$name}
,

      Update local cache  of {$name}

	WARNING:An InfoMan trying to cache its own service directory will result in a deadlock.  see this issue

,

Get cache Meta Data  for {$name}
,

Drop cache Meta Data  of {$name}

  )
    }

};


update serialization

update serialization

(:~
: trees as svg
: @author andy bunce
: @since sept 2012
:)

module namespace web = 'apb.hedge.web';
declare default function namespace 'apb.hedge.web';
import module namespace tree = 'apb.tree' at "hedgetree/treedraw.xqm";
declare namespace rest = 'http://exquery.org/ns/restxq';

(:~
: main page
:)
declare
%rest:GET %rest:path("hedge")
%output:method("html") %output:version("5.0")
%rest:form-param("hedge","{$hedge}")
%rest:form-param("url","{$url}")
function hedge($hedge,$url) {
	let $ehedge:=if($url) then "" else fn:encode-for-uri($hedge)
	let $xml:=getxml($hedge,$url)
	let $layout:=tree:layout($xml)
	let $svg:=tree:svg($layout)

	return

		<title>Drawing trees with XQuery and SVG</title>
		<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="tree xquery svg" />

Drawing trees with XQuery and SVG

Enter a  string representing a tree in the form below; use letters for nodes and () to enclose subnodes. Use {{...}} for multi character names. {{name|href}} will create a link. Examples: a(bcd(ef)),
                  another
		a proper hedge: a(bcd)e(fgh).

 Or enter a Url to a xml document examples:
		sample1,
	hedgeweb
	remote

		 <form method="get" action="./hedge" style="background-color:#EEEEEE;padding:8px;">

		 <textarea name="hedge" rows="2" cols="80">{$hedge}</textarea>

Or enter the url to a node XML source
		 <input name="url"  value="{$url}" style="width:30em"/>

		 <button type="submit">Redraw</button>
		</form >

Inline SVG

{$svg}

Object referencing svg,
		( download svg)

		<object height="150" width="300" data="hedge/svg?hedge={$ehedge}&url={$url}"
		style="border:5px solid red;" type="image/svg+xml">
		SVG Here
		</object>

SVG xml

		 {fn:serialize($svg)}

Layout xml

		 {fn:serialize($layout)}

Tree xml

		 {fn:serialize($xml)}

About

 Source: @github:, Twitter:
     Tweet
.

};

(:~
: @param hedge
: @param url option location of node xml to use instead of hedge
: @param dl if present add header to force browser download
: @return svg for hedge with download option. cors header
:)
declare
%rest:GET %rest:path("hedge/svg")
%rest:form-param("hedge","{$hedge}")
%rest:form-param("url","{$url}")
%rest:form-param("dl","{$dl}")
%output:media-type("image/svg+xml")
function hedge-svg($hedge,$url,$dl) {
	let $xml:=getxml($hedge,$url)
	let $layout:=tree:layout($xml)
	let $svg:=tree:svg($layout)
	let $resp:=<rest:response>
            <http:response>
            <http:header name="Access-Control-Allow-Origin" value="*"/>
            {if($dl)
            then <http:header name="Content-Disposition" value='attachment;filename="hedge.svg"'/>
            else ()}
           </http:response>
       </rest:response>
	return ($resp,$svg)
};

(:~  use hedge or url :)
declare %private function getxml($hedge,$url){
 if($url) then
    try{fn:doc(fn:resolve-uri($url))/*} catch * { <node label="{$err:description}"/>}
else
	try{ tree:hedge2xml($hedge)} catch * { <node label="{$err:description}"/>}
};

(:~
: trees as svg
: @author andy bunce
: @since sept 2012
:)

module namespace web = 'apb.hedge.web';
declare default function namespace 'apb.hedge.web';
import module namespace tree = 'apb.tree' at "hedgetree/treedraw.xqm";
declare namespace rest = 'http://exquery.org/ns/restxq';

(:~
: main page
:)
declare
%rest:GET %rest:path("hedge")
%output:method("html5")
%rest:form-param("hedge","{$hedge}")
%rest:form-param("url","{$url}")
function hedge($hedge,$url) {
	let $ehedge:=if($url) then "" else fn:encode-for-uri($hedge)
	let $xml:=getxml($hedge,$url)
	let $layout:=tree:layout($xml)
	let $svg:=tree:svg($layout)

	return

		<title>Drawing trees with XQuery and SVG</title>
		<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="tree xquery svg" />

Drawing trees with XQuery and SVG

Enter a  string representing a tree in the form below; use letters for nodes and () to enclose subnodes. Use {{...}} for multi character names. {{name|href}} will create a link. Examples: a(bcd(ef)),
                  another
		buggy: a(bcd)e(fgh).

 Or enter a Url to a xml document examples:
		sample1,
	hedgeweb
	remote

		 <form method="get" action="./hedge" style="background-color:#EEEEEE;padding:8px;">

		 <textarea name="hedge" rows="2" cols="80">{$hedge}</textarea>

Or enter the url to a node XML source
		 <input name="url"  value="{$url}" style="width:30em"/>

		 <button type="submit">Redraw</button>
		</form >

Inline SVG

{$svg}

Object referencing svg,
		( download svg)

		<object height="150" width="300" data="hedge/svg?hedge={$ehedge}&url={$url}"
		style="border:5px solid red;" type="image/svg+xml">
		SVG Here
		</object>

SVG xml

		 {fn:serialize($svg)}

Layout xml

		 {fn:serialize($layout)}

Tree xml

		 {fn:serialize($xml)}

About

 Source: @github:, Twitter:
     Tweet
.

};

(:~
: @param hedge
: @param url option location of node xml to use instead of hedge
: @param dl if present add header to force browser download
: @return svg for hedge with download option. cors header
:)
declare
%rest:GET %rest:path("hedge/svg")
%rest:form-param("hedge","{$hedge}")
%rest:form-param("url","{$url}")
%rest:form-param("dl","{$dl}")
%output:media-type("image/svg+xml")
function hedge-svg($hedge,$url,$dl) {
	let $xml:=getxml($hedge,$url)
	let $layout:=tree:layout($xml)
	let $svg:=tree:svg($layout)
	let $resp:=<rest:response>
            <http:response>
            <http:header name="Access-Control-Allow-Origin" value="*"/>
            {if($dl)
            then <http:header name="Content-Disposition" value='attachment;filename="hedge.svg"'/>
            else ()}
           </http:response>
       </rest:response>
	return ($resp,$svg)
};

(:~  use hedge or url :)
declare %private function getxml($hedge,$url){
 if($url) then
    try{fn:doc(fn:resolve-uri($url))/*} catch * { <node label="{$err:description}"/>}
else
	try{ tree:hedge2xml($hedge)} catch * { <node label="{$err:description}"/>}
};