setup temporal-collection and axes and range indexes required for it

xquery version "1.0-ml";

module namespace bootstrap = "http://marklogic.com/rest-api/resource/bootstrap";
(: Copyright 2002-2010 Mark Logic Corporation.  All Rights Reserved. :)

import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";
import module namespace temporal = "http://marklogic.com/xdmp/temporal" at "/MarkLogic/temporal.xqy";

declare namespace dbx = "http://marklogic.com/xdmp/database";
declare namespace error = "http://marklogic.com/xdmp/error";

declare default function namespace "http://www.w3.org/2005/xpath-functions";
declare option xdmp:mapping "false";

declare function bootstrap:database-configure(
  $dbid as xs:unsignedLong)
as empty-sequence()
{
    let $c := admin:get-configuration()

    (: collection and word lexicons and triple index on :)
    let $c := admin:database-set-collection-lexicon($c, $dbid, true())
    let $c := admin:database-set-maintain-last-modified($c, $dbid, true())
    let $c := admin:database-set-triple-index($c, $dbid, true())

    let $index-specs :=
        let $curr-idx := admin:database-get-range-element-indexes($c, $dbid)
        let $new-idx  := (
            "dateTime", "http://marklogic.com/xdmp/property", "last-modified",
            "string",   "http://nwalsh.com/ns/photolib",      "tag",
            "date",     "http://nwalsh.com/ns/photolib",      "date",
            "double",   "",                                   "double",
            "int",      "",                                   "int",
            "string",   "",                                   "grandchild",
            "string",   "",                                   "string",
            "dateTime", "",                                   "system-start",
            "dateTime", "",                                   "system-end",
            "dateTime", "",                                   "valid-start",
            "dateTime", "",                                   "valid-end"
            )
        for $i in 1 to (count($new-idx) idiv 3)
        let $offset    := ($i * 3) - 2
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $ns        := subsequence($new-idx, $offset + 1, 1)
        let $name      := subsequence($new-idx, $offset + 2, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            string(dbx:namespace-uri) eq $ns and
            tokenize(string(dbx:localname), "\s+") = $name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-element-index(
                $datatype, $ns, $name, $collation, false()
                )

    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-element-index($c, $dbid, $index-specs)

    let $index-specs :=
        let $curr-idx := admin:database-get-range-element-attribute-indexes($c, $dbid)
        let $new-idx  := (
            "date", "http://nwalsh.com/ns/photolib", "view", "", "date"
            )
        for $i in 1 to (count($new-idx) idiv 5)
        let $offset    := ($i * 5) - 4
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $e-ns      := subsequence($new-idx, $offset + 1, 1)
        let $e-name    := subsequence($new-idx, $offset + 2, 1)
        let $a-ns      := subsequence($new-idx, $offset + 3, 1)
        let $a-name    := subsequence($new-idx, $offset + 4, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            string(dbx:parent-namespace-uri) eq $e-ns and
            tokenize(string(dbx:parent-localname), "\s+") = $e-name and
            string(dbx:namespace-uri) eq $a-ns and
            tokenize(string(dbx:localname), "\s+") = $a-name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-element-attribute-index(
                $datatype, $e-ns, $e-name, $a-ns, $a-name, $collation, false()
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-element-attribute-index($c, $dbid, $index-specs)

    let $index-specs :=
        let $curr-idx := admin:database-get-element-word-lexicons($c, $dbid)
        let $new-idx  := (
            "", "suggest"
            )
        for $i in 1 to (count($new-idx) idiv 2)
        let $offset    := ($i * 2) - 1
        let $collation := "http://marklogic.com/collation/"
        let $ns        := subsequence($new-idx, $offset, 1)
        let $name      := subsequence($new-idx, $offset + 1, 1)
        let $curr      := $curr-idx[
            string(dbx:namespace-uri) eq $ns and
            tokenize(string(dbx:localname), "\s+") = $name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-element-word-lexicon($ns, $name, $collation)
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-element-word-lexicon($c, $dbid, $index-specs)

    (: create geospatial indexes for geo unit test :)
    let $index-specs :=
        let $curr-idx := admin:database-get-geospatial-element-pair-indexes($c, $dbid)
        let $p := "http://marklogic.com/ns/test/places"
        let $new-idx  := (
            $p, "place", $p, "lat", $p, "long", "wgs84"
            )
        for $i in 1 to (count($new-idx) idiv 7)
        let $offset    := ($i * 7) - 6
        let $p-ns      := subsequence($new-idx, $offset, 1)
        let $p-name    := subsequence($new-idx, $offset + 1, 1)
        let $lat-ns    := subsequence($new-idx, $offset + 2, 1)
        let $lat-name  := subsequence($new-idx, $offset + 3, 1)
        let $lon-ns    := subsequence($new-idx, $offset + 4, 1)
        let $lon-name  := subsequence($new-idx, $offset + 5, 1)
        let $coord-sys := subsequence($new-idx, $offset + 6, 1)
        let $curr      := $curr-idx[
            string(dbx:parent-namespace-uri) eq $p-ns and
            tokenize(string(dbx:parent-localname), "\s+") = $p-name and
            string(dbx:latitude-namespace-uri) eq $lat-ns and
            tokenize(string(dbx:latitude-localname), "\s+") = $lat-name and
            string(dbx:longitude-namespace-uri) eq $lon-ns and
            tokenize(string(dbx:longitude-localname), "\s+") = $lon-name and
            string(dbx:coordinate-system) eq $coord-sys
            ]
        return
            if (exists($curr)) then ()
            else admin:database-geospatial-element-pair-index(
                $p-ns, $p-name, $lat-ns, $lat-name, $lon-ns, $lon-name, $coord-sys, false()
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-geospatial-element-pair-index($c, $dbid, $index-specs)

    let $def-specs :=
        let $curr-def := admin:database-get-fields($c, $dbid)
        for $new-def in ("int1", "int2")
        let $curr := $curr-def[
            string(dbx:field-name) eq $new-def
            ]
        return
            if (exists($curr)) then ()
            else admin:database-field($new-def, false())
    let $c :=
        if (empty($def-specs)) then $c
        else (
            (: you can't create field and field range index in same transaction :)
            admin:save-configuration-without-restart(
                admin:database-add-field($c, $dbid, $def-specs)
                ),

            admin:get-configuration()
            )

    let $index-specs :=
        let $curr-idx := admin:database-get-range-field-indexes($c, $dbid)
        let $new-idx  := (
            "int", "int1",
            "int", "int2"
            )
        for $i in 1 to (count($new-idx) idiv 2)
        let $offset    := ($i * 2) - 1
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $name      := subsequence($new-idx, $offset + 1, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            tokenize(string(dbx:field-name), "\s+") = $name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-field-index(
                $datatype, $name, $collation, false()
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-field-index($c, $dbid, $index-specs)

    let $index-specs :=
        let $curr-idx := admin:database-get-range-path-indexes($c, $dbid)
        let $new-idx  := (
            "string", "com.marklogic.client.test.City/population",
            "unsignedLong", "com.marklogic.client.test.Country/continent"
            )
        for $i in 1 to (count($new-idx) idiv 2)
        let $offset    := ($i * 2) - 1
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $path      := subsequence($new-idx, $offset + 1, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            string(dbx:path-expression) eq $path and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-path-index(
                $dbid, $datatype, $path, $collation, false(), "ignore"
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-path-index($c, $dbid, $index-specs)

    return admin:save-configuration-without-restart($c)
};

declare function bootstrap:security-config(
$command as xs:string
)
{
    try {
        xdmp:eval(concat('xquery version "1.0-ml"; ',
                    'import module namespace sec="http://marklogic.com/xdmp/security" at  ',
                    '    "/MarkLogic/security.xqy"; ',
                    $command),
        (),
        <options xmlns="xdmp:eval">
            <database>{ xdmp:database("Security") }</database>
        </options>)
    } catch($e) {
        xdmp:log($e)
    }
};

declare function bootstrap:temporal-setup() as xs:string*
{
    try {
        let $id := temporal:axis-create(
            "system-axis",
            cts:element-reference(xs:QName("system-start"), "type=dateTime"),
            cts:element-reference(xs:QName("system-end"), "type=dateTime")
        )
        return if ( $id ) then "Created system-axis" else ()
    } catch($e) {
        if ( "XDMP-ELEMRIDXNOTFOUND" = $e/error:code ) then
            xdmp:log("Couldn't create system-axis.  Waiting for creation of system-start and system-end " ||
                "element range indexes...try again")
        else if ( "TEMPORAL-DUPAXIS" = $e/error:code ) then "system-axis already exists"
        else xdmp:log($e)
    },
    try {
        let $id := temporal:axis-create(
            "valid-axis",
            cts:element-reference(xs:QName("valid-start"), "type=dateTime"),
            cts:element-reference(xs:QName("valid-end"), "type=dateTime")
        )
        return if ( $id ) then "Created valid-axis" else ()
    } catch($e) {
        if ( "XDMP-ELEMRIDXNOTFOUND" = $e/error:code ) then
            xdmp:log("Couldn't create system-axis.  Waiting for creation of valid-start and valid-end " ||
                "element range indexes...try again")
        else if ( "TEMPORAL-DUPAXIS" = $e/error:code ) then "valid-axis already exists"
        else xdmp:log($e)
    },
    try {
        let $id := temporal:collection-create("temporal-collection", "system-axis", "valid-axis")
        return if ( $id ) then "Created temporal-collection" else ()
    } catch($e) {
        if ( "TEMPORAL-AXISNOTFOUND" = $e/error:code ) then
            xdmp:log("Couldn't create temporal-collection.  " ||
                "Waiting for creation of system-axis and valid-axis...try again")
        else if ( "TEMPORAL-DUPCOLLECTION" = $e/error:code ) then "temporal-collection already exists"
        else xdmp:log($e)
    }
};

declare function bootstrap:load-data()
{
    xdmp:eval('xquery version "1.0-ml";
    xdmp:document-insert(
        "/sample/first.xml",
        <root name="first">
            <child id="1">
                <leaf>leaf1</leaf>
            </child>
            <child id="2">
                <leaf>leaf2</leaf>
            </child>
            <child id="3">
                <leaf>leaf3</leaf>
            </child>
        </root>
        ),
    xdmp:document-add-collections("/sample/first.xml",("http://some.org/collection1","http://some.org/collection2")),
    xdmp:document-set-permissions("/sample/first.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/first.xml",
        (
            <sample-property>first</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/second.txt",
        <text><![CDATA[First line
    Second line
    Third line]]></text>/text()
        ),
    xdmp:document-set-permissions("/sample/second.txt",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/second.txt",
        (
            <sample-property>second</sample-property>,
            <container-property><name>beta</name><number>2</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/third.json",
        <text><![CDATA[{
        "firstKey":"first value",
        "secondKey":["first item","second item","third item"],
        "thirdKey":3,
        "fourthKey":{"subKey":"sub value"}
    }]]></text>/text()
        ),
    xdmp:document-set-permissions("/sample/third.json",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/third.json",
        (
            <json:sample-property type="string">third</json:sample-property>,
            <json:container-property type="object">
                <json:name type="string">gamma</json:name>
                <json:number type="number">3</json:number>
            </json:container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/fourth.xml",
    <json:json version="1.0" type="object">
        <json:firstKey type="string">first value</json:firstKey>
        <json:fourthKey type="object">
            <json:subKey type="string">sub value</json:subKey>
        </json:fourthKey>
        <json:secondKey type="array">
            <json:item type="string">first item</json:item>
            <json:item type="string">second item</json:item>
            <json:item type="string">third item</json:item>
        </json:secondKey>
        <json:thirdKey type="number">3</json:thirdKey>
    </json:json>
        ),
    xdmp:document-set-permissions("/sample/fourth.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/fourth.xml",
        (
            <sample-property>fourth</sample-property>,
            <container-property><name>delta</name><number>4</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/fifth.sh",
            <text><![CDATA[#!/bin/sh
    echo "hello, world"
    ]]></text>/text()
        ),
    xdmp:document-set-permissions("/sample/fifth.sh",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/fifth.sh",
        (
            <sample-property>fifth</sample-property>,
            <container-property><name>epsilon</name><number>5</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/databases-icon-mini.png",
    binary{xs:hexBinary(xs:base64Binary(
    "iVBORw0KGgoAAAANSUhEUgAAAA0AAAATCAYAAABLN4eXAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oIEQEjMtAYogQAAAKvSURBVCjPlZLLbhxFAEVPVVdXVz/G8zCOn0CsKGyQkSIIKzas8xfsWbLkp/gJhCKheIlAJDaj2MYez6u7p7vrxQKUPVc6+yOdK77/4cfXQohJqlOVZdmBSpKY6jQKBM45oVMlgHvrvMuNWRljvlNKq69G2YyqLDg4mLE/2yPNYFRWlFXF/nTC2clRWbc7Fss1IcZzqTA8eWY5eu7p1Hv+WvyBVjnGZOQmI9UKISUqSXDO0bS7Tko0xfGSp18kjM7v+P3+NUMr8T5grWMYLCEErHM474khoCw1t78eU/8mEOpjXpxekJUORIZSCbkxSCnRWpPnBikTqbx31E1DjJHpeIzRhnW9xceI857H5Yr1Zku765jf3DIMtlUAIQRCiFhnabsOH1IEAmstAGWRY11ApykmM0oplTKZjNGZREpJoUueHI0ZFRV7exX7+1Nm0yn9YLm5u2fX96lUseLwxQ0vX8H04i2/XP9Et5H44OkHS920hBDo+56u77GDjcrHjvV1ya3TDO2M01mOUAEAhED+R5IkpKmCiFCOjoc/p+xuLbPpCc+P95HaEqIBIhHoB8t2W/PwsKBudl5FH7GxwUYYouJh5ci7nLbtWW02LBaPvLuef1AdrItKKolJpkivwGrG5QxTCsq8pCxLqqrk7PiIwTmW6y0xRCVTSg4vFnz+raM4+5ur1RtSUZHnOUWeMx5VVFWJTlOstfTWRuk96NIyOUgRRc188RZvgRg/3OffjoFESohxUMvmjqufP+X+MqDTU77+5EvMKKBUQpZpijxHSkluDHvjMW8uL79Rnz07bwSyzDLFqCzwDNw/PNI0O9bbhvVmQ7vb0bQdi+Wq327rl+rko8krodKnCHnofJju+r5oupBstg1KJT7Vuruev185O9zVm/WVUmouYoz83/0DxhRmafe2kasAAAAASUVORK5CYII="
    ))}
        ),
    xdmp:document-insert(
        "/sample/databases-icon-mini.xhtml",
    <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
      <xhtml:head>
        <xhtml:meta name="content-type" content="image/png"/>
        <xhtml:meta name="filter-capabilities" content="none"/>
        <xhtml:meta name="size" content="815"/>
        <xhtml:meta name="MarkLogic_Binary_Source" content="/sample/databases-icon-mini.png"/>
      </xhtml:head>
    </xhtml:html>
    ),
    xdmp:document-set-permissions("/sample/databases-icon-mini.png",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-permissions("/sample/databases-icon-mini.xhtml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate2.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all2.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all3.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all3.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all4.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all4.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate-json2.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate-json2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all-json2.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all-json2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all-json3.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all-json3.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/prop-only.xml",
        (
            <sample-property>first</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-set-properties(
        "/sample/prop-only.json",
        (
            <json:sample-property type="string">third</json:sample-property>,
            <json:container-property type="object">
                <json:name type="string">gamma</json:name>
                <json:number type="number">3</json:number>
            </json:container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/invalid-separate.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/invalid-separate.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/invalid-all.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/invalid-all.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/invalid-separate-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/invalid-separate-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/invalid-all-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/invalid-all-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/lexicon-test1.xml",
        <root name="first">
            <child id="1">
                <grandchild>grandchild1</grandchild>
            </child>
            <child id="2">
                <grandchild>grandchild2</grandchild>
            </child>
            <child id="3">
                <grandchild>grandchild3</grandchild>
            </child>
        </root>
        ),
    xdmp:document-add-collections("/sample/lexicon-test1.xml",("http://some.org/collection1","http://some.org/collection2")),
    xdmp:document-set-permissions("/sample/lexicon-test1.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/lexicon-test1.xml",
        (
            <sample-property>lexicon-test</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/lexicon-test2.xml",
        <root name="first">
            <child id="1">
                <grandchild>grandchild4</grandchild>
            </child>
            <child id="2">
                <grandchild>grandchild5</grandchild>
            </child>
            <child id="3">
                <grandchild>grandchild6</grandchild>
            </child>
        </root>
        ),
    xdmp:document-add-collections("/sample/lexicon-test2.xml",("http://some.org/collection1","http://some.org/collection2")),
    xdmp:document-set-permissions("/sample/lexicon-test2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/lexicon-test2.xml",
        (
            <sample-property>lexicon-test</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/lexicon-test3.xml",
        <root name="first">
            <child id="1">
                <double>1.2</double>
                <int>10</int>
            </child>
            <child id="2">
                <double>2.3</double>
                <int>20</int>
            </child>
        </root>
        ),
    xdmp:document-set-permissions("/sample/lexicon-test3.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/lexicon-test4.xml",
        <root name="second">
            <child id="3">
                <double>2.2</double>
                <int>30</int>
            </child>
            <child id="5">
                <double>1.2</double>
                <int>10</int>
            </child>
             <child id="6">
                <double>1.2</double>
                <int>4</int>
            </child>
        </root>
        ),
    xdmp:document-set-permissions("/sample/lexicon-test4.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/udf-test.xml",
        <root name="first">
            <element-test attribute-test="1"/>
            <element-test attribute-test="5"/>
            <element-test attribute-test="9"/>
        </root>),
xdmp:document-insert(
    "/sample/tuples-test1.xml",
    <root name="first">
        <child id="1">
            <double>1.1</double>
            <int>1</int>
            <string>Alaska</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test1.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
xdmp:document-insert(
    "/sample/tuples-test2.xml",
    <root name="second">
        <child id="3">
            <double>1.1</double>
            <int>3</int>
            <string>Birmingham</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test2.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
xdmp:document-insert(
    "/sample/tuples-test3.xml",
    <root name="second">
        <child id="3">
            <double>1.2</double>
            <int>3</int>
            <string>Birmingham</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test3.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
xdmp:document-insert(
    "/sample/tuples-test4.xml",
    <root name="second">
        <child id="3">
            <double>1.2</double>
            <int>3</int>
            <string>Alaska</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test4.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
    xdmp:document-set-permissions("/sample/udf-test.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/legacy space file.xml",
        <samplelegacy>document</samplelegacy>
        ),
    xdmp:document-set-permissions("/sample/legacy space file.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"))
        ),

    xdmp:document-insert("/sample/suggestion.xml",
        <suggest><string>FINDME</string>Something I love to suggest is sugar with savory succulent limes.</suggest>),
    xdmp:document-set-permissions("/sample/suggestion.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"))
        ),
    xdmp:document-add-collections("/sample/suggestion.xml",("http://some.org/complexsuggestions")),
    xdmp:document-insert("/sample2/suggestion.xml",
        <suggest>Something I hate to suggest is liver with lard.</suggest>),
    xdmp:document-set-permissions("/sample2/suggestion.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"))
            ),
    xdmp:document-add-collections("/sample2/suggestion.xml",("http://some.org/suggestions"))
'
    )
};

declare function bootstrap:load-search-data()
{
    ()
};

declare function bootstrap:post(
    $context as map:map,
    $params  as map:map,
    $input as document-node()*
) as document-node()*
{
    let $responses := (
        for $user in ("rest-admin", "rest-reader", "rest-writer", "valid")
        let $user-id :=
            try {
                xdmp:user($user)
            } catch($e) {
                xdmp:log("User "||$user||" not found.")
            }
        return
            if (exists($user-id)) then xdmp:log("User "|| $user || ", id "||$user-id|| "already exists")
            else if ($user eq "valid")
            then bootstrap:security-config('sec:create-user("valid", "valid unprivileged user", "x", (), (), (), ())')
            else bootstrap:security-config('sec:create-user("'||$user||'", "'||$user||' user", "x", ("'||$user||'"), (), (), () )'),

        let $dbid := xdmp:database("java-unittest")
        return (
            bootstrap:database-configure($dbid),
            xdmp:log(concat("Configured Java test database:", xdmp:database-name($dbid)))
            ),

        bootstrap:temporal-setup(),
        bootstrap:load-data()
    )
    return if ( $responses ) then
        document{<responses>{
            for $response in $responses
            return <response>{$response}</response>
        }</responses>}
    else ()
};

xquery version "1.0-ml";

module namespace bootstrap = "http://marklogic.com/rest-api/resource/bootstrap";
(: Copyright 2002-2010 Mark Logic Corporation.  All Rights Reserved. :)

import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";

declare namespace dbx = "http://marklogic.com/xdmp/database";

declare default function namespace "http://www.w3.org/2005/xpath-functions";
declare option xdmp:mapping "false";

declare function bootstrap:database-configure(
  $dbid as xs:unsignedLong)
as empty-sequence()
{
    let $c := admin:get-configuration()

    (: collection and word lexicons and triple index on :)
    let $c := admin:database-set-collection-lexicon($c, $dbid, true())
    let $c := admin:database-set-maintain-last-modified($c, $dbid, true())
    let $c := admin:database-set-triple-index($c, $dbid, true())

    let $index-specs :=
        let $curr-idx := admin:database-get-range-element-indexes($c, $dbid)
        let $new-idx  := (
            "dateTime", "http://marklogic.com/xdmp/property", "last-modified",
            "string",   "http://nwalsh.com/ns/photolib",      "tag",
            "date",     "http://nwalsh.com/ns/photolib",      "date",
            "double",   "",                                   "double",
            "int",      "",                                   "int",
            "string",   "",                                   "grandchild",
            "string",   "",                                   "string"
            )
        for $i in 1 to (count($new-idx) idiv 3)
        let $offset    := ($i * 3) - 2
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $ns        := subsequence($new-idx, $offset + 1, 1)
        let $name      := subsequence($new-idx, $offset + 2, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            string(dbx:namespace-uri) eq $ns and
            tokenize(string(dbx:localname), "\s+") = $name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-element-index(
                $datatype, $ns, $name, $collation, false()
                )

    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-element-index($c, $dbid, $index-specs)

    let $index-specs :=
        let $curr-idx := admin:database-get-range-element-attribute-indexes($c, $dbid)
        let $new-idx  := (
            "date", "http://nwalsh.com/ns/photolib", "view", "", "date"
            )
        for $i in 1 to (count($new-idx) idiv 5)
        let $offset    := ($i * 5) - 4
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $e-ns      := subsequence($new-idx, $offset + 1, 1)
        let $e-name    := subsequence($new-idx, $offset + 2, 1)
        let $a-ns      := subsequence($new-idx, $offset + 3, 1)
        let $a-name    := subsequence($new-idx, $offset + 4, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            string(dbx:parent-namespace-uri) eq $e-ns and
            tokenize(string(dbx:parent-localname), "\s+") = $e-name and
            string(dbx:namespace-uri) eq $a-ns and
            tokenize(string(dbx:localname), "\s+") = $a-name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-element-attribute-index(
                $datatype, $e-ns, $e-name, $a-ns, $a-name, $collation, false()
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-element-attribute-index($c, $dbid, $index-specs)

    let $index-specs :=
        let $curr-idx := admin:database-get-element-word-lexicons($c, $dbid)
        let $new-idx  := (
            "", "suggest"
            )
        for $i in 1 to (count($new-idx) idiv 2)
        let $offset    := ($i * 2) - 1
        let $collation := "http://marklogic.com/collation/"
        let $ns        := subsequence($new-idx, $offset, 1)
        let $name      := subsequence($new-idx, $offset + 1, 1)
        let $curr      := $curr-idx[
            string(dbx:namespace-uri) eq $ns and
            tokenize(string(dbx:localname), "\s+") = $name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-element-word-lexicon($ns, $name, $collation)
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-element-word-lexicon($c, $dbid, $index-specs)

    (: create geospatial indexes for geo unit test :)
    let $index-specs :=
        let $curr-idx := admin:database-get-geospatial-element-pair-indexes($c, $dbid)
        let $p := "http://marklogic.com/ns/test/places"
        let $new-idx  := (
            $p, "place", $p, "lat", $p, "long", "wgs84"
            )
        for $i in 1 to (count($new-idx) idiv 7)
        let $offset    := ($i * 7) - 6
        let $p-ns      := subsequence($new-idx, $offset, 1)
        let $p-name    := subsequence($new-idx, $offset + 1, 1)
        let $lat-ns    := subsequence($new-idx, $offset + 2, 1)
        let $lat-name  := subsequence($new-idx, $offset + 3, 1)
        let $lon-ns    := subsequence($new-idx, $offset + 4, 1)
        let $lon-name  := subsequence($new-idx, $offset + 5, 1)
        let $coord-sys := subsequence($new-idx, $offset + 6, 1)
        let $curr      := $curr-idx[
            string(dbx:parent-namespace-uri) eq $p-ns and
            tokenize(string(dbx:parent-localname), "\s+") = $p-name and
            string(dbx:latitude-namespace-uri) eq $lat-ns and
            tokenize(string(dbx:latitude-localname), "\s+") = $lat-name and
            string(dbx:longitude-namespace-uri) eq $lon-ns and
            tokenize(string(dbx:longitude-localname), "\s+") = $lon-name and
            string(dbx:coordinate-system) eq $coord-sys
            ]
        return
            if (exists($curr)) then ()
            else admin:database-geospatial-element-pair-index(
                $p-ns, $p-name, $lat-ns, $lat-name, $lon-ns, $lon-name, $coord-sys, false()
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-geospatial-element-pair-index($c, $dbid, $index-specs)

    let $def-specs :=
        let $curr-def := admin:database-get-fields($c, $dbid)
        for $new-def in ("int1", "int2")
        let $curr := $curr-def[
            string(dbx:field-name) eq $new-def
            ]
        return
            if (exists($curr)) then ()
            else admin:database-field($new-def, false())
    let $c :=
        if (empty($def-specs)) then $c
        else (
            (: you can't create field and field range index in same transaction :)
            admin:save-configuration-without-restart(
                admin:database-add-field($c, $dbid, $def-specs)
                ),

            admin:get-configuration()
            )

    let $index-specs :=
        let $curr-idx := admin:database-get-range-field-indexes($c, $dbid)
        let $new-idx  := (
            "int", "int1",
            "int", "int2"
            )
        for $i in 1 to (count($new-idx) idiv 2)
        let $offset    := ($i * 2) - 1
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $name      := subsequence($new-idx, $offset + 1, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            tokenize(string(dbx:field-name), "\s+") = $name and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-field-index(
                $datatype, $name, $collation, false()
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-field-index($c, $dbid, $index-specs)

    let $index-specs :=
        let $curr-idx := admin:database-get-range-path-indexes($c, $dbid)
        let $new-idx  := (
            "string", "com.marklogic.client.test.City/population",
            "unsignedLong", "com.marklogic.client.test.Country/continent"
            )
        for $i in 1 to (count($new-idx) idiv 2)
        let $offset    := ($i * 2) - 1
        let $datatype  := subsequence($new-idx, $offset, 1)
        let $collation :=
            if ($datatype eq "string")
            then "http://marklogic.com/collation/"
            else ""
        let $path      := subsequence($new-idx, $offset + 1, 1)
        let $curr      := $curr-idx[
            string(dbx:scalar-type) eq $datatype and
            string(dbx:path-expression) eq $path and
            string(dbx:collation) eq $collation
            ]
        return
            if (exists($curr)) then ()
            else admin:database-range-path-index(
                $dbid, $datatype, $path, $collation, false(), "ignore"
                )
    let $c :=
        if (empty($index-specs)) then $c
        else admin:database-add-range-path-index($c, $dbid, $index-specs)

    return admin:save-configuration-without-restart($c)
};

declare function bootstrap:security-config(
$command as xs:string
)
{
    try {
        xdmp:eval(concat('xquery version "1.0-ml"; ',
                    'import module namespace sec="http://marklogic.com/xdmp/security" at  ',
                    '    "/MarkLogic/security.xqy"; ',
                    $command),
        (),
        <options xmlns="xdmp:eval">
            <database>{ xdmp:database("Security") }</database>
        </options>)
    } catch($e) {
        xdmp:log($e)
    }
};

declare function bootstrap:load-data()
{
    xdmp:eval('xquery version "1.0-ml";
    xdmp:document-insert(
        "/sample/first.xml",
        <root name="first">
            <child id="1">
                <leaf>leaf1</leaf>
            </child>
            <child id="2">
                <leaf>leaf2</leaf>
            </child>
            <child id="3">
                <leaf>leaf3</leaf>
            </child>
        </root>
        ),
    xdmp:document-add-collections("/sample/first.xml",("http://some.org/collection1","http://some.org/collection2")),
    xdmp:document-set-permissions("/sample/first.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/first.xml",
        (
            <sample-property>first</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/second.txt",
        <text><![CDATA[First line
    Second line
    Third line]]></text>/text()
        ),
    xdmp:document-set-permissions("/sample/second.txt",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/second.txt",
        (
            <sample-property>second</sample-property>,
            <container-property><name>beta</name><number>2</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/third.json",
        <text><![CDATA[{
        "firstKey":"first value",
        "secondKey":["first item","second item","third item"],
        "thirdKey":3,
        "fourthKey":{"subKey":"sub value"}
    }]]></text>/text()
        ),
    xdmp:document-set-permissions("/sample/third.json",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/third.json",
        (
            <json:sample-property type="string">third</json:sample-property>,
            <json:container-property type="object">
                <json:name type="string">gamma</json:name>
                <json:number type="number">3</json:number>
            </json:container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/fourth.xml",
    <json:json version="1.0" type="object">
        <json:firstKey type="string">first value</json:firstKey>
        <json:fourthKey type="object">
            <json:subKey type="string">sub value</json:subKey>
        </json:fourthKey>
        <json:secondKey type="array">
            <json:item type="string">first item</json:item>
            <json:item type="string">second item</json:item>
            <json:item type="string">third item</json:item>
        </json:secondKey>
        <json:thirdKey type="number">3</json:thirdKey>
    </json:json>
        ),
    xdmp:document-set-permissions("/sample/fourth.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/fourth.xml",
        (
            <sample-property>fourth</sample-property>,
            <container-property><name>delta</name><number>4</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/fifth.sh",
            <text><![CDATA[#!/bin/sh
    echo "hello, world"
    ]]></text>/text()
        ),
    xdmp:document-set-permissions("/sample/fifth.sh",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/fifth.sh",
        (
            <sample-property>fifth</sample-property>,
            <container-property><name>epsilon</name><number>5</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/databases-icon-mini.png",
    binary{xs:hexBinary(xs:base64Binary(
    "iVBORw0KGgoAAAANSUhEUgAAAA0AAAATCAYAAABLN4eXAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oIEQEjMtAYogQAAAKvSURBVCjPlZLLbhxFAEVPVVdXVz/G8zCOn0CsKGyQkSIIKzas8xfsWbLkp/gJhCKheIlAJDaj2MYez6u7p7vrxQKUPVc6+yOdK77/4cfXQohJqlOVZdmBSpKY6jQKBM45oVMlgHvrvMuNWRljvlNKq69G2YyqLDg4mLE/2yPNYFRWlFXF/nTC2clRWbc7Fss1IcZzqTA8eWY5eu7p1Hv+WvyBVjnGZOQmI9UKISUqSXDO0bS7Tko0xfGSp18kjM7v+P3+NUMr8T5grWMYLCEErHM474khoCw1t78eU/8mEOpjXpxekJUORIZSCbkxSCnRWpPnBikTqbx31E1DjJHpeIzRhnW9xceI857H5Yr1Zku765jf3DIMtlUAIQRCiFhnabsOH1IEAmstAGWRY11ApykmM0oplTKZjNGZREpJoUueHI0ZFRV7exX7+1Nm0yn9YLm5u2fX96lUseLwxQ0vX8H04i2/XP9Et5H44OkHS920hBDo+56u77GDjcrHjvV1ya3TDO2M01mOUAEAhED+R5IkpKmCiFCOjoc/p+xuLbPpCc+P95HaEqIBIhHoB8t2W/PwsKBudl5FH7GxwUYYouJh5ci7nLbtWW02LBaPvLuef1AdrItKKolJpkivwGrG5QxTCsq8pCxLqqrk7PiIwTmW6y0xRCVTSg4vFnz+raM4+5ur1RtSUZHnOUWeMx5VVFWJTlOstfTWRuk96NIyOUgRRc188RZvgRg/3OffjoFESohxUMvmjqufP+X+MqDTU77+5EvMKKBUQpZpijxHSkluDHvjMW8uL79Rnz07bwSyzDLFqCzwDNw/PNI0O9bbhvVmQ7vb0bQdi+Wq327rl+rko8krodKnCHnofJju+r5oupBstg1KJT7Vuruev185O9zVm/WVUmouYoz83/0DxhRmafe2kasAAAAASUVORK5CYII="
    ))}
        ),
    xdmp:document-insert(
        "/sample/databases-icon-mini.xhtml",
    <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
      <xhtml:head>
        <xhtml:meta name="content-type" content="image/png"/>
        <xhtml:meta name="filter-capabilities" content="none"/>
        <xhtml:meta name="size" content="815"/>
        <xhtml:meta name="MarkLogic_Binary_Source" content="/sample/databases-icon-mini.png"/>
      </xhtml:head>
    </xhtml:html>
    ),
    xdmp:document-set-permissions("/sample/databases-icon-mini.png",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-permissions("/sample/databases-icon-mini.xhtml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate2.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all2.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all3.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all3.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all4.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all4.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-separate-json2.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-separate-json2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all-json2.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all-json2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/metadata-all-json3.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/metadata-all-json3.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/prop-only.xml",
        (
            <sample-property>first</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-set-properties(
        "/sample/prop-only.json",
        (
            <json:sample-property type="string">third</json:sample-property>,
            <json:container-property type="object">
                <json:name type="string">gamma</json:name>
                <json:number type="number">3</json:number>
            </json:container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/invalid-separate.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/invalid-separate.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/invalid-all.xml",
        <metadata-target/>
        ),
    xdmp:document-set-permissions("/sample/invalid-all.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/invalid-separate-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/invalid-separate-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/invalid-all-json.xml",
        <json:json type="object"/>
        ),
    xdmp:document-set-permissions("/sample/invalid-all-json.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/lexicon-test1.xml",
        <root name="first">
            <child id="1">
                <grandchild>grandchild1</grandchild>
            </child>
            <child id="2">
                <grandchild>grandchild2</grandchild>
            </child>
            <child id="3">
                <grandchild>grandchild3</grandchild>
            </child>
        </root>
        ),
    xdmp:document-add-collections("/sample/lexicon-test1.xml",("http://some.org/collection1","http://some.org/collection2")),
    xdmp:document-set-permissions("/sample/lexicon-test1.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/lexicon-test1.xml",
        (
            <sample-property>lexicon-test</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/lexicon-test2.xml",
        <root name="first">
            <child id="1">
                <grandchild>grandchild4</grandchild>
            </child>
            <child id="2">
                <grandchild>grandchild5</grandchild>
            </child>
            <child id="3">
                <grandchild>grandchild6</grandchild>
            </child>
        </root>
        ),
    xdmp:document-add-collections("/sample/lexicon-test2.xml",("http://some.org/collection1","http://some.org/collection2")),
    xdmp:document-set-permissions("/sample/lexicon-test2.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-set-properties(
        "/sample/lexicon-test2.xml",
        (
            <sample-property>lexicon-test</sample-property>,
            <container-property><name>alpha</name><number>1</number></container-property>
            )
        ),
    xdmp:document-insert(
        "/sample/lexicon-test3.xml",
        <root name="first">
            <child id="1">
                <double>1.2</double>
                <int>10</int>
            </child>
            <child id="2">
                <double>2.3</double>
                <int>20</int>
            </child>
        </root>
        ),
    xdmp:document-set-permissions("/sample/lexicon-test3.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/lexicon-test4.xml",
        <root name="second">
            <child id="3">
                <double>2.2</double>
                <int>30</int>
            </child>
            <child id="5">
                <double>1.2</double>
                <int>10</int>
            </child>
             <child id="6">
                <double>1.2</double>
                <int>4</int>
            </child>
        </root>
        ),
    xdmp:document-set-permissions("/sample/lexicon-test4.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/udf-test.xml",
        <root name="first">
            <element-test attribute-test="1"/>
            <element-test attribute-test="5"/>
            <element-test attribute-test="9"/>
        </root>),
xdmp:document-insert(
    "/sample/tuples-test1.xml",
    <root name="first">
        <child id="1">
            <double>1.1</double>
            <int>1</int>
            <string>Alaska</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test1.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
xdmp:document-insert(
    "/sample/tuples-test2.xml",
    <root name="second">
        <child id="3">
            <double>1.1</double>
            <int>3</int>
            <string>Birmingham</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test2.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
xdmp:document-insert(
    "/sample/tuples-test3.xml",
    <root name="second">
        <child id="3">
            <double>1.2</double>
            <int>3</int>
            <string>Birmingham</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test3.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
xdmp:document-insert(
    "/sample/tuples-test4.xml",
    <root name="second">
        <child id="3">
            <double>1.2</double>
            <int>3</int>
            <string>Alaska</string>
        </child>
    </root>
    ),
xdmp:document-set-permissions("/sample/tuples-test4.xml",
    (xdmp:permission("rest-reader","read"),
    xdmp:permission("rest-writer","update"),
    xdmp:permission("app-user","read"),
    xdmp:permission("app-user","update"))
    ),
    xdmp:document-set-permissions("/sample/udf-test.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"),
        xdmp:permission("app-user","read"),
        xdmp:permission("app-user","update"))
        ),
    xdmp:document-insert(
        "/sample/legacy space file.xml",
        <samplelegacy>document</samplelegacy>
        ),
    xdmp:document-set-permissions("/sample/legacy space file.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"))
        ),

    xdmp:document-insert("/sample/suggestion.xml",
        <suggest><string>FINDME</string>Something I love to suggest is sugar with savory succulent limes.</suggest>),
    xdmp:document-set-permissions("/sample/suggestion.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"))
        ),
    xdmp:document-add-collections("/sample/suggestion.xml",("http://some.org/complexsuggestions")),
    xdmp:document-insert("/sample2/suggestion.xml",
        <suggest>Something I hate to suggest is liver with lard.</suggest>),
    xdmp:document-set-permissions("/sample2/suggestion.xml",
        (xdmp:permission("rest-reader","read"),
        xdmp:permission("rest-writer","update"))
            ),
    xdmp:document-add-collections("/sample2/suggestion.xml",("http://some.org/suggestions"))
'
    )
};

declare function bootstrap:load-search-data()
{
    ()
};

declare function bootstrap:post(
    $context as map:map,
    $params  as map:map,
    $input as document-node()*
) as document-node()*
{
    for $user in ("rest-admin", "rest-reader", "rest-writer", "valid")
    let $user-id :=
        try {
            xdmp:user($user)
        } catch($e) {
            xdmp:log("User "||$user||" not found.")
        }
    return
        if (exists($user-id)) then xdmp:log("User "|| $user || ", id "||$user-id|| "already exists")
        else if ($user eq "valid")
        then bootstrap:security-config('sec:create-user("valid", "valid unprivileged user", "x", (), (), (), ())')
        else bootstrap:security-config('sec:create-user("'||$user||'", "'||$user||' user", "x", ("'||$user||'"), (), (), () )'),

    let $dbid := xdmp:database("java-unittest")
    return (
        bootstrap:database-configure($dbid),
        xdmp:log(concat("Configured Java test database:", xdmp:database-name($dbid)))
        ),

    bootstrap:load-data()
};


Updated dataSetId as xs:string external

Updated dataSetId as xs:string external

(:
 : Copyright (C) [2013] [The FURTHeR Project]
 :
 : 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.
 :)
xquery version "3.0";
(: import module namespace frt = "http://further.utah.edu/result-translation"
    at 'frt.xqm'; :)
import module namespace frt = "http://further.utah.edu/result-translation"
    at '${server.mdr.ws}${path.mdr.ws.resource.path}/result/frt.xqm';

(: ALWAYS PUT THIS IN THE XQUERY PROLOG! :)
declare namespace fn  = 'http://www.w3.org/2005/xpath-functions';
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare namespace fq = "http://further.utah.edu/core/query";

(: Turn On the Option to Output the <xml> heading on the first Line :)
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:omit-xml-declaration "no";

(: Set docName :)
declare variable $docName as document-node() external;

(: Get Source Namespace ID from External :)
declare variable $srcNmspcId as xs:string external;

(: Set DataSet ID :)
declare variable $dataSetId as xs:string external;

(: END PROLOG :)

(:==================================================================:)
(: Call Main Translate Query Function                               :)
(:==================================================================:)

(: Sanitize Data to Prevent XQuery Injection Attacks :)
let $sanitizedDoc := frt:sanitize($docName)

(: Use the Source Namespace ID instead of Namespace Name :)
return frt:transResult($sanitizedDoc,$srcNmspcId,$dataSetId)

(:
 : Copyright (C) [2013] [The FURTHeR Project]
 :
 : 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.
 :)
xquery version "3.0";
(: import module namespace frt = "http://further.utah.edu/result-translation"
    at 'frt.xqm'; :)
import module namespace frt = "http://further.utah.edu/result-translation"
    at '${server.mdr.ws}${path.mdr.ws.resource.path}/result/frt.xqm';

(: ALWAYS PUT THIS IN THE XQUERY PROLOG! :)
declare namespace fn  = 'http://www.w3.org/2005/xpath-functions';
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare namespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
declare namespace fq = "http://further.utah.edu/core/query";

(: Turn On the Option to Output the <xml> heading on the first Line :)
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:omit-xml-declaration "no";

(: Set docName :)
declare variable $docName as document-node() external;

(: Get Source Namespace ID from External :)
declare variable $srcNmspcId as xs:string external;

(: Set DataSet ID :)
declare variable $dataSetId as document-node() external;

(: END PROLOG :)

(:==================================================================:)
(: Call Main Translate Query Function                               :)
(:==================================================================:)

(: Sanitize Data to Prevent XQuery Injection Attacks :)
let $sanitizedDoc := frt:sanitize($docName)

(: Use the Source Namespace ID instead of Namespace Name :)
return frt:transResult($sanitizedDoc,$srcNmspcId,$dataSetId)


Refined offending tests

Refined offending tests

svn path=/trunk/eXist-1.0/; revision=3699

declare namespace xqts="http://exist-db.org/xquery/xqts";
declare namespace catalog="http://www.w3.org/2005/02/query-test-XQTSCatalog";

declare namespace props="java:java.io.File";

import module namespace util="http://exist-db.org/xquery/util";
import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace xdiff="http://exist-db.org/xquery/xmldiff"
at "java:org.exist.xquery.modules.xmldiff.XmlDiffModule";
import module namespace request="http://exist-db.org/xquery/request";

(:~ ----------------------------------------------------------------------------------------
     W3C XQuery Test Suite

     This is the main module for running the XQTS on eXist. You can either
     run the whole test suite, a specific test group or a single test case.

     Setup:

     * Make sure the XmlDiff module is registered in conf.xml

     * Edit config.xml and change basedir to point to the directory into
     which you unzipped the XQTS sources. Note: it needs to be an URI.

     * Create a collection /db/XQTS in the database.

     * From the XQTS directory, upload XQTSCatalog.xml into the created
     collection.

     * Upload the "TestSources" directory so the source docs can be found
     in /db/XQTS/TestSources.

     * Run this script with the client.
     ------------------------------------------------------------------------------------------- :)
declare variable $xqts:CONFIG { xqts:initialize() };
declare variable $xqts:XQTS_HOME { xqts:path-to-uri($xqts:CONFIG/basedir/text()) };

declare function xqts:initialize() as element() {
    let $home := util:system-property("exist.home")
    let $path := concat($home, "/webapp/xqts")
    let $collection := xdb:create-collection("/db", "XQTS")
    let $config0 := doc("/db/XQTS")/config
    let $config :=
        if ($config0) then
            $config0
        else
            let $stored := xdb:store-files-from-pattern("/db/XQTS", $path, "*.xml", "text/xml")
            return
                doc("/db/XQTS/config.xml")/config
    let $xqtsHome := $config/basedir/text()
    let $catalog0 := doc("/db/XQTS/XQTSCatalog.xml")
    let $catalog :=
        if ($catalog0) then $catalog0
        else
            xdb:store($collection, "XQTSCatalog.xml",
                xs:anyURI(xqts:path-to-uri(concat($xqtsHome, "XQTSCatalog.xml"))))
    let $sources0 := collection("/db/XQTS/TestSources")
    let $sources :=
        if ($sources0) then
            $sources0
        else
            let $sourceCol := xdb:create-collection("/db/XQTS", "TestSources")
            return
                xdb:store-files-from-pattern($sourceCol, concat($xqtsHome, "TestSources"), "*.xml", "text/xml")
    return
        $config
};

declare function xqts:path-to-uri($path as xs:string) as xs:string {
        if (starts-with($path, "/")) then
            concat("file://", $path)
        else
            concat("file:///", $path)
};

declare function xqts:create-progress-file($testCount as xs:int) as empty() {
    let $results := xdb:store("/db/XQTS", "progress.xml",
        <progress total="{$testCount}" done="0" failed="0" passed="0"/>)
    return ()
};

declare function xqts:report-progress($test-case as element()) as empty() {
    let $result := string($test-case/@result)
    let $progress := doc("/db/XQTS/progress.xml")/progress
    let $counter := $progress/@done
    return (
        update value $counter with xs:int($counter + 1),
        if ($result eq 'fail') then
            update value $progress/@failed with xs:int($progress/@failed + 1)
        else
            update value $progress/@passed with xs:int($progress/@passed + 1)
    )
};

declare function xqts:create-collections($group as element(catalog:test-group)) as node() {
    let $rootColl := xdb:create-collection("/db/XQTS", "test-results")
    let $ancestors := reverse(($group/ancestor::catalog:test-group, $group))
    let $collection := xqts:create-collections($rootColl, $ancestors, "/db/XQTS/test-results")
    let $results := xdb:store($collection, "results.xml", <test-result failed="0" passed="0"/>)
    return
        doc($results)
};

declare function xqts:create-collections($parent as object,
    $pathElements as element()+, $currentPath as xs:string)
as object {
    let $next := $pathElements[last()]
    let $remainder := subsequence($pathElements, 1, count($pathElements) - 1)
    let $newColl := xdb:create-collection($parent, $next/@name)
    return
        if ($remainder) then
            xqts:create-collections($newColl, $remainder, concat($currentPath, "/", $next/@name))
        else
            $newColl
};

declare function xqts:get-query($case as element(catalog:test-case)) {
   let $query-name := $case//catalog:query/@name
   let $path := concat( $xqts:XQTS_HOME, "Queries/XQuery/", $case/@FilePath, $query-name, ".xq" )
   let $xq-string := util:file-read($path)
   return $xq-string
};

declare function xqts:print-result($test-name as xs:string, $passed as xs:boolean, $query as xs:string,
    $result as item()*, $expected as item()*, $case as element(catalog:test-case)) as element() {
    <test-case name="{$test-name}" result="{if ($passed) then 'pass' else 'fail'}">
    {
        if (not($passed)) then (
            <result>{$result}</result>,
            if ($expected instance of element() and count($expected/*) > 10) then
            	<expected truncated="">{$expected/*[position() < 10]}</expected>
            else
                <expected>{$expected}</expected>,
            (: element {$case/catalog:input-file/@variable} { xqts:getInputValue($case) }, :)
            <query>{$query}</query>
        ) else ()
    }
    </test-case>
};

declare function xqts:normalize-text($result as item()*) as xs:string {
    let $str := string-join($result, " ")
    return
        (: Remove leading and trailing whitespace :)
        replace(replace($str, "^\s+", ""), "\s+$", "")
};

declare function xqts:check-output($query as xs:string, $result as item()*, $case as element(catalog:test-case)) {
    let $output := $case/catalog:output-file[last()]
    return
        (: Expected an error, but got a result :)
        if (exists($case/catalog:expected-error)) then
            <test-case name="{$case/@name}" result="fail">
                   <expected-error>{$case/catalog:expected-error/text()}</expected-error>
                   <query>{$query}</query>
            </test-case>
        (: Comparison method: "Text" :)
        else if ($output/@compare eq "Text") then
            let $text := util:file-read(concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                "/", $output/text()))
            let $test := xqts:normalize-text($text) eq xqts:normalize-text($result)
            return
                xqts:print-result($case/@name, $test, $query, $result, $text, $case)
        (: Comparison method: "XML" :)
        else if ($output/@compare eq "XML") then
            util:catch("java.lang.Exception",
                let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                    $output/text())
                let $expected := doc(xdb:store("/db", "temp.xml", xs:anyURI($filePath), "text/xml"))
                let $test := xdiff:compare($expected, $result)
                return
                    xqts:print-result($case/@name, $test, $query, $result, $expected, $case),
                (: Handle unexpected exceptions :)
                <test-case name="{$case/@name}" result="fail">
                   <exception>Exception while loading expected result: {$util:exception-message}</exception>
                   <query>{$query}</query>
                </test-case>
            )
        (: Comparison method: "Fragment" :)
        else if ($output/@compare eq "Fragment") then
            util:catch("java.lang.Exception",
                let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath, $output/text())
                let $expectedFrag := util:file-read($filePath)
                let $xmlFrag := concat("<f>", $expectedFrag, "</f>")
                let $log := util:log("DEBUG", ("Frag stored: ", $xmlFrag))
                let $expected := doc(xdb:store("/db", "temp.xml", $xmlFrag, "text/xml"))
                let $test := xdiff:compare($expected, <f>{$result}</f>)
                return
                    xqts:print-result($case/@name, $test, $query, $result, $expected, $case),
                (: Handle unexpected exceptions :)
                <test-case name="{$case/@name}" result="fail">
                   <exception>Exception while loading expected result fragment: {$util:exception-message}</exception>
                   <query>{$query}</query>
                </test-case>
            )
        (: Comparison method: "Inspect" :)
        (: A text compare is sufficient in many test cases :)
        else if ($output/@compare eq "Inspect") then
            let $text := util:file-read(concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                "/", $output/text()))
            let $test := xqts:normalize-text($text) eq xqts:normalize-text($result)
            return
                xqts:print-result($case/@name, $test, $query, $result, $text, $case)

        (: Don't know how to compare :)
        else
            <error test="{$case/@name}">Unknown comparison method: {$output/@compare}.</error>
};

declare function xqts:run-test-case( $case as element(catalog:test-case)) as item()* {
   let $query := xqts:get-query($case)
   let $context :=
       <static-context>
       {
           for $input in $case/catalog:input-file
           return
               <variable name="{$input/@variable}">{xqts:get-input-value($input)}</variable>
       }
       </static-context>
   let $result :=
       util:catch("java.lang.Exception",
           let $result :=
               util:eval-with-context($query, $context, false())
           return
               xqts:check-output($query, $result, $case),
           if ($case//catalog:expected-error) then
               <test-case name="{$case/@name}" result="pass">
                   <exception>{$util:exception-message}</exception>
                   <expected-error>{$case//catalog:expected-error/text()}</expected-error>
                   <query>{$query}</query>
               </test-case>
           else
               <test-case name="{$case/@name}" result="fail">
                   <exception>{$util:exception-message}</exception>
                   <query>{$query}</query>
               </test-case>
       )
   return $result
};

declare function xqts:finish($result as element()) as empty() {
    let $passed := count($result//test-case[@result = 'pass'])
    let $failed := count($result//test-case[@result = 'fail'])
    return (
        update value $result/@passed with xs:int($passed),
        update value $result/@failed with xs:int($failed)
    )
};

declare function xqts:run-single-test-case($case as element(catalog:test-case),
    $resultRoot as element()?) as empty() {
    let $result := xqts:run-test-case($case)
    return (
        update insert $result into $resultRoot,
        let $added := $resultRoot/test-case[@name = $case/@name]
        return
            if ($added) then xqts:report-progress($added)
            else ()
    )
};

declare function xqts:run-test-group($group as element(catalog:test-group)) as empty() {
    (: Create the collection hierarchy for this group and get the results.xml doc to
        append to. :)
    let $resultsDoc := xqts:create-collections($group)
    let $tests := $group/catalog:test-case[
    	not(starts-with(@name, 'Constr-inscope-10')) and
    	not(starts-with(@name, 'Constr-inscope-11')) and
    	not(starts-with(@name, 'Constr-inscope-12')) and
    	not(starts-with(@name, 'Constr-inscope-13')) and
    	not(starts-with(@name, 'Constr-inscope-14')) and
    	not(starts-with(@name, 'Constr-namespace-22'))
    	]
    return (
        (: Execute the test cases :)
        for $test in $tests
        let $log := util:log("DEBUG", ("Running test case: ", string($test/@name)))
        return
            xqts:run-single-test-case($test, $resultsDoc/test-result),
        if ($tests) then
            xqts:finish($resultsDoc/test-result)
        else
            xdb:remove(util:collection-name($resultsDoc), util:document-name($resultsDoc)),
        (: Execute tests in child groups :)
        for $childGroup in $group/catalog:test-group
        let $log := util:log("DEBUG", ("Entering group: ", string($childGroup/@name)))
        return
            xqts:run-test-group($childGroup)
    )
};

declare function xqts:test-single($name as xs:string) as element() {
    let $test := //catalog:test-case[@name = $name]
    return
        if ($test) then
            let $resultsDoc := xqts:create-collections($test/parent::catalog:test-group)
            let $dummy := xqts:run-single-test-case($test, $resultsDoc/test-result)
            return
                $resultsDoc/test-result
        else
            <error>Test case not found: {$name}.</error>
};

declare function xqts:test-group($groupName as xs:string) as empty() {
    let $group := //catalog:test-group[@name = $groupName]
    return (
        xqts:create-progress-file(count($group//catalog:test-case)),
        xqts:run-test-group($group)
    )
};

declare function xqts:test-all() as empty() {
    for $test in /catalog:test-suite/catalog:test-group
    return
        xqts:test-group($test/@name)
};

declare function xqts:get-input-value($input as element(catalog:input-file)) as item()* {
   if ($input eq "emptydoc") then
       ()
   else (
       let $source := root($input)//catalog:source[@ID = $input/text()]
       return
           if (empty($source)) then
               concat("no input found: ", $input/text())
           else
               doc(concat("/db/XQTS/", $source/@FileName))
   )
};

declare function xqts:overall-result() {
    let $passed := count(//test-case[@result = "pass"])
    let $failed := count(//test-case[@result = "fail"])
    return
        <test-result failed="{$failed}" passed="{$passed}"
            percentage="{$passed div ($passed + $failed)}"/>
};

let $group := request:get-parameter('group', ())
return
    if ($group) then
        xqts:test-group($group)
    else
        ()

declare namespace xqts="http://exist-db.org/xquery/xqts";
declare namespace catalog="http://www.w3.org/2005/02/query-test-XQTSCatalog";

declare namespace props="java:java.io.File";

import module namespace util="http://exist-db.org/xquery/util";
import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace xdiff="http://exist-db.org/xquery/xmldiff"
at "java:org.exist.xquery.modules.xmldiff.XmlDiffModule";
import module namespace request="http://exist-db.org/xquery/request";

(:~ ----------------------------------------------------------------------------------------
     W3C XQuery Test Suite

     This is the main module for running the XQTS on eXist. You can either
     run the whole test suite, a specific test group or a single test case.

     Setup:

     * Make sure the XmlDiff module is registered in conf.xml

     * Edit config.xml and change basedir to point to the directory into
     which you unzipped the XQTS sources. Note: it needs to be an URI.

     * Create a collection /db/XQTS in the database.

     * From the XQTS directory, upload XQTSCatalog.xml into the created
     collection.

     * Upload the "TestSources" directory so the source docs can be found
     in /db/XQTS/TestSources.

     * Run this script with the client.
     ------------------------------------------------------------------------------------------- :)
declare variable $xqts:CONFIG { xqts:initialize() };
declare variable $xqts:XQTS_HOME { xqts:path-to-uri($xqts:CONFIG/basedir/text()) };

declare function xqts:initialize() as element() {
    let $home := util:system-property("exist.home")
    let $path := concat($home, "/webapp/xqts")
    let $collection := xdb:create-collection("/db", "XQTS")
    let $config0 := doc("/db/XQTS")/config
    let $config :=
        if ($config0) then
            $config0
        else
            let $stored := xdb:store-files-from-pattern("/db/XQTS", $path, "*.xml", "text/xml")
            return
                doc("/db/XQTS/config.xml")/config
    let $xqtsHome := $config/basedir/text()
    let $catalog0 := doc("/db/XQTS/XQTSCatalog.xml")
    let $catalog :=
        if ($catalog0) then $catalog0
        else
            xdb:store($collection, "XQTSCatalog.xml",
                xs:anyURI(xqts:path-to-uri(concat($xqtsHome, "XQTSCatalog.xml"))))
    let $sources0 := collection("/db/XQTS/TestSources")
    let $sources :=
        if ($sources0) then
            $sources0
        else
            let $sourceCol := xdb:create-collection("/db/XQTS", "TestSources")
            return
                xdb:store-files-from-pattern($sourceCol, concat($xqtsHome, "TestSources"), "*.xml", "text/xml")
    return
        $config
};

declare function xqts:path-to-uri($path as xs:string) as xs:string {
        if (starts-with($path, "/")) then
            concat("file://", $path)
        else
            concat("file:///", $path)
};

declare function xqts:create-progress-file($testCount as xs:int) as empty() {
    let $results := xdb:store("/db/XQTS", "progress.xml",
        <progress total="{$testCount}" done="0" failed="0" passed="0"/>)
    return ()
};

declare function xqts:report-progress($test-case as element()) as empty() {
    let $result := string($test-case/@result)
    let $progress := doc("/db/XQTS/progress.xml")/progress
    let $counter := $progress/@done
    return (
        update value $counter with xs:int($counter + 1),
        if ($result eq 'fail') then
            update value $progress/@failed with xs:int($progress/@failed + 1)
        else
            update value $progress/@passed with xs:int($progress/@passed + 1)
    )
};

declare function xqts:create-collections($group as element(catalog:test-group)) as node() {
    let $rootColl := xdb:create-collection("/db/XQTS", "test-results")
    let $ancestors := reverse(($group/ancestor::catalog:test-group, $group))
    let $collection := xqts:create-collections($rootColl, $ancestors, "/db/XQTS/test-results")
    let $results := xdb:store($collection, "results.xml", <test-result failed="0" passed="0"/>)
    return
        doc($results)
};

declare function xqts:create-collections($parent as object,
    $pathElements as element()+, $currentPath as xs:string)
as object {
    let $next := $pathElements[last()]
    let $remainder := subsequence($pathElements, 1, count($pathElements) - 1)
    let $newColl := xdb:create-collection($parent, $next/@name)
    return
        if ($remainder) then
            xqts:create-collections($newColl, $remainder, concat($currentPath, "/", $next/@name))
        else
            $newColl
};

declare function xqts:get-query($case as element(catalog:test-case)) {
   let $query-name := $case//catalog:query/@name
   let $path := concat( $xqts:XQTS_HOME, "Queries/XQuery/", $case/@FilePath, $query-name, ".xq" )
   let $xq-string := util:file-read($path)
   return $xq-string
};

declare function xqts:print-result($test-name as xs:string, $passed as xs:boolean, $query as xs:string,
    $result as item()*, $expected as item()*, $case as element(catalog:test-case)) as element() {
    <test-case name="{$test-name}" result="{if ($passed) then 'pass' else 'fail'}">
    {
        if (not($passed)) then (
            <result>{$result}</result>,
            if ($expected instance of element() and count($expected/*) > 10) then
            	<expected truncated="">{$expected/*[position() < 10]}</expected>
            else
                <expected>{$expected}</expected>,
            (: element {$case/catalog:input-file/@variable} { xqts:getInputValue($case) }, :)
            <query>{$query}</query>
        ) else ()
    }
    </test-case>
};

declare function xqts:normalize-text($result as item()*) as xs:string {
    let $str := string-join($result, " ")
    return
        (: Remove leading and trailing whitespace :)
        replace(replace($str, "^\s+", ""), "\s+$", "")
};

declare function xqts:check-output($query as xs:string, $result as item()*, $case as element(catalog:test-case)) {
    let $output := $case/catalog:output-file[last()]
    return
        (: Expected an error, but got a result :)
        if (exists($case/catalog:expected-error)) then
            <test-case name="{$case/@name}" result="fail">
                   <expected-error>{$case/catalog:expected-error/text()}</expected-error>
                   <query>{$query}</query>
            </test-case>
        (: Comparison method: "Text" :)
        else if ($output/@compare eq "Text") then
            let $text := util:file-read(concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                "/", $output/text()))
            let $test := xqts:normalize-text($text) eq xqts:normalize-text($result)
            return
                xqts:print-result($case/@name, $test, $query, $result, $text, $case)
        (: Comparison method: "XML" :)
        else if ($output/@compare eq "XML") then
            util:catch("java.lang.Exception",
                let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                    $output/text())
                let $expected := doc(xdb:store("/db", "temp.xml", xs:anyURI($filePath), "text/xml"))
                let $test := xdiff:compare($expected, $result)
                return
                    xqts:print-result($case/@name, $test, $query, $result, $expected, $case),
                (: Handle unexpected exceptions :)
                <test-case name="{$case/@name}" result="fail">
                   <exception>Exception while loading expected result: {$util:exception-message}</exception>
                   <query>{$query}</query>
                </test-case>
            )
        (: Comparison method: "Fragment" :)
        else if ($output/@compare eq "Fragment") then
            util:catch("java.lang.Exception",
                let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath, $output/text())
                let $expectedFrag := util:file-read($filePath)
                let $xmlFrag := concat("<f>", $expectedFrag, "</f>")
                let $log := util:log("DEBUG", ("Frag stored: ", $xmlFrag))
                let $expected := doc(xdb:store("/db", "temp.xml", $xmlFrag, "text/xml"))
                let $test := xdiff:compare($expected, <f>{$result}</f>)
                return
                    xqts:print-result($case/@name, $test, $query, $result, $expected, $case),
                (: Handle unexpected exceptions :)
                <test-case name="{$case/@name}" result="fail">
                   <exception>Exception while loading expected result fragment: {$util:exception-message}</exception>
                   <query>{$query}</query>
                </test-case>
            )
        (: Comparison method: "Inspect" :)
        (: A text compare is sufficient in many test cases :)
        else if ($output/@compare eq "Inspect") then
            let $text := util:file-read(concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                "/", $output/text()))
            let $test := xqts:normalize-text($text) eq xqts:normalize-text($result)
            return
                xqts:print-result($case/@name, $test, $query, $result, $text, $case)

        (: Don't know how to compare :)
        else
            <error test="{$case/@name}">Unknown comparison method: {$output/@compare}.</error>
};

declare function xqts:run-test-case( $case as element(catalog:test-case)) as item()* {
   let $query := xqts:get-query($case)
   let $context :=
       <static-context>
       {
           for $input in $case/catalog:input-file
           return
               <variable name="{$input/@variable}">{xqts:get-input-value($input)}</variable>
       }
       </static-context>
   let $result :=
       util:catch("java.lang.Exception",
           let $result :=
               util:eval-with-context($query, $context, false())
           return
               xqts:check-output($query, $result, $case),
           if ($case//catalog:expected-error) then
               <test-case name="{$case/@name}" result="pass">
                   <exception>{$util:exception-message}</exception>
                   <expected-error>{$case//catalog:expected-error/text()}</expected-error>
                   <query>{$query}</query>
               </test-case>
           else
               <test-case name="{$case/@name}" result="fail">
                   <exception>{$util:exception-message}</exception>
                   <query>{$query}</query>
               </test-case>
       )
   return $result
};

declare function xqts:finish($result as element()) as empty() {
    let $passed := count($result//test-case[@result = 'pass'])
    let $failed := count($result//test-case[@result = 'fail'])
    return (
        update value $result/@passed with xs:int($passed),
        update value $result/@failed with xs:int($failed)
    )
};

declare function xqts:run-single-test-case($case as element(catalog:test-case),
    $resultRoot as element()?) as empty() {
    let $result := xqts:run-test-case($case)
    return (
        update insert $result into $resultRoot,
        let $added := $resultRoot/test-case[@name = $case/@name]
        return
            if ($added) then xqts:report-progress($added)
            else ()
    )
};

declare function xqts:run-test-group($group as element(catalog:test-group)) as empty() {
    (: Create the collection hierarchy for this group and get the results.xml doc to
        append to. :)
    let $resultsDoc := xqts:create-collections($group)
    let $tests := $group/catalog:test-case[not(starts-with(@name, 'Constr-inscope-1'))]
    return (
        (: Execute the test cases :)
        for $test in $tests
        let $log := util:log("DEBUG", ("Running test case: ", string($test/@name)))
        return
            xqts:run-single-test-case($test, $resultsDoc/test-result),
        if ($tests) then
            xqts:finish($resultsDoc/test-result)
        else
            xdb:remove(util:collection-name($resultsDoc), util:document-name($resultsDoc)),
        (: Execute tests in child groups :)
        for $childGroup in $group/catalog:test-group
        let $log := util:log("DEBUG", ("Entering group: ", string($childGroup/@name)))
        return
            xqts:run-test-group($childGroup)
    )
};

declare function xqts:test-single($name as xs:string) as element() {
    let $test := //catalog:test-case[@name = $name]
    return
        if ($test) then
            let $resultsDoc := xqts:create-collections($test/parent::catalog:test-group)
            let $dummy := xqts:run-single-test-case($test, $resultsDoc/test-result)
            return
                $resultsDoc/test-result
        else
            <error>Test case not found: {$name}.</error>
};

declare function xqts:test-group($groupName as xs:string) as empty() {
    let $group := //catalog:test-group[@name = $groupName]
    return (
        xqts:create-progress-file(count($group//catalog:test-case)),
        xqts:run-test-group($group)
    )
};

declare function xqts:test-all() as empty() {
    for $test in /catalog:test-suite/catalog:test-group
    return
        xqts:test-group($test/@name)
};

declare function xqts:get-input-value($input as element(catalog:input-file)) as item()* {
   if ($input eq "emptydoc") then
       ()
   else (
       let $source := root($input)//catalog:source[@ID = $input/text()]
       return
           if (empty($source)) then
               concat("no input found: ", $input/text())
           else
               doc(concat("/db/XQTS/", $source/@FileName))
   )
};

declare function xqts:overall-result() {
    let $passed := count(//test-case[@result = "pass"])
    let $failed := count(//test-case[@result = "fail"])
    return
        <test-result failed="{$failed}" passed="{$passed}"
            percentage="{$passed div ($passed + $failed)}"/>
};

let $group := request:get-parameter('group', ())
return
    if ($group) then
        xqts:test-group($group)
    else
        ()